Single responsibility principle

Single responsibility principle

The single responsibility principle (SRP) tells us that each module, class or even function should have one single responsibility It means that every class, or similar structure, in your code should have only one job to do. Everything in the class should be related to that single purpose. It is a simple and intuitive principle, bu it is sometimes hard to get right.

A lot of us developers seem to have an ill adjusted intuition for when it’s time to restructure our code. It’s far too easy to convince ourselves that we’ll go back and clean up at a later time. I convince myself about that a lot more often than I actually go back and refactor something.

We also seem to have an even worse intuition for what type code code that will be easy to maintain in the long run. A lot of us (again, that includes myself) gravitate towards code that pack too much functionality into one place. We tell ourselves that it’s a quicker way to get the job done.

However, there’s a price to be paid for going to quick at the beginning and that price is almost always that you go gradually slower and slower. The very things we did early on to increase speed has a huge risk of slowing us down in the long run.

The point with the single responsibility principle is to help us get things (more) right from the start. The SRP tells us to take the time up front to design our code in a way that helps us in the long run. Each group of functionality into it’s own encapsulated and isolated class or module. Don’t mix  and match apples with rocket ships.

Single responsibility principle leads to Cleaner code

As with many things, you can take the single responsibility too far. It does not mean that your classes should only contain just one method. There may be many members as long as they relate to that single responsibility. It may be that when the a change occurs, multiple member functions of the class have to be updated. It’s even quite likely in many cases.

But the SRP does mean that we should try to separate code that might change for different reasons. A class that could change both because we want to modify front end HTML color scheme OR because we need change authentication method is most likely violating the SRP.

Working with the SRP is likely to have a  tremendous effect on your code. You are going to get more but smaller classes in your design. Each of those classes will be a lot cleaner since they’re only concerned with one thing.  You’re also going to have to be more diligent with how you name your classes and if you’re OK with letting go of PHP 5.2 (you should) you are going to benefit from using PHP namespaces and folders. You’re also being forced to think more about how each class interacts with the others since everything isn’t just available in the same class or even namespace any more.

A well thought out system design where classes are logically organized in folders  and where each class is  tightly focused on a single purpose sounds kind of appealing, doesn’t it? It also sounds a lot like what we call clean code.

(and clean code tends to be more testable and maintainable).

Finding the balance: Class Employee

There’s a classical example used to explain the only one reason to change idea, a class used to represent an employee in a system. The questions we’re supposed to ask is if it’s OK to have both functions to calculate the employee’s salary (business logic) and a set of functions that reads and writes employee objects to the database (persistence)?

 

The answer according to the SRP is no, the employee class should not mix business logic with persistence functionality. There are at least two reasons for the employee object to change, the first reason would be if we want to change the method used to calculate salary. The second reason to change would be if we decided to modify the database schema. Therefore according to the SRP, we should design our system with one class for employee business logic and another class for employee persistence. Different reasons for change means different classes.

But in a WordPress situation you could argue that this is a little bit over the top. Imagine a WordPress plugin that adds the custom post type to implement the Employee object and a third party tool like Advanced Custom Fields to define the various extra fields. We could still split the functionality in to two classes, one for business logic and one for database persistence.

The persistence mechanisms for a custom post type are largely decided by functions provided by the WordPress core and in this case, Advanced Custom Fields. Isolating persistence into an EmployeePersister class would simply mean that we create an additional layer between the WordPress database functions and the rest of our code. WordPress wraps the MySQL functions into an API and then we come along and wrap that API in another API. Does is make sense to create a separate class for 4-5 lines of code?

Well, it could make sense. If already know that we want to provide a Drupal version of that same plugin. Or perhaps we want to move away from using a custom post type to using our own database tables instead. If any of those two changes are actually realistic, we should go ahead and put the persistence specific code in a separate class.

But if you’re reasonably certain that such changes will not occur, then you can probably safely use the one Employee class for both types functions.

But then again, it could turn out that loading and saving the Employee internal state requires a lot of additional logic that is subject to change at a later time. In that case following the SRP and create a separate EmployeePersister class makes sense.

Applying the SRP requires us to find a balance between strict design and some sort of manageable reality.  If we try too hard to look into the future and foresee every potential change, we’re probably going to end up with things we’re never going to need  (YAGNI) which is bad in itself.

The opposite

One way to understand the SRP is to consider the very opposite. A god-object, sometimes also called a god-class.  We say that we have a a god object (or function) when a lot or even all of our code ends up in one really big class with lots methods, complex internal state, tons of dependencies and lots of responsibilities. Think of this one class as the god of your system, everything depends on it and it depends of nearly everything else. Even if the term god-object typically means the main class file of a system, god-objects are found in sub systems as well. In WordPress we can see an overall well designed plugin have local god-objects for certain things, I’ve seen a lot of Widgets implemented as de-facto god-objects.

The god object is a well known anti pattern (a common solution seen in system design that is usually ineffective and risky). A god-object often turns in  to a maintenance nightmare, are difficult to debug and nearly impossible to test using standard tolls such as PHPUnit. We should avoid them.

A few signs that one of your classes might be trying to do too much:

  • Your class is very long. If your class grows a lot beyond 1000 effective (not counting comments and white space) lines of code, you can probably split it into smaller classes with more distinct responsibilities
  • One or many of the methods in your class grows beyond 100 effective lines of code.  Large functions can usually be broken up into several smaller functions.
  • The total number of methods (excluding getters and setters) grows too far beyond 25. This depends a lot on the specific class, but too many functions is an indication that your class is doing too many things.
  • Your class declares a mix of static functions and instance functions. This is needed in some specific cases like to implement the singleton pattern. But if there’s a mix of static and non-static functions it usually means that the static functions has nothing to do with the object state and therefore could have been refactored into a separate class.
  • Your class has functions that outputs HTML or CSS code directly (example).  Following the SRP, a better option would be to separate HTML snippets and entire pages into their own files.
  • Your class constructor have side effects on global state (state that is not part of your actual class). Typically via calls to add_action or add_filter (same example). This makes it a lot harder, sometimes impossible, to write unit tests for your class.
  • Your main class file can’t even be included or required into a stand alone script without first loading WordPress.  This is typically seen in cases where a developer mixes a class definition and old school procedural code into the same module. So that even loading that class have the side effect that a piece of procedural PHP code gets executed (same example again)

If your code does more than one of the above things there’s a chance that you will get long term benefits from splitting your class into smaller ones.

A great tool to get you started with analyzing your code is the PHP Mess detector. It’s a static code analyzer that checks your code for a number of metrics including the size of your classes and functions.

Example: The WordPress plugin boilerplate

A very pragmatic thing to do is to look at the specific real life case with a WordPress theme or plugin. A good place to look at is the WordPress plugin boilerplate written by Tom McFarlin’s WPPB foundation plugin (now maintained by Devin Vinson). It’s a foundation that many WordPress plugin are based on and it provides a good starting point of how to apply the SRP in a WordPress environment. From a birds eye perspective, the boilerplate is organized like this (lots of details excluded):

WORDPRESS PLUGIN BOILERPLATE

The main plugin file serves to bootstrap the rest of the plugin. It’s the only file that WordPress core really knows anything about and it’s what gets included in at every request to the server. The main job is to load the main class and hook it up to the WordPress init function.

The includes folder is where all common code is placed, including the main plugin file. Note that there are separate PHP modules for plugin activation and deactivation, each with a single responsibility. The boilerplate even uses a separate module to register all WordPress actions and filters needed by the plugin.

The admin folder is for all code that is related to the admin dashboard pages needed by this plugin. The one thing to note here is that the boilerplate encourages us to keep functionality in the main admin class but everything that renders HTML in a separate views folder (it’s actually called “partials” in real life).

The public folder  has the exact same structure as the admin folder, but it’s intended for functionality and views that are used on the front end.

This basic structure of classes and folders provides an idea about how to separate different things into different folders and classes. Naturally, once you decide to base your plugin on this boilerplate, you will have plenty of opportunity to violate the SRP within this structure. Jamming all vital functionality into the main plugin class takes you right back to an evil god-object.

Look at the boilerplate as a starting point, as  soon as your plugin gains in complexity, it’s your job to ensure that the code you add doesn’t pack too much into one place. Be generous with creating additional classes and make sure that similar functionality is keps grouped together and well isolated. Consider what types of reasons that could drive change in your project.

