Configuring WordPress for multiple domains

One if the things you will run into while doing WordPress development is switching between your local development environment, the staging environment and, eventually, the production environment.

If you set up a new WordPress website and you use the out-of-the-box configuration mechanics, you will find that WordPress stores the website domain in the database. This means that whenever you e.g. generate a URL in your theme or insert an image in a post that that particular domain will be used to create the URL with. If you switch between environments this will become an issue.

Luckily there is a convenient way around this problem. In our wp-config.php we can set the WP_SITEURL and the WP_HOME constants and if we do, we’re overriding the value that is stored in the database. Once you set these constants you will also notice that you can no longer edit these values from the administration panel under Settings -> General.

Another thing you will run into when switching environments is your database details. If you run your website on shared hosting you don’t always get to choose your database name and/or database user name. This means that when you switch environments you also want to change these credentials.

What you don’t want is to manually edit your configuration each time you switch environment. How can we fix this?

Now that you have a way to programmatically set the domain for your website, it would be nice to automate things depending on which domain the website runs on. E.g, throughout the development live-cycle of our website we eventually switch between the following three domains (environments):

1
2
3
http://dev.example
http://stage.example.com
http://www.example.com

The first domain is the local development environment domain, the second the staging environment and the third one the production environment. We can configure our website in such a way that depending on either one of these domains our website runs on it picks up the correct configuration. Let’s look at some code. We start by adding the following to the beginning of wp-config.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
global $domain_config;
 
$domain_config = array(
   'default' => array(
      'db_host' => 'localhost',
      'db_charset' => 'utf8',
      'debug' => TRUE,
   ),
   'dev.example' => array(
      'siteurl' => 'http://dev.example',
      'db_user' => 'example_dev',
      'db_name' => 'example_dev',
      'db_password' => 'dbpassword',
   ),
   'stage.example.com' => array(
      'siteurl' => 'http://stage.example.com',
      'db_user' => 'example_stage',
      'db_name' => 'example_stage',
      'db_password' => 'dbpassword',
   ),
   'www.example.com' => array(
      'siteurl' => 'http://www.example.com',
      'db_user' => 'example_prod',
      'db_name' => 'example_prod',
      'db_password' => 'dbpassword',
      'debug' => FALSE,
   ),
);
 
global $config;
 
$config = (object)array_merge($domain_config['default'],
   $domain_config[ $_SERVER['HTTP_HOST'] ] );

As you can see we define a data structure that represent our three different environments. The default structure we use for either default values and/or values that aren’t set in other configurations.

When we create the $config object we basically merge the default configuration with the configuration indicated by $_SERVER['HTTP_HOST']. The $config object now holds all the configuration values for our website. We can now set all the necessary values to configure our website:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
define('WP_HOME', $config->siteurl);
define('WP_SITEURL', $config->siteurl);
 
/** The name of the database for WordPress */
define('DB_NAME', $config->db_name);
 
/** MySQL database username */
define('DB_USER', $config->db_user);
 
/** MySQL database password */
define('DB_PASSWORD', $config->db_password);
 
/** MySQL hostname */
define('DB_HOST', $config->db_host);
 
/** Database Charset to use in creating database tables. */
define('DB_CHARSET', $config->db_charset);

Now that we have the configuration part out of the way there is still one major issue we need to address. Whenever you insert an image into a post or page, the full URL to that image is stored in the post or page data. This means that if you insert an image on your local development box and you then move your website to your staging environment, the images suddenly won’t load because it’s trying to load the image from an unreachable domain (at least for people who don’t have a local development environment set up). This means that you need a way to filter your post and page content before you output it in your theme. To the rescue; the_content filter. Add the following code to your theme’s functions.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function my_the_content_filter( $content ) 
{
   global $config;
   global $domain_config;
 
   $siteurls = array();
 
   foreach( $domain_config as $values )
   {
      $siteurls[] = $values['siteurl'];
   }
 
   $content = str_replace($siteurls, $config->siteurl, 
         $content);
 
   return $content;
}
 
add_filter( 'the_content', 'my_the_content_filter' );

The above filter will turn the hard coded URL’s which where stored in the database relative to the current website configuration. So, if you inserted an image on your local development machine and the URL stored was http://dev.example/wp-content/uploads/myimage.jpg and you’re moving to the staging environment, the outputted URL will now be translated to; http://stage.example.com/wp-content/uploads/myimage.jpg.

We’re all done. You can now safely move your website from environment to environment without going through the hassle of manually configuring it each time or content links breaking.

This entry was posted in Wordpress and tagged , , . Bookmark the permalink. Both comments and trackbacks are currently closed.