My Simple WordPress Development Workflow

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:

Here is the detailed tutorial created by Ahmad Awais in order to complete the above steps:

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/'

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.

And finally…

What do you think about my setup? Some may think its extremely simplistic, or flawed, or inefficient, but you may actually find certain aspects to be an improvement on your current setup. Who knows 🙂

If you have any feedback, I’d love to hear it. Please reach out to me in the comments, Twitter or LinkedIn.





8 responses to “My Simple WordPress Development Workflow”

  1. Nick Pishvanov Avatar
    Nick Pishvanov

    Thank you for the extremely helpful post! One question- are you able to use a Gulp/Browsersync set up in the normal way, i.e. typically with the node_modules folder in the theme root, and just point the Browsersync proxy at the dev URL, or do you need to configure anything specifically with respect to Local/Flywheel? Thanks again.

    1. Chris Allen Avatar
      Chris Allen

      Hi Nick,

      I currently do not use a Browsersync setup on Local by Flywheel. I think it may be possible but I can only go as far as pointing you at the Local support forums.
      I’ve had it working on a Vagrant environment, and I fould it to be slow, but perhaps it may work better under Local, which is docker based.

  2. Marcos Gil Avatar
    Marcos Gil

    Hi Chris,
    Very helpful post, thank you!
    I have one doubt with the version control with git, do you save in a repository all the content of the web? or maybe the wp-content folder?
    Usually, I save just the theme I am working on or just the child theme. It’s true that you can keep track of the plugins and have more control.

    1. Chris Allen Avatar
      Chris Allen

      Hi Marcos. Your comment ended up in my spam, my apologies. I tend to set up a .gitignore file to ignore anything sensitive, and commit the wp-content folder. Make sure you do ignore the wp-config.php if you are going to commit the whole site, as once you commit it’ll remain in the history even if removed.

  3. Darryl Avatar

    Hi Chris,
    There is a plugin, migratedb, it’s extremely useful when working with pushing and pulling databases between local and live sites.
    I’ve found that setting up a git repo on the live server to push your theme changes to works really well, then use a git hook to move your files from the repo to the live folder.
    I’ve been playing with different local environments for some time and in the end always hit some kind of stumbling block with each one. Local simplifies things but I’ve found it slow in the past, have they improved things?

    1. Chris Allen Avatar
      Chris Allen

      Hi Darryl, I’ve used migratedb in the past, & I like your idea of using a git hook to trigger the file transfer. Definitely going to explore this.
      Regarding Local, it’s improving all the time. I’ve also started using a new host called, who have been fantastic so far.

  4. Michael Avatar

    Nice read!

    Yours is more advanced than mine, but I observe a similar and leaner WordPress workflow:
    – Create a local installation using Local by Flywheel (I use .local tld)
    – Develop theme through Sublime Text
    – Use BrowserSync for faster development
    – Push theme changes via FTP
    – Push media uploads via FTP (I use FileZilla’s compare view – that way I just upload new/updated files)
    – Push database changes using WP Migrate DB Pro (this takes care of renaming the local SITE_URL into the live one)

    When it comes to plugin updates, since I mostly update updating third-party plugins I prefer doing it on the live site because I think it’s faster than updating it via FTP/git. What do you think?

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

Leave a Reply

Your email address will not be published. Required fields are marked *