(note: There are some aspects of the plugin boilerplate that I think could be done differently to work better with other SOLID principles. Especially regarding dependency injection, but that’s a topic for another post)

Over to you

Do you have a specific question or do you just have something to add? Let me know in the comments below.

The SOLID principles and WordPress

SOLD WordPress

There are no shortage of acronyms in the field of computer programming. Some of those acronyms might come and go like a one hit wonder, others are here to stay. Robert “Uncle Bob” Martin first introduced the SOLID principles in the early 2000s and they’ve been around ever since. It’s an evergreen.

First they were just called “the first five principles” and is a collection of ideas brought forward by Robert Martin himself as well as other computer scientists before him. Just a few years later Michael Feathers came along and dubbed them SOLID which makes them a lot more fun and absolutely more  memorable.

Uncle Bob argued that by sticking to these 5 “first” principles of software design, a system will be much easier to maintain and extend over time.  Code that is written in adherence with the SOLID principles typically also turns out to be very clean and much more testable than code that violates them. If that’s not enough to pique your interest about a soon to be 20 year old set of ideas,  I can reveal that the SOLID principles have stood up well against the tests of time.  Each of the five principles are still very relevant and can help us write better code.

S.O.L.I.D

SOLID stands for:

As with most things in life, there’s a balance between being dogmatic and pragmatic, between being short sighted or planning for the long run. In a series of five posts, I’ll be talking about the five principles and how they can help us write better WordPress themes and plugins.

Knowing about and understanding the SOLID principles isn’t a guarantee against unclean or bad code. Think of the principles as something to lean on whenever you’re trying to work out how to design your code.In my own work, I often find that the cause of a messy code problem is a bad overall design. Solving the design issues typically makes the coding part much easier.

So if you ever find yourself going too slow through a project because it has become too complicated, you could take a step back and consider the SOLID principles.  They might be just what you’ve been looking for.

The first one is just out, read all about the single responsibility principle here.

New tricks for the Checksum API

Dog with new trick

As a step in preparing for new features in Integrity Checker and wp-checksum, the backend API that powers the two packages has learned a new trick. Alternative hashes, a way of saying that a specific file may have more than one acceptable MD5 hash.

Why are alternative hashes needed?

Lots of WordPress plugins and themes sometimes has small changes made to them without the version number getting bumped. The most common example of this that the readme.txt of a plugin is often changed when a new version of WordPress is released.

The readme file contains information about the latest version of WordPress that it was tested with. This information is shown to users in the plugin repository and can be a vital piece of information before deciding to install a plugin. So it’s quite natural that after a new release of WordPress, plugin authors update the readme file to reflect successful testing on the new version. The content of readme.txt doesn’t change the plugin functionality at all, so it’s quite OK to update it without bumping the plugin version.

The problem is that an updated readme.txt forces the MD5 hash to change and both Integrity Checker and wp-checksum will see this as a sign of a modified file and alert the user. Integrity Checker (and soon wp-checksum) has the concept of a SOFT change and will flag a modified readme.txt as one. But the modified file is still shown and may cause concern.

It’s not too uncommon for plugin authors to modify other files without bumping the version number. We’ve seem a lot of different files get a lot of different modifications within the same plugin version number. Sometimes it’s a corrected typo, other times it’s a quite dramatic change.

The end result is that for any given official version of  a plugin or theme there may be multiple actual versions, one actual version for each commit into the WordPress repository.

 

How does alternative hashes help?

By having alternative hashes defined for a file, the clients that are using the API will have far fewer false positives. The contents of a file in your WordPress installation might differ slightly from what that same file looks like in the WordPress repository. But that doesn’t mean that your files was modified in a malicious manner, it might just mean that the plugin  author modified the file without bumping the plugin version.

For any type of security related software, avoiding false positives is a good thing for several reasons. Most importantly, it means that whenever a real modification is found, you are much more likely to take it seriously. Another benefit is to avoid causing uncalled for worries, the less experience a user has, the more likely he/she is to become overly worried about something that turns out to be a false positive. All in all, reducing false positives is a win.

Next steps

With the upgraded backend API in place, both wp-checksum and Integrity Checker now needs to get support for the added feature.  We expect to have both clients updated within a week. Having said that, we’re not 100% in control over when the updated version of the plugin in the WordPress repository will be made available since the repository maintainer has a stricter upgrade procedure in place these days.

Access to the API

For the majority of users, accessing the API is mostly done via one of the clients we provide, Integrity Checker and wp-checksum, but the API is public and to some extent free to anyone.  If you’re interested in developing your own client, please don’t hesitate to contact us for API keys as well as developer documentation.

Your thoughts

We’d be glad to hear back from you. Ping us if you want to know more about the API, get an API key or just to say hi. We’d be especially happy if you have any ideas on how to improve client functionality or if you want to contribute to the development.

Introducing Integrity Checker

integrity-checker-logo

I’m very proud to introduce the newest member in the WordPress Essentials family: The WordPress Integrity Checker plugin, or just Integrity Checker for short. Download it straight from the WordPress plugin repository or stay here and read more about it.

Integrity Checker is an admin plugin that will help you find potential security issues with your WordPress installation. It uses three different strategies to do so:

  1. Verifying file integrity by comparing the checksum of each file in WordPress core, plugins and themes against it’s original version
  2. Verifying file and folder permissions for all important WordPress files and folders
  3. Checking for some well known security problems related to WordPress settings.

File Integrity

Integrity Checker uses the same powerful technique and back end API as it’s older brother wp-checksum. It will go through all individual files in your WordPress core as well as all plugins and themes and compare the exact content of the file with the original version of each file. Any difference between your local version is reported back to you.

Issues in plugin
Integrity Checker reporting about suspicious issues in a plugin

Our back end database keeps MD5 signatures (fingerprints) of how each file looked in the WordPress official repositories at the time of it’s release. So even if you’re not running the latest version of every plugin, we’re almost always able to find the original version to compare to. What makes Integrity Checker (and wp-checksum) a little bit unique is that while many other tools can compare files in WordPress core, our back end API also covers plugins and themes (and even som premium plugins too).

Knowing that a file has changed is one thing. But Integrity Checker takes one more important step and lets you see a visual diff between your file and the original, making it extremely easy to understand what’s going on. Sometimes a detected change is just a few added spaces in a harmless place, sometimes it’s an outright security problem. Integrity Checker helps you tell the difference.

Showing a diff in Integrity Checker
Integrity Checker highlights the actual row that is different between the local version and the original version.

File Permissions

Another important aspect of WordPress security is keeping an eye on the permissions for all files and folders. WordPress.org has a very clear recommendation on what they should be and it’s easy enough to change. The only problem is that it’s quite difficult to determine what they actually are without using an external ftp or sftp client. Integrity Checker can scan all files and folder in your installation and report if any issues are found.

Permission issues
Integrity Checker reports about permission issues found in a WordPress installation.

Settings and related issues

The last tool in Integrity Checker is checking up on common problems caused by configuration and settings. While WordPress is mostly secure from out of the box, there are multiple things that we as users can get wrong and that compromises the overall security. This includes problems with:

  • Bad or weak database credentials (database)
  • Bad or non existing keys and salts (wp-config.php)
  • Lack of SSL security to protect the admin area (webserver)
  • Directory indexing allowed (webserver)
  • Old versions of core, plugins or themes (user related)
  • User enumeration (WordPress weakness)

By checking up on these common issues, Integrity Checker helps you highlight issues that you might have just forgotten or even didn’t know about.

Free for all, but with opportunity to contribute

Integrity Checker uses our powerful back end API to do a lot of its work. While we’d like to be all generous and give this away for free, we’d also like to find a compromise that works for as many users as possible and at the same time allows us to focus our time to maintain and enhance our products.

We’ve settled on a business model where small sites with a casual usage of either Integrity Checker or wp-checksum (the cli version) can use the back end api for free. When usage is scaled up with more frequent checks of more and larger sites, there is a cost associated with using the api.

As an anonymous user, you can query our API 25 times per hour(subject to change). We think (but would love your input) that this is sufficient for most small and medium sized WordPress installations with 20-25 plugins and a theme. There are some caching going on in the background, so repeated scans doesn’t always result in more queries to us. We create an anonymous user in our database and assign an API key to that user, that API key is sent back to your WordPress installation and stored in your database. You can see your API key in the About section in Integrity Checker as well as your current API usage.

