This is the 4th post in a series of developing for WordPress in a DevOps friendly way. The other articles:
- Introduction to WordPress and DevOps
- Developing with WordPress and Vagrant
- Grunt Automation for WordPress developer
- WordPress configuration management
In the previous posts in this series we’ve been looking at how to work with Vagrant and WordPress and how to automate setup work using Grunt and WP-CLI. In this posts, we’ll look a little bit on how we can transfer various settings between the WordPress database and into text files in the source code tree. Because as soon as we have the settings in files, we can easily transfer those settings to a target system such as a staging environment or the live site.
There’s a Git repository available with code for this post here: https://github.com/eriktorsner/wpconfigurationmanagement I suggest you clone or download the code to your development computer to make it easier to follow along.
WordPress settings
A Setting is any of the small or large things you change in the Settings menu in the WordPress admin area. The number of blog posts shown on the first page is a setting and so is the site title and the default date format.
WordPress uses the database to store settings into a table named wp_options (at least as long as you are using the standard wp_ prefix). Most of the settings that a core WordPress installation will put into the wp_options table are simple scalar values, a string or a numeric value. But some of the settings consists of larger more complex structs like an array or even arrays containing objects containing arrays. The internal WordPress code makes sure that pretty much anything you can represent in a PHP variable can be stored as a setting. If needed, WordPress uses the native PHP function serialize() to convert any given variable to a text representation suitable for database storage and then unserialize() to convert it back when needed.
Serializing
The concept of taking a complex structure and transforming it into a text representation is called seriallization, so no wonder the PHP functions are named as they are. In our ambitions to automate the setup of WordPress, we want to serialize some settings to a text file that we can keep in our source code repository. When we first install a development version of our WordPress site in a new environment, or when we want to deploy it to another environment, we want to take that text file with serialized settings and update the database. To do this we will continue to build on the WordPress skeleton from the previous posts, you’ll find it in the Github repository for this post. To get started with this code repository, please refer to the first post to learn a little bit about Vagrant and how we’re using it. A few notes:
- This repo uses an evolved version of the Vagrantfile. Only the rows you need to change are present, everything else is moved in to a file in the vagrant/ sub folder.
- No need to change anytning inside the vagrant/ sub folder, everything it’s taken care of during provisioning.
We’re going to talk about two different approaches for managing settings in a text file. The first approach is using Gruntfile.js itself, the other approach uses the free plugin WP-CFM.
Keeping settings in Gruntfile.js
The most straight forward way would be to use Gruntfile and Wp-cli. The settings themselves will be in the form of Wp-cli statements that will be automatically inserted into the target WordPress installation when the Grunt task wp-setup is executed.
[code firstline=”36″ title=”wp-setup task in Gruntfile” language=”js” highlight=”47-49″]
grunt.registerTask(‘wp-setup’, ”, function() {
ls = getLocalsettings();
wpcmd = ‘wp –path=’ + ls.wppath + ‘ –allow-root ‘;
// some standard plugins
stdplugins = [‘google-analyticator’, ‘wp-cfm’];
for(i=0;i<stdplugins.length;i++) {
name = stdplugins[i];
shell.exec(wpcmd + ‘plugin install –activate ‘ + name);
}
shell.exec(wpcmd + ‘option update blogname "New blog title"’);
shell.exec(wpcmd + ‘option update blogdescription "experimental tagline"’);
shell.exec(wpcmd + ‘option update posts_per_page "20"’);
})
[/code]
The three highlighted rows will update the Site title (blogname), the tag line (blogdescription) and the ‘Blog pages show at most’ setting (posts_per_page) that are found in WordPress Admin. This is a very manual form of serializing settings to disk and it’s easy to get started with. If you only have a few of them that you need to set, this approach will work but it has a few downsides.
Obviously, the manual work involved in writing the wp-cli statements in your Grunt file is not very optimal. Easy to forget individual settings, easy to lose the overview etc. The other downside is that changes you make in WordPress admin has no way of automatically find their way into the Gruntfile. You’re in for a lot of manual work. But there is another way.
WP-CFM
WP-CFM is a free plugin available in the WordPress plugin repository. It’s name stands for WordPress Configuration Management and it does exactly that: Configuration Management. WP-CFM uses a concept call bundels. A bundle is a group of individual WordPress settings. WP-CFM can Push a bundle to file, meaning that it will read the value of each of the settings in the bundle from the database and store them in a file. And later, WP-CFM can Pull that file back in and restore those values in the database.
In the Gruntfile above I took the liberty of installing and activating wp-cfm in the WordPress installation in the Vagrant box, so if you’re following along you should already have it in WordPress. This plugin adds a menu item under settings named WP-CFM. The main WP-CFM screen looks like this:
We want to create a bundle with the same three setting that we handled in the Grunt task above. So we’ll go ahead and click ‘Add Bundle’, name it ‘settings’ and select the individual settings items we need:
After the bundle is created and saved, we can click ‘Push’ to store those three settings to disk. You should end up with a text file in /vagrant/www/wordpress-default/wp-content/config named settings.json:
[code title=”wp-content/config/settings.json” language=”js”]
{
"blogdescription": "experimental tagline",
"blogname": "New blog title",
"posts_per_page": "20",
".label": "settings";
}
[/code]
As you can see, WP-CFM uses a JSON file to store the individual values and stores the file in a predictable location. For fun, we can change the “blogname” setting inside this file and try the Pull button (you probably will need to reload the page for the Pull button to become active). Once the updated settings has been pulled into the database and you’ve reloaded the page, you should see that whatever value you selected for “blogname” now is in the page title.
A little automation
The one great thing with WP-CFM that I didn’t mention yet is that it was written with support for Wp-cli right out of the box. WP-CFM adds a command verb to Wp-cli named ‘config’ with sub commands push and pull. We just need to call these two commands from our Gruntfile to automate things. As usual, a little bit of plumbing is also needed as well, best explained with code, so let’s have a look at the two new Grunt tasks that we’ve added for this post:
[code title=”Gruntfile.js” language=”js” firstline=”53″]
grunt.registerTask(‘wp-export’, ”, function() {
ls = getLocalsettings();
wpcmd = ‘wp –path=’ + ls.wppath + ‘ –allow-root ‘;
pwd = shell.pwd();
shell.mkdir(‘-p’, pwd + ‘/config’);
// push settings from DB to file
src = ls.wppath + ‘/wp-content/config/settings.json’;
trg = pwd + ‘/config/settings.json’;
shell.exec(wpcmd + ‘config push settings’);
shell.cp(‘-f’, src, trg);
});
grunt.registerTask(‘wp-import’, ”, function() {
ls = getLocalsettings();
wpcmd = ‘wp –path=’ + ls.wppath + ‘ –allow-root ‘;
pwd = shell.pwd();
shell.mkdir(‘-p’, ls.wppath + ‘/wp-content/config’);
src = pwd + ‘/config/settings.json’;
trg = ls.wppath + ‘/wp-content/config/settings.json’;
shell.cp(‘-f’, src, trg);
shell.exec(wpcmd + ‘config pull settings’);
});
[/code]
- Line 53, define the task wp-export
- Line 58, create the /vagrant/config folder unless it already exists
- Line 63, run the wp-cli command ‘config push’ for the bundle named ‘settings’
- Line 64, copy the settings file into our local folder /vagrant/config where it will be under source code control
- Line 67, define the taks wp-import
- Line 72, create the folder www/wordpress-default/wp-content/config unless it already exists
- Line 76, copy the settings.json file from the project folder into the correct folder in the WordPress installation (where WP-CFM will expect to find it)
- Line 77, run the wp-cli command ‘config pull’ for the bundle named settings so that each settings is pulled from the file into the database
Since the WP-CFM plugin was build for automation from the start, our work is reduced to managing the settings file so that we can keep in under source code control. With these two Grunt tasks, we’ve now automated the process for storing WordPress settings in the source code control system.
A few pitfalls
Using WP-CFM together with Grunt and wp-cli takes us a long way in terms of creating a fully automated process for managing WordPress. However, this process isn’t really perfect yet. There are a few issues to look out for when it comes to WP-CFM:
- Some settings might store the absolute URL for a post or page on the WordPress installation. If that setting is pulled from disk to the database unchanged, the live site might end up with URL references to the development version of the site
- Some settings contains references to a page, a post or a menu item using the internal database id and the database ID might differ between the development version and the production version.
These two issues as well as the challenge of moving actual content (pages, images etc) from development to production is going to be covered in future posts in this series. So stay tuned!
WordPress DevOps – The book
I’ve written an ebook on this subject. Released in September this year on Leanpub.com. Expect a 100+ tightly written pages where we walk through the creation of the skeleton of a WordPress based Saas application, connected to Stripe and Paypal with a working deployment process that takes content into account. Just add your billion dollar idea. Jump on over to Leanpub to get your copy.
[wysija_form id=”3″]