WordPress and Multiple Environments

Last Updated August 25, 2016

We’ve talked about developing sites locally using MAMP. Awesome, right?!

The only “problem” is suddenly you’re juggling multiple database configurations. How do you manage that…easily?

I’ll show you two different ways. The first way, is my go to. I’ve been using this method for a couple of years.

The second way, I ran across this past week and it’s pretty slick. It will be making it’s way into my code base.

local-config.php

NOTE:

This method is great if you’re working locally and have a production server. — Two different environments.

Typically, all your database information is stored within wp-config.php, something like this:

define('DB_NAME', 'wordpress');
define('DB_USER', 'root');
define('DB_PASSWORD', '*****');
define('DB_HOST', 'localhost');
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

In my wp-config.php I have a few extra lines of code:


// Include local configuration
if (file_exists(dirname(__FILE__) . '/local-config.php')) {
include(dirname(__FILE__) . '/local-config.php');
}

// Global DB config
if (!defined('DB_NAME')) {
define('DB_NAME', 'wordpress');
}
if (!defined('DB_USER')) {
define('DB_USER', 'root');
}
if (!defined('DB_PASSWORD')) {
define('DB_PASSWORD', '*******');
}
if (!defined('DB_HOST')) {
define('DB_HOST', 'localhost');
}

/** Database Charset to use in creating database tables. */
if (!defined('DB_CHARSET')) {
define('DB_CHARSET', 'utf8');
}

/** The Database Collate type. Don't change this if in doubt. */
if (!defined('DB_COLLATE')) {
define('DB_COLLATE', '');
}

Don’t be intimidated!

Let’s talk through what each line of code does. The first few lines is where all the magic lies:


// Include local configuration
if (file_exists(dirname(__FILE__) . '/local-config.php')) {
include(dirname(__FILE__) . '/local-config.php');
}

All it’s saying is, “Does a file local-config.php exist (within your root directory)?” If so, go ahead and include it.

Then, for each of the settings I listed, it asks, “Is this already defined?” If not, use this value.

Pretty straight forward.

I’ll go ahead and include all my production server credentials within this file.

If you try looking at your site on your computer, you’ll probably get a Database error. — That’s because it’s looking for the production database and not the one on our machine.

Remember how our code asked if local-config.php exists? Let’s use that file to override the information within wp-config.php and point to our local server.

Within your root directory, create a new file called local-config.php.

Add the following lines of code to your new file:

<?php
define('DB_NAME', 'zeal_wp');
define('DB_USER', 'root');
define('DB_PASSWORD', 'root');
define('DB_HOST', 'localhost' );
$table_prefix = 'wp_';

NOTE:

Did you notice how I don’t have a closing ?> tag at the end? With PHP you can leave it open like that. In fact, I’d recommend it. Why? If you have trailing white space (a space or tab) after the ?> it can mess up how your file is read, more specifically how the header information on yoru page is rendered.

There’s nothing more frustrating than getting an error message, and deleting lines and lines of code, trying to figure out where the problem is, only to discover it’s a space at the end of your file throwing everything off. Do I sound like I speak from experience?

Replace the information within local-config.php with your local server information.

Are you running MAMP and not sure what this information is or where to find it? I wrote a whole post devoted to MAMP that walks through this very topic.

Awesome, now when you pull up your site within the browser, you shouldn’t have any problems.

When you get ready to put the files on your server, don’t upload the local-config.php file. Remember, it contains your computers information. You don’t want that overriding the live server’s (the information within wp-config.php).

If you’re using .git, you can simply include local-config.php within your .gitignore.

Not to shabby.

If you’d like to see the entire wp-config.php, have at it!

Multiple Environments

The first method will get you pretty far. Like I said, I’ve used that method for the past couple of years, and it’s treated me well.

This week, I was working on a site, I had several different environments:

  • Local Server where I was developing the site on my computer.
  • Staging Server where I was allowing the client to preview all the site updates before going live.
  • Production Server where the live site lives.

I could use the local-config.php trip, but suddenly I’m managing several different configuration files. Surely there’s an easier way. — And there is!