If you are willing to share your email address with us, we increase that hourly quota up to 75 requests per hour(subject to change).

The API key’s can be reused between sites, so once you have registered with us, you can use that key on more than one site.

If you need more than 75 requests per hour assigned to one API key, you can purchase a premium subscription from this site

 

At last

We’re quite proud of this new offering and we’re hoping that other members of the WordPresser community agrees with us. Do you have a question or comment about Integrity Checker or wp-checksum, please let us know in the comment section below or on Twitter.

 

WP Bootstrap 0.4.0, now a wp-cli sub command

Dr Martens - spring edition

 

So, as this post is written, the test suite for WP Bootstrap 0.4.0 all turned green and a new version is about to get tagged and available via composer. This release is a big one. If you’re the least bit interested in managing WordPress in a proper deployment workflow, I think you should continue reading.

Selection_466

Tighter wp-cli integration

This is the first release of WP Bootstrap that is entirely intended to be used as a wp-cli sub command. That means that instead of using WP Bootstrap as a stand alone command (or via composer scripts), all WP Bootstrap actions are now sub commands of wp-cli. Where we’d previously would have typed:

$ composer wp-setup

We’ll now be typing

$ wp bootstrap setup

That might seem as a very small change and on the surface I admit it is. But underneath the hood it has meant a lot of changes like replacing almost all external calls to wp-cli via exec() to using the internal wp-cli methods. Since wp-cli comes with functions for logging, output formatting and most importantly, internal functions for running other wp-cli commands, a lot of code has been cleaned up and Monolog  as well as Phpleague CLImate was replaced with corresponding wp-cli functionality. Last but not least, WP Bootstrap now uses Pimple for dependency management because it’s one of the few with the same PHP version requirements as wp-cli itself.

Settings files with dotenv and Yaml

Previous versions of WP Bootstrap has used json files for both application and local settings. Since json is not really that suitable for configuration files they are now gone.

Environment specific settings was previously kept in localsettings.json but are now replaced with dotenv files. Most DevOps engineers are familiar with dotenv files and several provisioning and deployment systems has support for working with them. So one of the benefits of switching formats is that more engineers will recognize them. WP Bootstraps uses Vance Lucas implementation of dotenv which enables a very elegant way of overloading values from several dotenv files. By defining that we’re working in environment ‘test’, we can have WP Bootstrap first load values from the base .env file and if it exists, overlay with values picked up from .env-test.

A bigger change is that appsettings.json is now replace with appsettings.yml. The format is pretty much still the same and converting an old appsettings.json can be done in seconds using a service like JSON to YAML Online. The main benefit of switching to Yaml is that Yaml allows comments. For a configuration file that keeps on growing this is surprisingly important. Just like dotenv, Yaml files are already quite popular among a lot of DevOps engineers, probably because Ansible uses them. And the fact that wp-cli itself relies on Yaml made the decision quite easy.

Feature upgrades

There are a few new features, some of them technically saw the light of day earlier than 0.4.0 but haven’t been previously announced (besides in the change log):

Extensions

Yes, WP Bootstrap now supports having extensions that can react to actions and filters. An extension is just a PHP class that implements the method ‘init’. In the init-method the extension can hook up to a few filters and actions. The PHP class can be loaded using Composer auto loading or it can exist as part of a theme or plugin. WP Bootstrap just needs to know the name of the class and you just need to make sure it implements the init-method.

The use case for this is to provide a way to perform extra processing during export and import. For instance, we’ve written a WooCommerce extension that handles import and export of the custom database tables that WooCommerces adds to a WordPress install. I expect to find the time to write blog posts on this topic really soon because it opens up a whole lot of new use cases for WP Bootstrap.

Plugin dependencies

Another important new feature is the ability to define dependencies between plugins and themes. Some plugins (mostly) simply will not install correctly or at all unless some other plugin or theme is already in place. To mitigate this, WP Bootstrap now allows you to define which other themes or plugins that needs to exist before this one gets installed.

Performance

When importing lots of media files, WP Bootstrap would always regenerate all thumbnails. When dealing with hundreds or even thousands of images, this becomes very time consuming. WP Bootstrap now checks if an updated image was actually changed before generating the thumbnails again. In a similar way, in the setup phase, WP Bootstrap would try to reinstall plugins even if they were already installed. While wp-cli would refuse to do the actual work, the plugin file would be downloaded from the repo on every attempt which costs a lot of time.

Removed features

Since WP Bootstrap is now just a wp-cli command, there’s no real need for keeping the upgrade commands for themes and plugins anymore. For command line management of plugin versions, you are better of using the standard wp-cli commands instead.

Test coverage

Refactoring tests and using with WP_Mock

Code quality is still one of the most important aspects of WP Bootstrap development, so a lot of time was spent on refactoring code and making sure code coverage remains high. Tests are now divided into unit tests and functional tests. Unit tests uses WP_Mock and manages to get up to about 50% code coverage without even needing a proper WordPress installation or a database. It should be possible to reach near 100% coverage for the unit tests, but we’re not quite there yet.

The other half of testing is made using functional tests. The functional tests requires a WordPress installation to work. Generally, the functional tests are easier to write but they are also much slower to run. Some tests are also impossible to get code coverage measurements from. As of the 0.4.0 release, functional tests covers roughly 66% of the code base but the overlap with the unit tests are quite high. Together unit tests and functional tests covers about 82%. That’s actually down a little bit compared to version 0.3.0 and that’s obviously an area to focus on going forward.

 

All test cases are still kept in a separate github repo just for testing. If you want to contribute to WP Bootstrap, this is where I recommend you start looking. Any contributions to WP Bootstrap are more than welcome, you can just send a pull request or better, shoot me an email first at: erik@wpessentials.io

 

Tutorial: Managing a WordPress installation in Git using WP Bootstrap

Multiple copies

In the previous tutorial, we covered how to set up a simple WordPress site using WP Bootstrap, essentially preparing the site for git and git based deployments. In this tutorial we’re taking the next step. We’re going to add all the needed files to a Git repository and after that we’re going to deploy the code into a production environment.

Update 2016-01-11: After this post was first published, I’ve published wp-deployhelper, a tool intended to speed up deployments to shared hosts. If you’re interested in fast shared host deployments I strongly suggest you have a look at wp-deployhelper.

We’ll look at how we can deploy changes to the production environment regardless if you have ssh access with composer and wp-cli available, or if you’re working with a standard shared host using ftp access. Full ssh access to production is going to be better 999 out of 1000 times. But many WordPress developers have little or no influence over where their customers sites are hosted and we want to document a solid work flow even for this (very common) scenario.

The deployment technique outlined here is based on the very most basic git usage with a manual pull in the target environment. There are other more sophisticated ways like Capistrano or Rocketeer to get the job done and those will be covered at another time, in this tutorial focus is on the basics.

Overview

The steps covered in this tutorial are:

  • Initiating a local git repository and adding files to a Github repository
  • Checking out the project files on the production environment and set up the site for the first time
  • Making changes in the development environment and deploying them to production

 

Step 1: Initiating a local git repository and adding files

This step assumes that you have already created a repository on Github. We’re using a repository named “tutorial-simplesite1” for this part. Note that some of the commands below contains both the Github username and repository names, make sure you modify these if you copy/paste directly from this tutorial. You also need to have git installed and setup properly, it’s included by default inside the Vagrant environment we’re using. But apart from installing it, you will also need to set up name and email address and perhaps add an ssh key. Please refer to the help pages on Github on how to get started with Git and how to set up keys.

Make sure you the Vagrant machine is running (vagrant up) and that you are in a shell inside the machine (vagrant ssh) in the path where the development environment is ($ cd /vagrrant).

First, we’ll create a local git repository directly in the development environment;

$ git init

Create a .gitignore with the following

localsettings.json
.vagrant/
staging/
www/
vendor/
wp-cli.yml
composer.lock

Add the config files

$ git add appsettings.json composer.json .gitignore

Add vagrant files

$ git add Vagrantfile vagrant/

Add content and local files

$ git add bootstrap/ wp-content/

Then commit the files

$ git commit -m "initial import"

Set up the connection with Github and push, note that this assumes you are using Github with the same repository name as in this tutorial. Replace hostname, username and repository name to suit your conditions.

