Hey there! You're using an out-of-date browser, so this site probably looks pretty funny. Upgrade your browser for the full experience.

Configuring WordPress for Multiple Environments

As a production-ready system WordPress can be difficult to setup in multiple environments. Take a look at how we setup our WordPress projects to in multiple environments and shared across our team. All with ease of migration and without plugins.

Now with over 5 million users, WordPress is arguably the web’s de facto blog software. With recent updates in the 3.0 release, it began to cross over into a content management system. WordPress is a production-ready system. You’re up and running with their 5 minute install. But even with the ease of install, setting up WordPress on a tiered dev environment can be a task.

Any serious development project should follow a software development lifecycle. This implies source code management (GitHub, SVN, etc) and at least a development and production environment. Unfortunately WordPress doesn’t really scale well in this area. WordPress requires several hardcoded configurations as well as runtime configurations stored in the database. Each of these may be environment dependent. Of course, you could configure each environment by hand. Yet that’s a maintenance nightmare. VIA Studio manages dozens of WordPress installations. We needed a better process.

There are various plugins – Domain Mirror, MU Domain Manager, WP Network – available to help. These seemed to manage the WordPress runtime configurations using filters. They didn’t solve the hardcoded configurations required by specific environments. In the end, it was just smoke and mirrors. You’re trading configuring one system for configuring another. Furthermore, we like keeping things as simple and native to WordPress as possible.

VIA Studio WordPress Development Architecture

VIA Studio has development, staging, and production environments for each of our WordPress projects. All requiring specific configurations. Our staging and production environment have a complete WordPress install – code + database. However, our development environments are specific for each team member but share the same database. This way each team member can work independently in their environment without effecting others and they aren’t burdened with managing content, as the database is shared. You could set each environment up with it’s own database, but we have yet to find a true need.

We use SVN to manage our source code as well as migration. Any files required by a specific environment are suffixed with a .dev, .stage, of .prod. A symlink is created in the respective environment and added to svn:ignore. For example, robots.txt is not part of our source code, but production has a symlink for robots.txt pointing to robots.prod.txt.

Apache Setup

As WordPress is built upon the xAMP stack, we turn to Apache for mapping our environments correctly. We use Apache VirtualHosts for each one of our projects. Staging and production have the standard domain mapping. In development, we map a domain for each of our developers and point it to their code base. Here’s an example of the VirtualHost configuration for my environment on the viastudio.com project.

<VirtualHost *>
    ServerName viastudio.jmccreary.fuzz
    DocumentRoot /home/jmccreary/www/viastudio.com/webroot
    LogLevel debug
    ErrorLog /var/log/apache2/viastudio.error.log
    CustomLog /var/log/apache2/viastudio.access.log combined
</VirtualHost>

Modifying wp-config

Each environment is correctly mapped to it’s code base and resolves at the appropriate domain. Now WordPress needs to know how to behave for each environment. Most all of the WordPress configuration is handled by wp-config.php. We added a few lines to wp-config.php to essentially sniff out the current environment. Then we include a configuration file for that environment to set any specific options. Any additional configurations are set in favor of the production environment. As WordPress is a production-ready system, this makes the most sense. It’s also a fail safe so to ensure production remains stable.

The following code is added to the top of our wp-config.php:

// NOTE: lives outside webroot for additional security
// set the config file based on current environment
if (strpos($_SERVER['HTTP_HOST'], 'fuzz') !== false) {
    $config_file = 'config/wp-config.dev.php';
}
elseif (strpos($_SERVER['HTTP_HOST'], 'viastaging') !== false) {
    $config_file = 'config/wp-config.stage.php';
}
else {
    $config_file = 'config/wp-config.prod.php';
}

$path = dirname(__FILE__) . '/';
if (file_exists($path . $config_file)) {
    // include the config file if it exists, otherwise WP is going to fail
    require_once $path . $config_file;
}

An example of wp-config.dev.php:

<?php
// MySQL settings
/** The name of the database for WordPress */
define('DB_NAME', 'viastudio_dev');

/** MySQL database username */
define('DB_USER', 'db');

/** MySQL database password */
define('DB_PASSWORD', 'dbpass');

/** MySQL hostname */
define('DB_HOST', 'localhost');

/**
 * For developers: WordPress debugging mode.
 *
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 */
define('WP_DEBUG', false);

// used to override the wp_options and 
// dynamically set the site for this environment
// http://codex.wordpress.org/Editing_wp-config.php
define('WP_SITEURL', 'http://' . $_SERVER['SERVER_NAME']);
define('WP_HOME', 'http://' . $_SERVER['SERVER_NAME']);

// used to determine environment from easily accessible constant
define('VIA_ENVIRONMENT', 'dev');

This file configures the MySQL configuration for the development environment. In addition, this allows developers to quickly turn on debugging. Note that setting WP_SITEURL and WP_HOME are critical for the development and staging environments. This allows us to override the values in the wp_options table, which is set for production. This is especially useful in development as we can use $_SERVER['SERVER_NAME'] to dynamically set this the developer’s domain. Check out the WordPress Codex for more details on how this words. Finally, we also define an environment flag, VIA_ENVIRONMENT, that allows us to perform any environment specific logic in our WordPress code.

Migrating Between Environments

Migrating between environments occurs in two ways: code and database.

The code is simple, as each environment has a working copy of the project, we run svn update. Regardless of your approach, if you’ve followed the conventions above, this is a one step process.

The database is not one step. Due to WordPress being a production-ready system, most data is stored environment specific. Fortunately, migrating the database is rarely required. To do so, we perform the following steps:

  • Export the source environment database
  • Import the database to the destination environment
  • Export the wp_posts table
  • Replace any environment specific paths (i.e. “/” with “/”)
  • Re-import the wp_posts table

Once a site is live we rarely push to production. So you’ll only migrate the database to update your other environments. Since we set most runtime configurations for production, we don’t have a problem migrating the database down. However, you could exclude the wp_options table from your export if you wish.

Additional Tweaks

There are a few tweaks to the project that we’ve done to make things even smoother. Mainly regarding project resources, such as the uploads folder. We’ve decided to not include this in our project files. So we’ve added it to svn:ignore. It is setup in each of our environments as part of the initial install. For development, we symlink it to a public folder so resources are shared among the team. This keeps with the WordPress production-ready mentality and keeps our SVN repository size down.

With WordPress 3.0 you can now setup multi-site with a single WordPress install. Although our configuration works, it requires additional steps for our development environments. We are still working on the best way to handle this. Look for a follow-up blog post in the coming months.

In Conclusion

There is still a little bit of manual work to get multiple development environments setup in WordPress. However, we consider it a wash. You’d have to configure WordPress in each environment anyway. Plus, this is something you can build on top of. We created a set of scripts to initially setup projects on each environment. We can create a WordPress project literally in seconds. We can deploy it to each environment simply and without additional configuration. This is a big win. We don’t have to manage another plugin and we’ve done everything native to WordPress. Some might argue that we’ve hacked the core by modifying wp-config.php. We don’t believe so. This file is meant to be configured for your WordPress install, and that’s exactly what we’re doing. Nailed it!