WordPress Development Workflow by Chris Allen

I want to share my development setup and talk about how I do things these days.

This post is has two main sections. Part one covers the tools I use, and part two will cover my workflow ie. how I perform common tasks.

Part 1: The Tools

Local Web Server

Local by Flywheel

I’ve used Vagrant, then Docker, and Vagrant again. Finally, I discovered Local by Flywheel. It’s a free tool which wraps docker up into a really slick app, and it makes life a lot simpler. If you find yourself working on WordPress most of the time, its a no-brainer.

From the interface, it allows you to add a new local website with just a few clicks and integrates nicely with Adminer or Sequel Pro. You can add a local SSL with one click, and includes MailHog to catch your development emails.

Flywheel gives away the app for free, as it deploys seamlessly to their Flywheel hosting, but it’s a standalone tool so you can actually use whatever hosting you like.

Production Hosting

I use Digital Ocean, and not Flywheels managed hosting platform. Using a VPS means that you also have to be your own server admin, but personally, I need the flexibility.

DigitalOcean’s control panel

For the cost, Digital Ocean is excellent value, and if there’s one thing that stands out for me, it’s their depth of written tutorials. You can Google almost any server related How-To and find one of their community written tutorials.

Version Control

Git is essential (to me). If my project is public facing, I use Github, if not I use Gitlab as they provide private repositories at no extra cost. Even with a platform where the content is primarily stored in the database, it makes sense to keep all your updates versioned in case you need to roll back any changes.

Production Deployment

These days I am a team of one, so I just keep it simple and clone my master branch onto the server.

Text Editor

VSCode with the SpaceGray theme

Visual Studio Code. It is fast, customisable and allows me to make use of the built-in PHP debugger really easily. Setting it up to work with Local by Flywheel is simple: It’s one config file, and a Chrome extension. I’ll cover the nitty gritty in part 2.

Part 2: Workflow

Setting up a new site

  • Click the big + icon and work your way through step 1 of the wizard.
  • Once you get to step 2, choose the custom environment. This is important if you want to use the PHP debugger in VSCode. It exposes the config directory for you can edit the necessary ini files.
  • Finish the wizard step 3. It’ll provision the site automatically for you, and after a minute or two you’ll be able to load it up in your browser.
Choose ‘Custom’ environment to take advantage of Xdebug

Using the same TLD as production:

It’s worth mentioning here that I personally prefer to use the same TLD as production for my local sites, and I use a host editor app such as Gasmask to quickly switch my host file. I can then avoid having to edit the database when I migrate it from local to production.

Using a hosts editor throws a spanner in the works with Local’s host file management, so you’ll need to set your own host entries using the app. Of course, if you want to simplify, just use a .local TLD instead.

Its a choice between looking after the hosts file yourself, or having to find and replace DB dumps when you want to migrate.

Using a hosts editor app causes warnings in Local by Flywheel

Setting up the PHP debugger in VSCode

In the past, I’ve found setting up XDebug to be a bit of a headache. Luckily, with VSCode & Local by Flywheel, its really straightforward. I’ll link to the exact tutorial I followed, but overall it goes something like this:

  • Make sure you chose the ‘Custom’ setup when you created your Local site.
  • Edit /yoursiteroot/conf/php/7.2.0/php.ini a little.
  • Click a button in VSCode, and edit the .vscode/launch.json that gets created.
  • Install this Chrome extension: https://github.com/mac-cain13/xdebug-helper-for-chrome

Here is the detailed tutorial created by Ahmad Awais in order to complete the above steps: https://gist.github.com/ahmadawais/d6e809d45b8103b2b3a79fa8845f9995

Updating plugins & deploying to production

When updating plugins, I prefer the following procedure:

  • Update the plugin on my local website.
  • Add & commit the new files, with a commit message like Update WP Rocket
  • Git push to my remote Git repository.
  • SSH into my Digital Ocean server, cd into my webroot and then I use a couple of custom alias commands:

I’ve got one called 770 that opens up my file permissions, in order to perform the git pull without any file linking errors.

I’ve got another alias called perms, which I run once the git commands have completed. This runs a separate shell script, which sets all the common WordPress permissions for me. It accepts one argument, the absolute path of the WordPress directory, for example: /var/www/html/production/chrisjallen/

My aliases:

# User specific aliases and functions

alias 770='sudo chmod -R 770 .'

alias perms='sudo /usr/local/bin/wp-permissions.sh'

And the custom permissions script:

# Author: Chris Allen


WP_OWNER=apache # -- wordpress owner

WP_GROUP=apache # -- wordpress group

WP_ROOT=$1 # -- wordpress root directory ( arg #1 )

WS_GROUP=apache # -- webserver group


# reset to safe defaults

echo "Setting permissions for files & folders.."

find ${WP_ROOT} -exec chown ${WP_OWNER}:${WP_GROUP} {} \;

find ${WP_ROOT} -type d -not -path ${EXCLUDE} -exec chmod 755 {} \;

find ${WP_ROOT} -type f -not -path ${EXCLUDE} -exec chmod 644 {} \;

# allow wordpress to manage wp-config.php (but prevent world access)

echo "Setting wp-config permissions..."

chgrp ${WS_GROUP} ${WP_ROOT}/wp-config.php

chmod 660 ${WP_ROOT}/wp-config.php

# allow wordpress to manage .htaccess

echo "Setting .htaccess permissions..."

touch ${WP_ROOT}/.htaccess

chgrp ${WS_GROUP} ${WP_ROOT}/.htaccess

chmod 664 ${WP_ROOT}/.htaccess

# allow wordpress to manage wp-content

echo "Setting wp-content permissions..."

find ${WP_ROOT}/wp-content -exec chgrp ${WS_GROUP} {} \;

find ${WP_ROOT}/wp-content -type d -exec chmod 775 {} \;

find ${WP_ROOT}/wp-content -type f -exec chmod 664 {} \;

# reset the .git permissions

find ${WP_ROOT}/.git -type d -exec chmod 770 {} \;

find ${WP_ROOT}/.git -type f -exec chmod 770 {} \;

tput setaf 2; echo "Complete."; tput sgr0

Please note: If you aren’t 100% confident with the command line, just be aware that one false move can cause untold destruction, so be careful what you type.

Migrating a database

Because I share a TLD between my local and love sites, the process is fairly simple. One thing I do try to avoid is migrating the DB from local to live. I tend to make sure I’m only exporting the live database into my local. The live database takes care of itself most of the time. I’ve listed the steps here so you can see how simple it is.

  • Open up Sequel Pro, and connect to my live database.
  • Select the correct database, and then go to file > export
  • I usually go with the defaults and export the whole database to my desktop.
  • Close Sequel Pro, then go to the ‘Database’ tab in Local by Flywheel and click Sequel Pro. This reconnects to the local box, with no connection config required.
  • Delete the tables from the database, which will usually be called ‘local’ and then do a file import.

Keeping live changes in sync

Any active live website will undergo daily content changes, people process orders, write posts, upload images. All of this means code changes on the live site.

To check for this, I SSH into the live server regularly and run a git status on the webroot. Any changes which haven’t been performed by me get added, committed and pushed to the remote git repository. Usually with a super-descriptive commit message like "User updates".

It’s not perfect, but it’s real-world, and it ensures my live site is always under version control.