$ git remote add origin git@github.com:yourusername/tutorial-simplesite1.git
$ git push -u origin master

 

 

Step 3: Checking out the files on the production server

Note: In your production environment, I strongly discourage keeping the project files directly in the web root folder. In most hosting scenarios, you can keep the project files in a folder that’s not directly accessible via the web. If you have no choice, you must remove all sensitive information from localsettings.json once WordPress has installed for the first time.

Scenario 1. A server you can access via ssh with wp-cli and composer are installed.

In this scenario, we’re assuming that you are are working in your users home directory and that the web server is configured to use /var/www/tutorial-simplesite1. We’re also assuming that you have created a database and have the user name and password available.

Log in to the server and navigate to the folder where you want to keep your local copy of the code. Note that during checkout, a sub folder will be created, so run this command from one level above. Here we’ll create a sub folder projects under the users home directory:

$ cd /home/user/
$ mkdir projects
$ cd projects
$ git clone git@github.com:yourusername/tutorial-simplesite1.git

Then install WP Bootstrap via composer

$ composer update

…and initialize WP Bootstrap for access via Composer scripts:

$ vendor/bin/wpbootstrap wp-init-composer

Next, generate a localsettings file:

$ composer wp-init

Edit the contents of localsettings.json to suit your server:

{
    "environment": "production",
    "url": "www.example.com",
    "dbhost": "localhost",
    "dbname": "wordpress",
    "dbuser": "wordpress",
    "dbpass": "database_password",
    "wpuser": "admin",
    "wppass": "strong_and_long_pass_1234!",
    "wppath": "/var/www/tutorial-simplesite1"
}

Install WordPress, set up plugins and themes and import the content

$ composer wp-install
$ composer wp-setup
$ composer wp-import

That’s all for this phase.

 

Scenario 2. Standard shared hosting with only ftp access

In this scenario, we’re assuming that the production server is perfectly normal shared host. The steps in this section are tested against a simple $3.95/month account on Bluehost but the steps should be easy to reproduce on most shared hosts. To follow these steps you need to have ftp username/password as well as the database credentials, host, database name, username and password.

The next perquisite for this scenario to work is that your shared host allow remote access to the MySQL server. Some hosts have no restrictions for this at all, while Bluehost and many other hosts allow you to open access to the MySQL server for a specific IP address. Bluehost outlines the steps needed here: Remote Database Connection Setup. If you’re on a different host you can probably find help via their support pages.

Using Git to deploy your site to a shared host is based on the following idea:

  • We will use a local vagrant machine to check out the code, just as the first steps above
  • When creating the localsettings.json file, we will use the credentials for the production database on the shared host
  • Then we run the WP Bootstrap scripts to install, setup and import
  • At last, we will transfer the file tree to the shared host using ftp

If you are using the Vagrant skeleton that was suggested in the previous tutorial, you should already have a staging environment in your local vagrant machine that we will use.

First make sure your vagrant machine is up and running (vagrant up) and that you have ssh’ed into it (vagrant ssh). Then at the command line in the vagrant box,

$ cd /srv/staging

The nginx default setting in the Vagrant box is that the staging WordPress installation should be at /srv/staging/wordpress, so create that folder:

$ mkdir /srv/staging/wordpress

Then clone the code

$ git clone git@github.com:yourusername/tutorial-simplesite1.git

Then install WP Bootstrap via composer

$ composer update

…and initialize WP Bootstrap for access via Composer scripts:

$ vendor/bin/wpbootstrap wp-init-composer

Next, generate a localsettings file:

$ composer wp-init

Edit the contents of localsettings to suit the your domain name database credentials for your shared host. Note that we’re still pointing at a local folder for the installation. That’s because we’re setting everything up there first.

{
    "environment": "production",
    "url": "www.yourdomainname.com",
    "dbhost": "box000.bluehost.com",
    "dbname": "your_database_name",
    "dbuser": "your_database_user",
    "dbpass": "secret_password",
    "wpuser": "admin",
    "wppass": "password",
    "wppath": "/srv/staging/wordpress"
}

Install WordPress, set up plugins and themes and import the content

$ composer wp-install
$ composer wp-setup
$ composer wp-import

After this, you should be able to see your site via the local URL to the staging server, but it will be slow and look terrible. The reasons for that is that (1) it’s using the database on your shared host which will be a lot slower that a local and (2) all internal links, including those for css and image files are now pointing to the production URL. We will not adress those issues right now, instead we’re going to do the very last step, to transfer the files to the shared host.

The bulk of the work will be done using a tool named sitecopy. It’s been around for a long time and it’s sole purpose is to ensure that a remote version of a site is identical to a local version via FTP. It’s a good fit four our needs. First we need to install sitecopy.

$ sudo apt-get install sitecopy

Next, we’ll create a folder where it keeps its state and the file that controls the behaviour of sitecopy:

$ mkdir ~/.sitecopy
$ chmod 0700 ~/.sitecopy
$ touc ~/.sitecopyrc
$ chmod 0600 ~/.sitecopyrc
$ nano ~/.sitecopyrc

And add the following

site remote
    server ftp.yourdomain.com
    remote /public_html
    local /srv/staging/wordpress
    username yourusername
    password "secret_pass"
    symlinks follow

Exit save the file using Ctrl+o and then exit using Ctrl+x.
Then we initiate sitecopy and run the first update

$ sitecopy remote --init
$ sitecopy remote --update

Sadly, since we’re dealing with ftp this step is going to take some time, expect 15-30 minutes even for a small WordPress site. But the advantage of using sitecopy is that it’s fairly quick on subsequent updates, at least compared to other ftp tools. If you run the update again, the process should finish in just a few seconds.

Additional notes
On some hosts, Bluehost is one, the database host name in wp-config.php must be ‘localhost’ in order for the site to function properly. But in our WordPress staging installation we have set the host name to ‘box000.bluehost.com’. The best workaround for this is to go in via a standard ftp client and edit the file directly on the server. Then, in order to avoid that this file gets overwritten at future deploys, we exclude it from the scope using a directive called “exclude” in the .sitecopyrc file:

site remote
    server ftp.yourdomain.com
    remote /public_html
    local /srv/staging/wordpress
    username yourusername
    password "secret_pass"
    symlinks follow
    exclude wp-config.php

Scenario 2 summary

As we’ve seen, there is a straight forward way to maintain a WordPress site using proper git version control even if we have to deploy the site to a very simple shared host.

But this approach has a few downsides. Performance is one, even a simple WordPress site can take very long for the first deploy to finish. But even subsequent deploys can be challenging since the database might be updated minutes before all new files have been copied to the server.

Another downside is that this is far from as robust as a normal deploy with git and composer directly on the server. For instance, changes to files in core or in plugins that happen on the server are not automatically detected. So sitecopy might think that everything is in sync between staging and production even if there are major differences. Updating plugins and core on the production server is simply not recommended when using this approach. If that happens and the file trees come out of sync, you need to either manually edit the state that sitecopy maintains in ~/.sitecopy/remote (an xml file) or run the command sitecopy remote –fetch to get the current state from the server.

Alternate approaches

There are a few alternative approaches to keep two file trees in sync via ftp. One is anohter command line tool called lftp that has a pretty powerful feature to mirror two trees, if for some reason sitecopy does not work out for you, lftp might be an alternative.

However, the biggest downside with using ftp for keeping two file trees in sync is that ftp is very slow when it has to deal with large amounts of files and folders. Not because of the connection speed, but because there will be a huge amount of individual ftp requests and each request has a little bit of overhead time.

Some hosts, including Bluehost, offer a limited ssh access to the server, enough to run another file synchronization tool called rsync. Bluehost has an option where you can verify your account with their verification department and after that you can get limited ssh access to your hosting server. I will describe how to set up a rsync based deployment in a later post or tutorial, for now you should at least examine the options on your host. Here’s an article that explains how to get ssh access on Bluehost.

Step 4: Creating changes

Before heading on to the final step in this tutorial, we’re going to make a few changes in development so that we have something to deploy. We’ll make the following changes in the development environment:

  • Modify code in the child themes functions.php
  • Modify the title on the welcome page to say “Welcome (git deploy)”

By making these two simple changes, we’ll cover deployment of changed code, normally pretty easy to transfer. But we’re also covering a change that took place in the database, which often is a little bit harder.

