If you’ve ever set up WordPress, you know that it’s super easy and fast to install. However, if you’ve ever tried to set up WordPress on multiple servers, deploying automatically from a repository or running on different environments, you know that these kind of tasks are a different story.
In this article, I’ll explain how we’ve set up WordPress for the build and deployment of the new SitePoint to adapt to various environments, namely development, staging and production.
WordPress has a central place for its configuration:
wp-config.php. This file contains all the basic information for the blog to work, such as how to connect to the database. Now, when you download WordPress, you’ll get a file called
wp-config-sample.php, which needs to be copied to
wp-config.php and adjusted to your setup. This works if you have just one environment (you’re not editing your files on the server, are you?) or if you take care never to overwrite the production configuration with your development one. If you have an additional staging setup, it gets quite tricky to manage.
Ideally, we would want different configuration files for every environment, automatically loaded by WordPress. Moreover, it would be great if no files actually contain any passwords or other sensitive data so that the files can be stored safely in a repository.
Let’s start by creating one configuration file for every environment. Usually, you’ll have at least three: Development, Staging and Production. I’m calling these
wp-config-development.php. Every one of those files will contain the configuration for that specific environment. We’ll come to the content of the files later, first we need to tell WordPress how to find the right configuration file for the environment.
The problem here is that WordPress does not know which one to load, it just loads
wp-config.php. We don’t want to change the behavior of WordPress, so we’ll have to include our environment-specific configuration file from
wp-config.php. In order to do that, we’ll modify
wp-config.php to look like this:
< ?php /** * The base configurations of the WordPress. */ /** Absolute path to the WordPress directory. */ if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/'); /** Include environment specific configuration. */ define('WP_ENV', (getenv('WP_ENV') ?: 'production')); require_once(ABSPATH . 'wp-config-' . WP_ENV . '.php'); /** Sets up WordPress vars and included files. */ require_once(ABSPATH . 'wp-settings.php');
Basically, we remove all content between
ABSPATH and the inclusion of
wp-settings.php. In between, we load the right configuration file.
How does this work?
The name of the environment is stored in a so-called environment variable. Environment variables are set in the virtual host configuration, which might look like this:
<VirtualHost *:80> SetEnv WP_ENV "development" ServerName blog.vm ServerAlias blog.vm <Directory /var/www/blog> ... </Directory> </VirtualHost>
WP_ENV can be read in PHP via
getenv('WP_ENV'). In our example, we store that value in a constant called
require_once(ABSPATH . 'wp-config-' . WP_ENV . '.php'); will load the correct configuration file.
We now need to copy all settings (except
ABSPATH and the inclusion of
wp-config-sample.php into each configuration file.
However, as I stated earlier, it would be preferable to not just enter the sensitive data directly in the file. We have two options:
Option 1: Environment variables
We’ve used an environment variable already to determine which environment we’re in. In the same way, we can set the database password etc. in environment variables as well and read them in via
getenv. For example:
define('DB_NAME', getenv('DB_NAME') ?: 'blog');
DB_NAME from the environment and falls back to use
blog. Providing fallbacks is especially helpful when sharing the codebase with other developers. If they set up their database using the default values, everything will “just work”, without the need to change anything.
On the other hand, if they prefer a different setup, it’s easy to change the environment values without having to touch the code, which is vital if you want to work on the same codebase.
Option 2: Write on build
If you’re using a build system to deploy your code, you could also use placeholders which are replaced during build, such as:
However, this option only works for the staging and production configurations, it’s not suited for your development configuration file.
When you choose to use environment variables everywhere, you could even use just one configuration file that reads all values via
getenv. However, I prefer having separate files. This makes it easier to see which configuration is in use for which environment. Also, you typically have some constants you only need in development, such as debugging:
That covers the setup for different configuration files. One other thing that I found really helpful when dealing with multiple environments was to set
WP_SITEURL in the configuration file instead of reading it from the database.
To wrap up, here are the advantages of this setup:
- It’s easy to see how a specific environment is configured
- New environments can be added easily
- Environments can use different constants
- All configuration files can safely be committed to a repository
- Using the environment variable setup, no credentials are stored at any time in a file
Michael Sauter is a German web developer at SitePoint. He's maintaining the backend of the various SitePoint sites and works on new features and products. Usually working with Ruby or PHP - currently interested in Go and Docker.