I recently ran into a situation when working with a site on WP Engine post going live. It was a bit of a struggle and I decided to come up with something better. I knew WP Engine had git push options, and had used them before, but that was only one of the pieces I needed for a more seamless workflow.

If you’re like me, you have a process for how you develop custom websites. It usually begins with your local development environment, version control of your code, and shared database for collaborative development etc…

However, that environment can tend to go quickly down the drain once a site goes live. You’re now at the mercy of the client-chosen hosting provider, never sure if your local or staging versions of the site are in true alignment with the live site, and every small edit from then on leaves a bad taste in your mouth on the site you put so much effort, organization, and passion into.

Assumptions

This tutorial is based on the assumption that you’re already using version control (git) and a local environment for your custom site, and that your local code is aligned with the live site already.

The Solution

GIT

As mentioned above, the first step is to get WP Engine setup to deploy via git push so we can properly continue using our version control. This is how I set up git on WP Engine, but for a more in-depth tutorial view WP Engine’s post on setting up git push.

Add ssh public key WP Engine for git push

You’ll first need to navigate to your public SSH key (usually named: id_rsa.pub) file. If you don’t already have one, there are plenty of great tutorials on generating one. Once you have located this, you’ll need to copy the contents to the WP Engine admin under “Git Push”

WP Engine Git Push SSH KeyWP Engine Git Push SSH Key Added

Click “Add Developer” and your key will be added. You may have to wait up to 10 minutes for it to set up. You can test that the deploy key has been fully added by running: ssh git@git.wpengine.com info, which, once ready, will show you a list of the repositories you can push to.

Add WP Engine git remotes for live / staging

Then we can go to our command line/terminal and add our additional git remotes by copying the urls from WP Engine. An example of how I usually add the remotes are:

git remote add production git@git.wpengine.com:production/%INSTALL_NAME%.git
git remote add staging git@git.wpengine.com:staging/%INSTALL_NAME%.git

Create git branch and checkout (optional)

We can now push to our codebase via git deploy to WP Engine. Personally, I like to create a branch for WP Engine since I’ll be adjusting the .gitignore and like to have a clear divide of when that occurred. For me, this looks like checking out a new branch (usually called WP Engine). If you’re following along and want the actual line of code, it’s as follows: git checkout -b wpengine

Setup gitignore and remove unneeded files (if being tracked)

Lastly for the git setup, WP Engine requests that we ignore all large local files that aren’t really vital to the theme or plugins themselves. Many people may already have their uploads and wordpress code excluded from their version control, but if not, we will need to remove those from our git tracking.

WP Engine provides a .gitignore example, (one to track WordPress Core, and one to exclude WordPress Core) that we can copy or add to our projects .gitignore. Commit that file to your repo and we are nearly set.

This is all well and good, but if you’ve already been tracking these files, they won’t immediately stop being tracked, even though they have been added to the gitignore. To clear these files from tracking we can use a little trick:

*make sure to include the –cached parameter*

We first remove all files from tracking without deleting the files from the filesystem with: git rm -rf --cached .

We can then git add --all which re-adds all of the files, but now ignores the ones we have included in our .gitignore.

Try running a git push staging wpengine to confirm everything is working, and you’re all set!

REMOTE DB

We now have our code synced up with the live site and can easily push our bug fixes and additions up without much deviation from our original workflow. The next step is syncing the data. WP Engine allows for this, and we can connect our local site up to the staging db (or live, if you like to live on the edge) fairly easily.

Whitelist your IPs

Just a quick support chat or ticket away, and WP Engine will happily whitelist your public ip and allow you remote database access.

Update your wp-config credentials

Once your IP(s) are whitelisted, we just need to ftp into our staging site and grab a copy of the wp-config credentials for the database. You’ll need the DB_NAME, DB_USER, DB_PASSWORD from the staging wp-config, and you can just put the WP Engine install IP as your DB_HOST.

Finally, we can add two additional lines to our wp-config to allow our local site to use the staging database without constantly redirecting to the staging urls set in the wp_options table:

Set your local wp-config URL

define( 'WP_HOME', 'http://%LOCAL_SITE_URL%' );
define( 'WP_SITEURL', 'http://%LOCAL_SITE_URL%' );

Here is an template for the wp-config changes needed:

define( 'DB_NAME', '%STAGING_DB_NAME%' );
define( 'DB_USER', '%STAGING_DB_USER%' );
define( 'DB_PASSWORD', '%STAGING_DB_PASS%' );
define( 'DB_HOST', '%STAGING_HOST_IP%' );
define( 'WP_HOME', 'http://%LOCAL_SITE_URL%' );
define( 'WP_SITEURL', 'http://%LOCAL_SITE_URL%' );

With that, give the local version of the site a reload and although it may be a bit slower, you should be seeing content and data directly from the staging site!

MEDIA FILES

Lastly, this leaves media files. WP Engine excludes these with the .gitignore as they tend to take up the majority of space on an install and would bog the site down if they were tracked. However, if your client is adding images here and there, it can become a real pain to keep track and sync the media down to your local, in the case that a styling issue or other bug arises.

.htaccess redirect modifications

With that, we can do a simple htaccess redirect that will redirect all wp-content/uploads requests to our live or staging server.

First we add an exception for any wp-content/uploads requests to be excluded from the normal request handling that wordpress has. We can do that by adding a RewriteCond like this to our htaccess file before the %{REQUEST_FILENAME} lines:

RewriteCond %{REQUEST_URI} !wp-content/uploads [NC]

Then we can add our own RewriteRule right before the closing IfModule tag to redirect all those uploads folder requests to the staging server:

RewriteRule ^wp-content/uploads/([^.]+)\.([^/]+)/? http://%STAGING_SITE_URL%/wp-content/uploads/$1.$2 [R=301,L,NC]

Here is an example of a final .htaccess file:

# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_URI} !wp-content/uploads [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
RewriteRule ^wp-content/uploads/([^.]+)\.([^/]+)/? http://%STAGING_SITE_URL%/wp-content/uploads/$1.$2 [R=301,L,NC]
# END WordPress

Refresh your local site, and images should automatically be pulling from your staging site!

ADDITIONAL IDEAS:

A couple of ideas to expand this workflow that I have yet to try out:

Automatic plugin downloader

I read an article a little while back (although I can’t seem to find it) where someone used a solution like wp-cli or something to check the registered plugins in the database, and automatically download them. This would help in the case when a client or someone downloads an additional plugin (like Yoast) to sync it down, since WP Engine won’t automatically add it to the git tracking.

Disable admin editor

Because additional files being added outside of the version control process aren’t automatically added to the git tracking, it might make sense to lock the default wordpress plugin and theme editors so that files aren’t overwritten/lost unintentionally.

WP Migrate DB Pro

I have yet to bite the bullet and purchase, but I am aware that WP Migrate DB pro offers database syncing, and recently even added the ability for media/uploads syncing as well. This definitely could be a much better solution (and I am hoping to test that flow out), but I did learn a bit, and enjoy the task of putting together a solution without this plugin.

Wrap Up

Now, this is definitely better than cowboy coding, in my opinion, but is still really a bit more of a hack-together solution. And although I probably wouldn’t recommend going too far with it, it has helped me at various times to simplify some of my post-launch work or bug fixes on a few sites.