First, make sure your vagrant box is still running and use your browser to surf to the development version of your site http://www.casestudy1.local/wp-admin. Log in to the admin area and make the modification to the welcome page. Change the title and feel free to do some changes in the content we created with Page builder. Save the page when your’re done.

Next we’ll make a little change in the child theme. Edit the file [project_folder]/wp-content/themes/vantage-child/functions.php and add the following code under the existing code:

add_filter( 'the_title', 'vantage_child_the_title',10, 2);

function vantage_child_the_title($title, $id = null)
{
    return $title . " [I'm added via code]";
}

Save the file and go have a look at http://www.casestudy1.local/, you should see that the title has changed, both the changed you did in the page editor as well as the text [I’m added via code]”. Once you have confirmed this, let’s bring up the terminal. Make sure to ssh into the Vagrant machine (vagrant ssh) and go to the correct folder:

$ cd /vagrant

Then we’re going to create a new export so that our database changes are stored in files in the bootstrap folder:

$ composer wp-export

Next, we’ll use git to find out what’s changed (output shortened):

$ git status
Changes not staged for commit:
	modified:   bootstrap/config/wpbootstrap.json
	modified:   bootstrap/manifest.json
	modified:   bootstrap/media/camera-1080/meta
	modified:   bootstrap/posts/attachment/camera-1080
	modified:   bootstrap/posts/ml-slider/new-slider
	modified:   bootstrap/posts/page/welcome
	modified:   bootstrap/taxonomies/ml-slider_manifest.json
	modified:   wp-content/themes/vantage-child/functions.php

WP Bootstrap regenerates all files in the bootstrap folder at wp-export, and if the internal ID’s changed during the last import process, chances are that there are small modifications in many files. We see our modified functions.php as well as the welcome page in the list of modified files, so it seems reasonable. We’ll commit these files and push them to the remote repository.

$ git add bootstrap/ wp-content/
$ git commit -m "A few changes"
$ git push

And that’s all for this part, all our changes are now stored safely in Git.

 

Step 5: Deploying the changes to production

So, in the last step in this tutorial we’re going to deploy these changes into production.

Scenario 1. A server you can access via ssh with wp-cli and composer are installed.

Log in to the server with ssh and navigate to the folder where you want to keep your local copy of the code (the folder where localsettings.json is located). Then do a git pull go get all the changes:

$ git pull

Then, apply any changes in themes or plugins (none in our case) and finally import the modified content

$ composer wp-setup
$ composer wp-import

And that’s actually it. You might want to create a small bash script to run both commands at once, or you might prefer to run them separately as we did above. In this case, we could have just run the wp-import command since we didn’t add any new plugins, but I’ve taken it as a habit to always run them both.

 

Scenario 2. Standard shared hosting with only ftp access

In this scenario, we’ll do pretty much the same things as above, but we’re going to run it from within our staging environment. Make sure you’re inside your vagrant box and navigate to staging:

$ cd /srv/staging/tutorial-simplesite1

Get the latest version of the code:

$ git pull

And then run the commands to apply changes;

$ composer wp-setup
$ composer wp-import

Now, all the database changes are in place on the production server, we need to push over the modified files as well. First, let’s look at what sitecopy want to transfer:

$ sitecopy remote --flatlist
sitestart|remote
sectstart|changed
item|wp-content/config/wpbootstrap.json
item|wp-content/uploads/2015/12/camera-1080-1080x380.jpg
item|wp-content/uploads/2015/12/camera-1080-720x380.jpg
item|wp-content/uploads/2015/12/camera-1080-768x512.jpg
item|wp-content/uploads/2015/12/camera-1080-150x150.jpg
item|wp-content/uploads/2015/12/camera-1080-960x480.jpg
item|wp-content/uploads/2015/12/camera-1080-1024x683.jpg
item|wp-content/uploads/2015/12/camera-1080.jpg
item|wp-content/uploads/2015/12/camera-1080-272x182.jpg
item|wp-content/uploads/2015/12/camera-1080-436x272.jpg
item|wp-content/uploads/2015/12/camera-1080-300x200.jpg
item|wp-content/themes/vantage-child/functions.php
sectend|changed
siteend|changed

Besides the functions.php file we know we changed, we’ll also see a bunch of other files that sitecopy think have changed. This is because how the import process works where several files get touched even if they didn’t in fact change. It’s a fairly small extra overhead, so we’ll get going with the final step:

$ sitecopy remote --update

 

Some more comments on the ftp/sitecopy approach

When writing this tutorial, the update of the above files took a total of 10 seconds. Most of that time was spent on transferering files that hadn’t actually changed. This means that the time between the database has been updated and all the files are in place was 10 seconds. During this time, there’s a fair chance that your site is in an “undefined” state, so we want to do what we can to fix this. Sitecopy offers a way to use checksums rather than the file modification date as detection method. That creates a little bit of overhead before the transfers can start, but it’s often worth it. If you have a lot of media files that is managed using WP Bootstrap, i suggest you add “state checksum” to the .sitecopyrc file:

site remote
    server ftp.yourdomain.com
    remote /public_html
    local /srv/staging/wordpress
    username yourusername
    password "secret_pass"
    symlinks follow
    exclude wp-config.php
    state checksum

Final thoughts

Combining Git with a “content aware” tool like WP Bootstrap is a fairly powerful combination. By defining precisely what parts of WordPress we need to manage, we can leave all the other stuff untouched. Updating the menu structure never conflicts with existing posts, comments or other content on the production site. So developers can take care of code and certain parts of the site, while writers and editors can manage the content that is just pure content.

Ideas? Questions? Feeling angry or happy? Please share your thoughts in the comment section below.

WP Bootstrap 0.3.1 released

Lots of spare time over the holidays means a lot of work can go into WP Bootstrap. Version 0.3.1 brings a few bug fixes and small but nice new feature

Version 0.3.0 had support for working with taxonomy terms that are named after a post id. That was a nice feature, but it turns out that the import process had to run twice for the import to work properly due to a PHP type conversion problem. The export of special taxonomies was enhanced with a WARNING message in the logs if the configuration isn’t correct.

The new feature is wp-cli related. Runnit the wp-init command generates localsettings and appsettings unless they already exist. In 0.3.1, it also creates a wp-cli.yml file that defines the path to the WordPress installation. The condition is that localsettings.json exists and that the wppath parameter in it is different from the default “[wppath]” value. So run wp-init once to get a template localsettings file and edit it. Run wp-init again to get a wp-cli.ym file.

The benefit of defining the path to WordPress in a .yml file is to reduce typing when running commands.

 

Tutorial: Preparing a WordPress site for Git using WP Bootstrap

There are a lot of tutorials around about how to use Git to manage WordPress installations. While they are almost all very good, many of these tutorials encourage a work flow that works great for code but less than great, or not at all, for WordPress content. While most content in a WordPress site is just posts, comments and images some of the content is actually more important. Besides code, your WordPress site is also made up of menus, pages, widgets and options to work and look as you designed it, and in WordPress, most of that is also content. So we need an improved way of managing “application content” as opposed to “content content” to be able to maintain a good development work flow with Git.

In this tutorial, we’re going to go through all steps needed to setup a simple WordPress one-page site using WP Bootstrap as the main tool for migrating content. Since the site is created using WP Bootstrap, it’s also extremely easy to manage under Git source code control and to migrate it to a production environment. This text assumes that you have a basic understanding about Vagrant and some experience from a Linux command line will not hurt either. This text also assumes that you’re working on a Mac on Linux computer rather than Windows. Most commands will work the same on Windows, but please note that the author hasn’t tested.

Overview

We’re going to cover a few different areas.

  • First we’re going to create a Vagrant machine that we use as the development environment.
  • In the Vagrant machine, we’ll work with wp-cli, composer and WP Bootstrap which are our main tools to build up the site.
  • We will walk through how to modify appsettings.json, the main WP Bootstrap configuration file, to include just the parts of the content we want to manage using WP Bootstrap and show how export that content.
  • At last, we’ll re-import this content to an empty WordPress installation to verify that the process works as intended.

As the end result, we’re going to have a Git manageable WordPress site that takes content into account.

Step 1: Creating the Vagrant machine