With a multiple environments, I can have each server’s information (environment) in a seperate file. The code will know where it is (local, staging, or production) and use the correct file…magically.

With a little help from Jonathan Suh, I got exactly what I wanted.

I changed the code within my wp-config.php to this:

// Set your environment/url pairs
$environments = array(
'local' => 'createdbyahha.dev',
'staging' => 'staging.createdbyahha.com',
'production' => 'createdbyahha.com'
);

// Get the hostname
$http_host = $_SERVER['HTTP_HOST'];

// Loop through $environments to see if there’s a match
foreach($environments as $environment => $hostname) {
if (stripos($http_host, $hostname) !== FALSE) {
define('ENVIRONMENT', $environment);
break;
}
}

// Exit if ENVIRONMENT is undefined
if (!defined('ENVIRONMENT')) exit('No database configured for this host');

// Location of environment-specific configuration
$wp_db_config = 'wp-config/wp-db-' . ENVIRONMENT . '.php';

// Check to see if the configuration file for the environment exists
if (file_exists(__DIR__ . '/' . $wp_db_config)) {
require_once($wp_db_config);
} else {
// Exit if configuration file does not exist
exit('No database configuration found for this host');
}

It’s a little more complicated, but as always, we’ll walk through it and I’ll help you make sense of what you’re reading.

The first few lines create an arary that stores all the environments that we’ve been talking about. For each environment we have a name (local, staging, production) and a corresponding URL:

$environments = array(
'local' => 'createdbyahha.dev',
'staging' => 'staging.createdbyahha.com',
'production' => 'createdbyahha.com'
);

NOTE:

If I lost you at array, don’t worry. It’s just a variable that stores multiple pieces of information. You can think of it like file folders. Each file folder has a label (the environment name) with content inside it (createdbyahha.dev).

As you’re adding environments, the important thing to note about an array is that each item is separated by a ,. How many times have I left that off or tried to use a ; instead?

The next section, figures out where we are.

// Get the hostname
$http_host = $_SERVER['HTTP_HOST'];

Then, it asks, “Is there a match with where we are and the options listed?”

// Loop through $environments to see if there’s a match
foreach($environments as $environment => $hostname) {
if (stripos($http_host, $hostname) !== FALSE) {
define('ENVIRONMENT', $environment);
break;
}
}

If there’s not a match and you can’t find the environment, display an error message:

// Exit if ENVIRONMENT is undefined
if (!defined('ENVIRONMENT')) exit('No database configured for this host');

If the user hits the error, the code will actually quit. — That’s the exit part that you see.

Let’s grab the file for the environment we found. Create a variable to hold the file name in it.

// Location of environment-specific configuration
$wp_db_config = 'wp-config/wp-db-' . ENVIRONMENT . '.php';

If that file exists, include it. Otherwise, display an error message. Again, if the code hits the error, the code will quit.

// Check to see if the configuration file for the environment exists
if (file_exists(__DIR__ . '/' . $wp_db_config)) {
require_once($wp_db_config);
} else {
// Exit if configuration file does not exist
exit('No database configuration found for this host');
}

There are no default settings that get overwritten.

Now, create a folder within the root directory of your project, called wp-config.

Create a new file for each environment. Name it wp-db-ENVIRONMENT.php, swapping out “ENVIRONMENT” with the actual name of your environment.

I have 3 files, one for local, staging, and production:

WordPress - Multiple Environments

Within each file, I have this code, swapping out the database name, user, password, and host credentials to match the environment:

if (!defined('ABSPATH')) exit();

define('DB_NAME', 'wordpress');
define('DB_USER', 'root');
define('DB_PASSWORD', 'root');
define('DB_HOST', 'localhost');
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

Done!

If you want to see my entire wp-config.php file for reference, go for it!

Yes, the second method takes a little bit extra setup, but in my ever so humble opinion, it feels a lot cleaner and more versatile.


If you grabbed the entire wp-config.php file for either use case, you may have noticed, that the Authentication Unique Keys and Salts section is empty. You’ll need to generate these yourself, for your project. It’s not complicated. Just go to the wordpress.org site, they have a salt generator on their site that will provide the code you need to copy and paste.


Reference and Resources


The Conversation