I’m nearing the final stages of constructing my first fairly large WordPress site, and I’m now encountering some friction. For the most part, the site was developed on my local machine and I would push changes up to a staging server for review (see this question for more background). The solution I ended up with worked quite well when it was just me editing content, but now some other people are editing the content while I still have features to add. The idea was: we could get things done more quickly if the features and the content came together in concert… but now I’m not so sure.
Currently there is different content in the database on the staging server than on my local machine. That’s fine by itself, as I don’t need the final body copy on my local machine, but I need to do more development which will affect the database (install/write a couple more plugins which need their own tables).
My question is:
Is there an easy way to automate the merging of databases so that multiple people can work on a WordPress install? I could, of course, just export the tables which I know have changed on my local machine and push them to the staging server, but it’s possible that there are also things on the staging server I would like to bring down. I could grab the SQL output of both DBs and diff them… but that seems tedious and hackish. I’m wondering if this is a problem others have solved; if there’s a community-accepted way to handle this sort of thing.
I asked this question over a year ago, and during that time we’ve added more people to our team and developed a much larger number of sites in WordPress. I wanted to walk through our process in case it might help anyone else.
Everything in Git
This was something I was doing even as I asked the question, but it’s good to call this point out. Using Git has not only helped us be more productive, but it’s also saved our collective asses several times.
Have you ever needed to make major structural renovations to a site, get approval for those renovations from a client, and all the while make minor updates to the non-renovated version? We have, and Git let us do it. Describing this setup would get a bit long-winded, but the basics are that we made a new branch, pulled that branch on to the server, and attached a subdomain to that branch.
We’ve also been saved by Git. It of course allows us to roll back changes, which is great, but it also allows us to bring old versions of files back. This means that if a client asks, “Remember how this part of the site worked about a year ago? Can we bring that back?”, the answer is yes — even if the person being asked wasn’t on that project a year ago.
Beside these points, it also means that we’re never stuck without the files we need. We can always pull down the newest version of the site from any machine and start making changes.
Use Git to deploy
We do our WordPress hosting on Media Temple, and we really like them. They’re not the cheapest provider, but their service is excellent and their servers are really well set up. The also provide Git by default. This means we can set the server up as a Git repository, and pull changes in that way instead of using SFTP. It also means that doing work on the server isn’t in danger of being overwritten (as those changes can just be merged and pushed back up).
Because we use BitBucket as our Git host, there’s a little bit of extra work required here. First of all we use .ssh/config files so that we we can type things like
ssh sitename to log into our servers (we also use passwordless SSH, which makes this super easy). We also make sure to always use ssh passphrases (Mac OS X makes this very easy by allowing you to store your passphrase in Keychain.app). Finally, we add the a ForwardAgent line to the .ssh/config entry on hosts we want to pull from. This means that we only need each person’s SSH public key in BitBucket, and not the public key of each server. We also make sure to keep the
.git directory one directory above the public HTML directory.
Automated database dumps
Once the server is in production mode, we make sure to automatically back up our database, just in case.
Everyone has their own wp-config
Because we’ve all got our own local database usernames and passwords, and because we could use different names and serving mechanisms, we each keep our own wp-config file. Each of these is stored in Git with a name like
wp-config-gavin.php, and when we want to use that config, we symlink it to
wp-config.php (which is ignored by Git using .gitignore).
This also allows us to override the
siteurl option in the
wp_options database table like so:
define('WP_SITEURL', 'http://sitename.localhost'); define('WP_HOME', 'http://sitename.localhost');
This prevents WordPress from looking at the database for the server location, and means there aren’t weird differences in location between local and server installs.
One final note about wp-config.php files: make sure to store them above the public HTML directory and make the permissions read only for the web user. This makes a huge difference in securing WordPress.
The database issue
Finally, the meat of the matter.
What I had to accept is, when using WordPress, there’s no good way to “merge” database changes. Instead, we needed to develop rules of conduct to solve this. The rules are fairly simple, and have served us well so far.
During development, there’s a single person who “owns” the site. That person usually does the setup (getting the hosting package together, starting the Basecamp project, slicing the design, that sort of thing). Once that person is to a reasonable point, the dump the database for the WordPress install and put it into Git. From that point forward, everyone doing development uses that database dump, and the owner is the only one who makes changes to the database.
Once the site build gets a bit further along, the site is put on a server. From that point on, the server’s database is canonical. Everyone (including the owner) must make all database changes on the server and pull the changes down for local development and testing.
This process isn’t perfect. It’s still possible that someone might need to make changes in the WordPress backend locally during development, and then have to make those changes again in production. However, we’ve found that sort of thing to be rare, and this process works fairly well for us.