Note: This guide does not aim to specifically teach anything about setting up and using Vagrant. If you want to read up on the basics of developing WordPress sites on top of Vagrant, please read this post. By the way, the rest of this text assumes that you have the vagrant plugin vagrant-hostupdater installed, as described in the linked post.

The first thing we’re going to do is to download a suitable Vagrant skeleton configuration. We’re going to use a derivative of Varying Vagrant Vagrants (vvv) with a little simplified setup that I’ve made available on Github. Open a terminal window and navigate to the folder where you keep your source code, the actual project folder will be created as part of this step, so don’t create that manually.

Get the zip, unzip it and rename the

$ wget https://github.com/eriktorsner/vagrant-wpskeleton/archive/master.zip
$ unzip master.zip
$ mv vagrant-wpskeleton-master/ casestudy1
$ rm -rf master.zip
$ cd casestudy1/

Navigate into the newly created folder casestudy1 and open the file Vagrantfile in your favorite text editor, you need to modify the four parameters in that file to suit this project (note that you might need to use a different IP depending on your Vagrant network settings):

 
# -*- mode: ruby -*-
# vi: set ft=ruby :

HOSTNAME = 'case1'
IPNUMBER = '192.168.50.38'
DEVDNS   = 'www.casestudy1.local'
TESTDNS  = 'test.casestudy1.local'

dir = Dir.pwd
require dir + '/vagrant/Vagrant'

Save the file and go back to the command line to type

$ vagrant up

This command might take a little while, up to 10 minutes is normal. First it will download the correct Ubuntu 14.04 LTS image and then it installs wp-cli, composer and some other tools. Once it’s finished, you can enter your newly created Vagrant machine:

$ vagrant ssh

 

Step 2: Install and configure WP Bootstrap

Note: From now on, unless stated otherwise, all bash commands shown should be executed from the /vagrant sub folder inside the virtual machine.

Once your inside the virtual machine, navigate to the /vagrant sub folder, install and initiate WP Bootstrap:

$ cd /vagrant
$ composer require eriktorsner/wp-bootstrap
$ vendor/bin/wpbootstrap wp-init-composer
$ composer wp-init

Note: The /vagrant sub folder inside the virtual machine is shared with the project folder on your normal hard drive, so you can edit files using your favorite text editor or IDE. This is one of the main advantages of using a Vagrant machine as development environment, you’ll use your standard set of tools to work with the code, but then the code runs inside a separate environment where you can install project specific things such as WP Bootstrap.

The last command above, wp-init, is a convenient command that creates template files for localsettings.json and appsettings.json. Those two files controls most of WP Bootstraps behavior so it’s nice get templates added. The file localsettings.json is used to keep settings that is specific to this machine, you’ll create a unique localsettings file for each different environment and you typically don’t want to maintain it in git. We need to edit localsettings.json to suit this machine and since we are using a standard Vagrant image we just use the mysql database created by default during the Vagrant provisioning. Edit localsettings.json:

{
	"environment": "development",
	"url": "www.casestudy1.local",
	"dbhost": "localhost",
	"dbname": "wordpress",
	"dbuser": "wordpress",
	"dbpass": "wordpress",
	"wpuser": "admin",
	"wppass": "admin",
	"wppath": "/vagrant/www/wordpress-default"
}

and appsettings.json to this:

{
	"title": "Case study 1"
}

Then we can get a very basic WordPress install up and running with a few commands:

$ composer wp-install
$ composer wp-setup

 

After a few minutes, you should be able to log in to your WordPress site using the url: http://www.casestudy1.local/wp-admin and login with username: admin and password: admin (don’t worry, your live site will not use these credentials, they are only used in development).

As a last preparation before moving on, we’re going to create a snapshot of what the WordPress options looks like right now for future reference using wp-cli. So before running the command, we’ll create a wp-cli settings file to reduce typing:

$ echo "path: /vagrant/www/wordpress-default" > wp-cli.yml
$ wp option list > opt.initial.snapshot

 

Step 3: Add plugins and a theme

This test site is going to use a free theme from the WordPress repository as well as a few free plugins. We’ll add them by editing appsettings.json and run the wp-setup command again. Open appsettings.json and change it to:

{
    "title": "Casestudy1",
    "themes": {
        "standard": ["vantage"],
        "local": ["vantage-child"],
        "active": "vantage-child"
    },
    "plugins": {
        "standard": [
            "ml-slider", "siteorigin-panels", "so-widgets-bundle",
            "wp-cfm"
        ]
    }
}

What does these things mean? Well, this json file contains different sections describing various aspects of the WordPress installation we’re creating:

  • title: This was added earlier and is simply the title for the WordPress site. This is the only mandatory property of appsettings.json since WordPress needs have a title to install and initialize. The other properties that are strictly needed, such as website url and admin username are defined in localsettings.json.
  • themes: this property is a json object with a few subproperties
    • standard: this is a list (array) of plugin slugs that will be installed from the WordPress standard theme repository. If you need, you can also specify a specific version using a colon, like this “vantate:1.0.2”
    • local: this is a list of themes that exist locally under “wp-content/themes” in your project folder. This is suitable if you’re using a premium theme that can’t be downloaded from the WordPress repo or as we’re going to do, use a local child-theme. The folder name needs to match the string supplied here, so for the above configuration, WP Bootstrap expects to find a folder named /path/to/your/project/wp-content/themes/vantage-child. Note that the folder will be sym-linked to the wp-content/themes folder in the actual WordPress installation (specified in localsettings.json).
    • active: a string that specifies the theme that should be activated, in this case, the child theme
  • plugins: This structure is very similar to the themes structure, but there isn’t any “active” property, all plugins are activated after install
    • standard: this is a list (array) of plugin slugs that will be installed from the WordPress standard plugin repository. If you need, you can also specify a version using a colon, like this “wp-cfm:1.0.2”. A URL to a zip file is also acceptable, this can be useful if you want to install a plugin directly from a git repo for instance
    • local: this is a list of plugins that exist locally under “wp-content/plugins” in your project folder. This is suitable if you’re using a premium plugin or plugins that you develop specifically for this particular site and that will be kept in git.

Before we can apply these settings to our WordPress installation, we need to create the child theme folder and place a minimal child theme in there.

$ mkdir -p wp-content/themes/vantage-child
$ touch wp-content/themes/vantage-child/style.css
$ touch wp-content/themes/vantage-child/functions.php

 

Open wp-content/themes/vantage-child/style.css in your favorite text editor and add the following content:

/*
 Theme Name:   Vantage-child
 Template:     vantage
*/

 

…and open wp-content/themes/vantage-child/functions.php and add the following:

<?php

add_action('wp_enqueue_scripts', 'theme_enqueue_styles');

function theme_enqueue_styles()
{
    wp_enqueue_style('parent-style', get_template_directory_uri().'/style.css');
    wp_enqueue_style('child-style', get_stylesheet_directory_uri().'/style.css', array('parent-style'));
}

 

Once both files are saved, we can go ahead and apply the changes using the command:

$ composer wp-setup

The first time this command runs, there’s not much output at all but it might take a minute or two depending on your Internet download speed. Once done, you can surf to http://www.casestudy1.local/ and you’ll see the Vantage theme default screen:

 

Vantage default look

Log in to the WordPress admin area and go to the plugins section, you should see that the plugins we specified in appsettings.json are all installed and activated:

List of plugins

 

At this point, we have created a WordPress site with the theme and plugins of our liking simply by creating a couple of configuration files,

  • composer.json used for installation of WP Bootstrap
  • localsettings.json that configures some server specific things like passwords and paths
  • appsettings.json than configures themes and plugins we want to use, both from the repo and local to our hard drive

So what we have done so far is to create a text file based configuration for installing WordPress and a couple of plugins, just in a format well suited for managing in Git.

Step 4: Creating content

For this step, we’re going to work mostly inside the WordPress admin area. We’re going to create a front page slider with the Meta Slider plugin and then set up a welcome page that uses that slider and some additional content.

Create the slider

Go to the Meta Slider settings and create a new slider and add a single image slide to it. The on screen instructions should be easy to follow, set the name “welcome” to the slider and set a caption for the image.

Meta slider

Create the Welcome page

Next, to go Pages->Add new to create a page. Give it the title “Welcome”.

Set a title

Select the Full Width Page template in the meta box on the right hand side. The theme we’ve selected has an option to select a Meta Slider as a page option and in that drop down, you should see the welcome-slider that we’ve just created. Then hit publish to save the page for the first time.

