My WordPress Workflow
12 comments Posted in WordPressThe subject of WordPress workflows has been rife on Twitter today, and as a hardened WP developer, I thought I should chime in and share my optimal workflow.
In this little writeup I’ll show you how to:
- Handle multiple URLS
- Support for dev, staging & live databases
- Source control
- Deploying scripts
Before I get started, I just want to say that I’ll gloss over anything that isn’t WordPress specific. No particulars in version control or deployment scripts, just the bits that make it possible in WordPress.
I’ll assume this follows the 3 tiered development platform, meaning a local version for development, a staging server for showing the work to the client and the live version which the world sees.
Getting Started
So, when I start a project, the first things I do are set up a new source control repo and choose a local domain inside MAMP Pro. We’ll give this site a local domain of mysite.dev, though that’s not important.
The next step is to download WordPress and chuck it in the appropriate place. The next step is a huge time saver. It means your install will work with any domain, no matter where it is, be it local, staging or live. This goes in wp-config.php just before the comment that says /* That's all, stop editing! Happy blogging. */.
// Assuming WP is in the root folder, adjust if not
define('WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST']);
define('WP_HOME', 'http://' . $_SERVER['HTTP_HOST']);
define('WP_CONTENT_DIR', $_SERVER['DOCUMENT_ROOT'] . '/wp-content');
Databases
WordPress is just PHP framework. There’s nothing you cannot do in it that you can do outside of it. So, using regular PHP if/else statements, we can make WP work with different databases, depending on the URL.
In wp-config.php, find the DB definitions.
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress.dev');
/** MySQL database username */
define('DB_USER', 'root');
/** MySQL database password */
define('DB_PASSWORD', 'root');
/** MySQL hostname */
define('DB_HOST', 'localhost');
Replace the whole lot with the code below. I’ll comment it properly so you know what it’s doing.
$domain = $_SERVER[HTTP_HOST];
if ($domain === '') : // If is live enviroment
define('DB_NAME', 'our_live_db');
define('DB_USER', 'our_live_user');
define('DB_PASSWORD', 'our_live_password');
define('DB_HOST', 'localhost');
elseif () : // If is staging enviroment
define('DB_NAME', 'our_staging_db');
define('DB_USER', 'our_staging_user');
define('DB_PASSWORD', 'our_staging_password');
define('DB_HOST', 'localhost');
elseif () : // If is first developers local enviroment
define('DB_NAME', 'first_env_db');
define('DB_USER', 'first_env_user');
define('DB_PASSWORD', 'first__env_password');
define('DB_HOST', 'localhost');
elseif () : // If is second developers local enviroment
define('DB_NAME', 'second_env_db');
define('DB_USER', 'second_env_user');
define('DB_PASSWORD', 'second__env_password');
define('DB_HOST', 'localhost');
else () : // If none, fallback to these
define('DB_NAME', 'fallback_db');
define('DB_USER', 'fallback_user'); // Usually 'root'
define('DB_PASSWORD', 'fallback_password'); // Usually 'root' too
define('DB_HOST', 'localhost');
endif;
With those if/else statements, you could make the database side of things work any way you want. You could just have the live environment then have everyone else (meaning every developer and staging environment) linked up to the staging database. That little snippet I mentioned earlier means domain & database issues just don’t exist, so long as you never hard-code a URL in, which is bad practice anyway.
Source Control
I check in code as much as I can, I recommend you to too. Make sure the wp-config.php is in source control too, or at least make sure it’s the same file across every developers system, as well as live & staging environments.
Deployment
I currently use Beanstalk to host my SCM repos. They have a nice feature that deploys sites via (S)/FTP, be it the staging or live environment. They can even handle multiple servers, so if you have a load-balanced setup with multiple servers (without a replication script), you can deploy the code to each of those servers.
Closing…
Hopefully these small tips mean you can work with WP across multiple environments with multiple developers. I’ve used this system on a site with 12 developers before, so I know it works.
Let me know if you have any tips, additions or changes.
Update [03/09/12 @ 12:25pm]
I’m digging up a few solutions and fixes to help with absolute asset URLs. I’ll post them here when I’m done.
Mighty nice tips, thanks !
Nice work Paul. Some nice tips and tricks hidden away in there.
One quick question though, the chunk of code you’ve posted about defining URLs right up the top so the site works regardless of domains, where does that code go? I’m no WP expert (as you know) but I can see how useful it’d be :)
Damn. Can’t believe I missed that bit! I just added where it goes to that section.
Great post, man! I don’t do too much with WordPress lately, but I still took away some useful bits :)
Nice post and good tips. I’ve been having some success using the WordPress plugin WP Migrate DB (http://wordpress.org/extend/plugins/wp-migrate-db/) to move between dev/stag/prod but I may give this workflow a shot in the future. Thanks!
Hi Paul,
I have added in your code for defining the different database using the if/else statements, but I am getting a parse error on the first elseif statement. I am using WordPress 3.5 not sure if that would make a difference?
Thanks!
Hi Vincent, can you share your code in. Gist of Pastebin?
HI Paul,
Here is a Gist of my wp-config file (https://gist.github.com/4363965). Maybe I am missing out thing very simple not sure.
Thanks again.
Ah, I see the issue. I didnt add any clauses to the if/else statements. So The lines 19,24,29,34 & 39 need a clause in the brackets, such as
if ($domain === 'mylivesite.com'andelseif ($domain === 'devsite.dev').Wouldn’t this be bad practice? Not only could other devs but the client themselves and anyone who has access to this folder at any point could pull down this global wp-config file with direct access to MULTIPLE databases. Am I missing something?
You are correct, but I guess it depends on the workflow. I much prefer to have the files on multiple servers to be exactly the same. I’ve never had a problem with files being breached, but having a different wp-config.php file on each server isn’t a problem, just make sure it’s not included in the SCM repo.
I agree with Nick. I lean toward security over convenience. Anyone who has access to your computer (or if your laptop gets stolen) will have access to all of your databases. It is not something that happens all the time but I would be cautious about it. Just a thought.
I normally set up wp-config.php separate for each environment. I then use .gitignore (or any comparable thingy :) in your VCS) to exclude such files as wp-config.php and .htaccess out of my repo just to be safe.
Despite that, very good tips. Thank you.