So I need to be able to have dev/stage/production iterations (over separate servers) for a WordPress website, I use git usually but this obviously isn’t going to work with WordPress sites because of the reliance on the database for the main configuration of… well, almost everything.
So my question is how do you guys do it? I had a quick Google and saw that there was a few plugins, is this the only way? Which ones do the job the best in terms of ease of use, speed, reliability, ui etc.?
I have a setup I’m pretty proud of, and it works extremely well for my team.
I keep the entire installation under git. All changes, be it a system update, adding/updating a plugin, adding/updating a theme, go through the same workflow. Changes can be rolled back at a moment’s notice. I have a deployment server (an old P4 desktop) running gitosis but you could just as easily use github or gitolite. In git, I have two “special” branches,
develop (explained more below). My production and staging servers are cloud-based.
Every developer runs their own development server on their own machine. In terms of databases, needing live data has hardly ever been an issue. We mainly use the theme unit test data. Otherwise export and import covers most things. If the DB piece was crucial, you could setup replication or setup something for on-demand syncing. When I initially setup this structure, I thought this would be crucial so I started writing a set of tools to do this, but to my surprise they really weren’t necessary. (note: since they weren’t necessary, I didn’t ever polish them up, so there are bugs e.g. it will replace the domain in serialized data).
When commits are pushed from the
develop branch to gitosis, they get automatically deployed to our staging server. The staging database is a slave to the production database.
When commits are pushed to gitosis on the
master branch, it’s automatically deployed to the production server.
The wp-config.php issue
wp-config.php to be unique from server to server, but you also want to keep it under version control. My solution was to use
.gitignore to ignore
wp-config.php, and store the staging and production versions as differently-named files. Then on each server, I symlink e.g.
wp-config.php -> wp-config-production.php. Each user then keeps their own DB with their own credentials, with their own (untracked) wp-config.php settings.
I use Rackspace Cloud, which is phenomenal and inexpensive. With it I can keep my staging and production servers identical. I’m also writing plugins right now that use their API to allow me to control my services right from within WordPress, it’s wonderful.
Cache directories, file upload directories, etc., are all added to .gitignore. If you wanted, you could setup a cron task to routinely check in uploads and push them to gitosis, but that never seemed necessary to me.
I’ve had 10 or so developers working off this structure for over a year now and it’s been a dream to work with. Reliable, secure, fast, functional, and agile, you can’t ask for much more!
First, I think its important to consider what you are going to Version Control . I would recommend against putting the entire WP directory under VC. I think it makes the most sense to put wp-content/themes/YourThemeName under VC. For a large site with a high number of complex plugins I could see the case to including wp-content/plugins as well. If you absolutely had to, you could include wp-content/uploads. The answers below will change a bit, depending on what you version control.
Given that, here is what I use:
Local: Setup a LAMP stack on your machine. Use the same URL as your development site. Use VirtualHosts and .host file entries to simulate the development environment from a URL point of view. If you are just VC’ing your theme, consider using SSHFS to link to wp-content/plugins, wp-content/uploads. Consider using the database on your development install of the project unless you are really doing some heavy lifting.
Development: Checkout a working copy of your Repo into your WP environment. Setup a POST-COMMIT Hook in SVN to update this repo on each commit. This will keep it sync’d. (Consider it a poor man’s continuous integration.)
Production: Check out a named version tag representing a final candidate. When you need to do use a new version, switch the tag and update the repo.
We recently discovered RAMP. Note: this is only a part of the whole process, but syncing content databases between servers is probably the most difficult part of it.
I do this with git and mercurial, just make sure you’re using a private repo.
The only problem is the config.php, which you can tell git to ignore on push or before init.
git update-index --assume-unchanged config.php (read a bit about the assumed-unchanged command before using it)
Use a conditional in the config.php that checks the url and applies the correct credentials, along the lines of “if server url = dev then use credentials A, else use credentials B “, etc.
Mark explains this better, http://markjaquith.wordpress.com/2011/06/24/wordpress-local-dev-tips/
ps. You can also server the files directly from a remote repo instead of having a traditional “file server”. ( really boring video I made about this http://www.youtube.com/watch?v=8ZEiFi4thDI )