Selection_358

The next step is to add some content using Page builder. Add a row with 3 columns and add a text widget to each of them. Place some dummy text in them and Update the page. The Page Builder view on the edit page should look something like this:

Page builder

Next, we’ll head to Settings -> Reading in the WordPress admin area to make our new page the front page of the site:

Settings -> Reading

Click Save changes and then head to Appearance -> Theme Settings. Note that this is a menu option that is specific for this theme, so don’t expect to see this if you’re testing this with a different theme. We want to remove the default “Header text” and menus:

Vantage Theme Settings

Vantage Theme settings pt2

Scroll down to the settings page and click Save Settings. We can now have a look at the test website, it should look something like this:

Case study test site

 

Step 5: Exporting content

We’ve now got a reasonably standard WordPress site with some added content and modified settings. Our next task is to make some additions to appsettings.json so that it can export all the content we’re interested in. Options that we’ve changed in the WordPress admin area will be stored to disk by setting up the WP-CFM plugin and we’re also going to add two new sections to appsettings.json:

  • content: The content section lists post types and individual posts that we want to include in the export. We’ll also be listing some taxonomies.
  • references: The references section is when the content is imported back into a WordPress site. In various places in the content, there are data items that refer to posts or taxonomy terms by the internal ID. If we can successfully tell WP Bootstrap which settings to treat as references, the import process will be able to restore those references during import.

But lets start with WP-CFM. Go to Settings -> WP-CFM in the WordPress admin area and click Add Bundle.  Name the bundle wpbootstrap and click the Save button. You should now see a lot of unchecked boxes, each box representing an option that is stored in the wp_options table:

WP-CFM settings

Identifying exactly which options to include is a separate, and quite big, topic, for now, we’re just going to add the options that matters (the most) in this specific installation. Most options in the wp_options table just get a default value and in most cases, it’s perfectly OK to let the target WordPress installation (where we’lll eventually import these settings) to set it’s own default values. For this tutorial, we’re going to be as lean as possible and only include values that we really need, namely these three:

  • vantage_theme_settings All theme options that we edited in step 4 above are stored in this single option.
  • show_on_front This is the WordPress option that determines if the first page is a static page or a list of recent blog posts, we’ve changed this option so we need to include it.
  • page_on_front WordPress keeps track of the post ID of the page that is set as our front page, we’ve set the “Welcome” page as our front page, so this setting needs to be exported

 

Find and mark each of these options in the WP-CFM settings page and click save.

The next thing we’ll do is add what posts to include in the export. For this, we’ll edit appsettings.json directly. To figure out what pages (and post types) to include, we’re going to use wp-cli to display what our installation has. First of all, we want to include the welcome page. We could just be lazy and include all pages, or we can be explicit and only include the page we know we want. First, list all pages using wp-cli at the Vagrant command line:

$ wp post list --post_type=page
+----+-------------+-------------+---------------------+-------------+
| ID | post_title  | post_name   | post_date           | post_status |
+----+-------------+-------------+---------------------+-------------+
| 6  | Welcome     | welcome     | 2015-12-29 17:24:30 | publish     |
| 2  | Sample Page | sample-page | 2015-12-27 22:25:16 | publish     |
+----+-------------+-------------+---------------------+-------------+

We’re going to be explicit and only include the page we’ve worked with, so the resulting appsettings.json becomes:

{
    "title": "Casestudy 1",
    "themes": {
        "standard": ["vantage"],
        "local": ["vantage-child"],
        "active": "vantage-child"
    },
    "plugins": {
        "standard": [
            "ml-slider", "siteorigin-panels", "so-widgets-bundle",
            "wp-cfm"
        ]
    },
    "content": {
        "posts": {
            "page": ["welcome"]
        }
    }
}

For reference, if we had wanted to include all pages, we could have used:

// lazy: include all posts with post-type = page
"posts": {
    "page": "*"
}

 

The plugin Meta Slider stores it’s sliders as posts with custom post type ml-slider. To figure this out, we can see what post types this installation has:

$ wp post-type list
+---------------+-----------------------+-------------+--------------+--------+-----------------+
| name          | label                 | description | hierarchical | public | capability_type |
+---------------+-----------------------+-------------+--------------+--------+-----------------+
| post          | Posts                 |             |              | 1      | post            |
| page          | Pages                 |             | 1            | 1      | page            |
| attachment    | Media                 |             |              | 1      | post            |
| revision      | Revisions             |             |              |        | post            |
| nav_menu_item | Navigation Menu Items |             |              |        | post            |
| ml-slider     | Meta Slider           |             |              | 1      | post            |
+---------------+-----------------------+-------------+--------------+--------+-----------------+

 

If you know your way around WordPress, you should quickly see that the type ml-slider is non standard. Let’s see what posts we have with that type:

$ wp post list --post_type=ml-slider
+----+------------+------------+---------------------+-------------+
| ID | post_title | post_name  | post_date           | post_status |
+----+------------+------------+---------------------+-------------+
| 4  | welcome    | new-slider | 2015-12-29 17:14:12 | publish     |
+----+------------+------------+---------------------+-------------+

The only post with type ml-slider has title welcome and post_name=new_slider and this matches with how we named the slider we created in step 4. When we define what posts to include in an export, we want to use the post_name as the identifier, to adding the slider to the exported content:

{
    "title": "Casestudy 1",
    "themes": {
        "standard": ["vantage"],
        "local": ["vantage-child"],
        "active": "vantage-child"
    },
    "plugins": {
        "standard": [
            "ml-slider", "siteorigin-panels", "so-widgets-bundle",
            "wp-cfm"
        ]
    },
    "content": {
        "posts": {
            "page": ["welcome"]
            "ml-slider": ["new-slider"]
        }
    }
}

 

When we just add an image to a page or post, WP Bootstrap is usually able to identify what media files to include in the export because it can be figured out by analyzing the post itself. But in this case, the image we added to the slider is not really attached to the page, it rather “belongs” to the slider. Since any image could potentially be included to more than one slider, the authors of Meta Slider is using a taxonomy (special kind of category) to tie the image to a slider. Because of this WP Bootstrap can’t figure out that the image needs to be included and we need to include the image separately. Internally, media files are just posts with the post type attachment:

$ wp post list --post_type=attachment
+----+-------------+-------------+---------------------+-------------+
| ID | post_title  | post_name   | post_date           | post_status |
+----+-------------+-------------+---------------------+-------------+
| 5  | camera-1080 | camera-1080 | 2015-12-29 17:14:48 | inherit     |
+----+-------------+-------------+---------------------+-------------+

So we’re going to and add this single attachment to appsettings.json:

{
    "title": "Casestudy 1",
    "themes": {
        "standard": ["vantage"],
        "local": ["vantage-child"],
        "active": "vantage-child"
    },
    "plugins": {
        "standard": [
            "ml-slider", "siteorigin-panels", "so-widgets-bundle",
            "wp-cfm"
        ]
    },
    "content": {
        "posts": {
            "page": ["welcome"]
            "ml-slider": ["new-slider"],
            "attachment": ["camera-1080"]
        }
    }
}

As mentioned above, Meta Slider uses a taxonomy to tie the image to the slider, let’s look at what taxonomies we have:

$ wp taxonomy list
+---------------+------------------+-------------+---------------+---------------+--------------+--------+
| name          | label            | description | object_type   | show_tagcloud | hierarchical | public |
+---------------+------------------+-------------+---------------+---------------+--------------+--------+
| category      | Categories       |             | post          | 1             | 1            | 1      |
| post_tag      | Tags             |             | post          | 1             |              | 1      |
| nav_menu      | Navigation Menus |             | nav_menu_item |               |              |        |
| link_category | Link Categories  |             | link          | 1             |              |        |
| post_format   | Format           |             | post          |               |              | 1      |
| ml-slider     | Categories       |             | attachment    |               | 1            |        |
+---------------+------------------+-------------+---------------+---------------+--------------+--------+

Again, if you know your way around WordPress, you’ll notice that the ml-slider taxonomy is a non standard taxonomy and it also say that it’s linking to object_type=attachment, so we know that’s the one we need to export. Normally when we add taxonomies to the WP Bootstrap appsettings.json, we can just specify it’s name like this if we want to export all terms in a taxonomy:

{
    "title": "Casestudy 1",
    "themes": {
        "standard": ["vantage"],
        "local": ["vantage-child"],
        "active": "vantage-child"
    },

    "plugins": {
        "standard": [
            "ml-slider", "siteorigin-panels", "so-widgets-bundle",
            "wp-cfm"
        ]
    },
    "content": {
        "posts": {
            "page": ["welcome"],
            "ml-slider": ["new-slider"],
            "attachment": ["glasses_coffee"]
        },
        "taxonomies": {
            "ml-slider": "*"
        }
    }
}

The above would cause WP Bootstrap to include any term in the taxonomy “ml-slider” in the export. During import, the taxonomy would be imported with it’s slug as the unique identifier. If a taxonomy term already exists with the same slug, WP Bootstrap would update that term, but if it didn’t exist, WP Bootstrap would create it. However, Meta Slider taxonomies are a little different. When a slider is created, a new taxonomy term is created with the slide post id as the name and slug. We saw above that our slider had post id = 4, so Meta Slider would have created a term with the name/slug = 4. This presents a little problem during import because there’s no guarantee that the slider will get id=4 on the target site so a taxonomy term with the name/slug 4 would be useless. We need to instruct WP Bootstrap to treat this taxonomy a little different. Instead of specifying an asterisk (string) or an array similar to the posts, we’re specifying it as an object with some properties, like this:

    "taxonomies": {
        "ml-slider": {
            "type": "postid",
            "termDescriptor": "*"
        }
    }

The resulting appsettings.json now becomes:

{
    "title": "Casestudy 1",
    "themes": {
        "standard": ["vantage"],
        "local": ["vantage-child"],
        "active": "vantage-child"
    },

    "plugins": {
        "standard": [
            "ml-slider", "siteorigin-panels", "so-widgets-bundle",
            "wp-cfm"
        ]
    },
    "content": {
        "posts": {
            "page": ["welcome"],
            "ml-slider": ["new-slider"],
            "attachment": ["glasses_coffee"]
        },
        "taxonomies": {
            "ml-slider": {
                "type": "postid",
                "terms": "*"
            }
        }
    }
}

 

Now, we have one last thing to do before we’re finished with appsettings.json and that is to define references. There are two post references in this site that matters, but we only need to take one of them into account. The first one is the page_on_front setting that we mentioned earlier. Since this is a standard WordPress setting, WP Bootstrap is already aware of it and we don’t need to specify it. The second one is slightly trickier, the welcome page has a reference to the ml-slider post. Since Vantage theme lets us specify what slider to use on a page as a separate setting, there’s bound to be a reference to it somewhere and it’s by definition a reference to a post (we already know that a slider is just a post with post type “ml-slider”). To figure out the name of this setting, go to the WordPress admin area to edit the Welcome page. At the top of the screen, you can enable to see custom fields by clicking the Screen options and marking the correct checkbox:

Showing custom fields

Scroll down the page to the custom fields section, now we’re able to see all custom fields on this post.

custom fields

As you can see, there’s a field named “vantage_metaslider_slider” that has the value “meta:4”. This is a row in the WordPress table wp_postmeta with a reference to the ml-slider post with id=4. To add this to our appsettings.json, we need to add a references section:

{
    "title": "Casestudy 1",
    "themes": {
        "standard": ["vantage"],
        "local": ["vantage-child"],
        "active": "vantage-child"
    },
    "plugins": {
        "standard": [
            "ml-slider", "siteorigin-panels", "so-widgets-bundle",
            "wp-cfm"
        ]
    },
    "content": {
        "posts": {
            "page": ["welcome"],
            "ml-slider": ["new-slider"],
            "attachment": ["glasses_coffee"]
        },
        "taxonomies": {
            "ml-slider": {
                "type": "postid",
                "termDescriptor": "*"
            }
        }
    },
    "references": {
        "posts": {
            "postmeta": ["vantage_metaslider_slider"]
        }
    }
}

There are a few ways to add information about references to WP Bootstrap, in this case we’re telling WP Bootstrap that there is a postmeta field named “vantage_metaslider_slider” and that it points to a post. We’re basically telling WP Bootstrap that whenever it comes across a postmeta field with this name, it contains an integer that’s a reference to a post id. During import, WP Bootstrap should look up what id that post has in the new site and change the value so that it points to the correct post id. We also saw that the content of this field was not an integer but a string (meta:4). WP Bootstrap can handle this fine just as long as the string doesn’t get too complicated.

With that last piece in place, we’re all done with appsettings.json and can perform the actual export:

$ composer wp-export

You now have a file based representation of your WordPress site in the sub folder bootstrap/ with the following structure:

bootstrap/
├── config/
├── manifest.json
├── media/
|   ├── camera-1080/
├── posts/
│   ├── attachment/
│   ├── ml-slider/
│   └── page/
└── taxonomies/
    └── ml-slider

Together with the appsettings.json file and the projects wp-content folder,  the bootstrap folder is all you need to check in to keep this site managed under Git. Using a workflow combining git commands and WP Bootstrap the relevant parts of the WordPress site can be migrated to a staging or production environment with ease. References between WordPress objects will be preserved on import. When importing this content to another WordPress installation, WP Bootstrap will not touch anything that’s not defined or described in the data we’re bringing, any other posts, pages, comments that exist on the target installation will remain untouched which is the whole point with WP Bootstrap.

Step 6: Putting it to the test

Since we now have a file based representation of our site we’re able to put WP Bootstrap to the test. Let’s destroy the actual site and try the wp-import command. If we’ve gotten everything correct, we should get our site back just as it looked before we destroyed it.

To begin with, WP Bootstrap has a command to completely wipe a WordPress installation, since it’s a bit dangerous it’s not automatically mapped as a composer script. Instead, we need to call the wpbootstrap binary directly:

$ vendor/bin/wpbootstrap wp-reset

This will command will drop all the WordPress tables from the database and forefully delete every single file in the WordPress folder defined in localsettings.json. Powerful but dangerous. Surf to http://www.casestudy1.local/ just to verify that your WordPress installation is indeed gone, you should see a 403 Forbidden message from Nginx.

Next, run the commands to install WordPress, set it up with the right theme and plugins and lastly import content and settings again.

$ composer wp-install
$ composer wp-setup
$ composer wp-import

After these three commands, go back and check http://www.casestudy1.local/ again, your WordPress installation should be back as it were before it was deleted. If you want to play around with WP Bootstrap a bit, an interesting exercise is to reset the installation, run wp-install and wp-setup  to get it back. But before the wp-import command, go ahead and add some pages and posts to make sure the database id’s on the imported posts are different than they were in the initial install.

Conclusions and next steps

Creating a site using WP Bootstrap requires some additional steps compared to the WordPress famous 5 minute install even if it should still be quite possible to do it in under 5 minutes. But the major benefit of using this method is not so that time can be saved at first install but at the long term advantages you’ll get. Now we have a WordPress site that can be installed and configured using a few commands at the terminal, even if that’s been possible to do using wp-cli alone for quite some time, we’re also managing the (important) content. And the content itself is in a format that is suitable for Git and contains just enough meta data for it to be portable between WordPress installations. It’s the foundation for a solid workflow.

The next natural step to go to from here is to add your website to a Git repository.  First, we need to create a .gitignore file with (at least) the following:

.vagrant/
vendor/
www/
localsettings.json

 

Then the following files and folders should be added to Git:

bootstrap/
wp-content/
.gitingore
appsettings.json
composer.json

 

After checkout in the staging or production environment, you can create the initial site using:

$ composer update
$ composer wp-install
$ composer wp-setup
$ composer wp-import

 

When making changes to the original Vagrant installation (your development environment), you check in all changes to git, then back in the staging or production environment, you’d just perform a few commands to get all the changes:

$ git pull
$ composer wp-setup
$ composer wp-import

 

A final note

WP Bootstrap is currently at version 0.3.1, a lot of features are already implemented, but bugs exist and a lot of features simply aren’t implemented yet. If you decide to use WP Bootstrap in a production environment, it’s because you are an early adopter and are prepared to spend lots of time fix potentially large and complicated issues manually. If you don’t feel like an early adopter or if you can’t risk to mess up a deployment, please refrain from using WP Bootstrap in production environment until the package is a bit more mature.

Questions? Concerns? Angry? Happy? Let me know in the comments section below.