How I use Bedrock, the WordPress stack from Roots

Tuesday, 8 July 2014

by Silumesii Maboshe

WordPress and I have had an on-again, off-again relationship for years. I recently decided to pick the CMS up again after Luke Brown introduced me to the BedRock WordPress Stack from Roots. For web development, Ruby on Rails is my framework of choice. Inspired by The 12-Factor App methodology, the team at Roots have managed to turn development and deployment of a WordPress site into one that is more like a using a web application framework. I like this because that is how I like to work in Rails. Thanks to BedRock, I can work this way in WordPress too (… almost)!

I find that when starting with BedRock, I make consistent changes before I can start to actually work. I thought that I’d share those. By doing this, I’m working through the process for myself as I write. If the changes still make sense when writing this article is done, I may put in a pull request to the project.

I’m going to take the scenic route and talk about my setup first. Once that’s done, we’ll dive in to BedRock.

Here we go.


My development operating system is Ubuntu 12.04 LTS (upgrading to the 14.04 LTS in a few days) and I edit using SublimeText 3. Before starting a new WordPress project, I’ll commonly have the following tools installed:

Here is how I set each of them up. I work in the terminal all the time so this article is “terminal-heavy”. When you see blocks of text looking like the block below that start with a $, I mean for you to type in to the terminal command prompt and then hit the Enter key:

$ date

If there is anything that contains a #, this is a comment. You can ignore these lines. If you happen to copy the # and the text after it, everything including and after # will have no effect.

$ cal # This is the date command

The version of Ubuntu I use will not always have the latest version of the tools I like to use. To add the latest versions, I use repositories in PPAs that are unofficially provided. Ubuntu will warn that PPAs should be used with caution. To date, I have had no problems using PPAs. Thankfully, the respective maintainers have been diligent. Nevertheless, the warning should be heeded, especially on production servers.

Before going to the next part, you want to check that you have python-software-properties installed. This will help us add PPAs:

$ sudo apt-get install python-software-properties


SublimeText is an excellent text editor. I currently use SublimeText 3. To keep in sync with updates, I use an installer from WEB UPD8:

$ sudo add-apt-repository ppa:webupd8team/sublime-text-3
$ sudo apt-get update
$ sudo apt-get install sublime-text-installer

The installer takes care of configuration as well and sets up the command subl to control SublimeText. Once completed, check the version installed using:

$ subl --version


Git is my version control system of choice. I use the PPA from the Ubuntu Git Maintainers team to stay up-to-date:

$ sudo add-apt-repository ppa:git-core/ppa
$ sudo apt-get update
$ sudo apt-get install git

To check the version installed, use:

$ git --version


For PHP, I use the PPA maintaned by Ondřej Surý:

$ sudo add-apt-repository ppa:ondrej/php5
$ sudo apt-get update
$ sudo apt-get install php5

To test which version you have installed use:

$ php --version


Since I’m using Nginx, I use PHP FPM to allow it to support PHP:

$ sudo apt-get install php5-fpm
$ php5-fpm --version


WP-CLI provides command-line functionality for a WordPress site. Being a command-line hermit, I have to admit, it’s pretty nifty. It would be a good idea to refer to the actual installation instructions for the latest setup procedure. Here’s what I did to set up WP-CLI on my machine.

Downloaded wp-cli.phar:

$ curl -O

Then, checked that it worked:

$ php wp-cli.phar --info

Made it executable by typing wp:

$ chmod +x wp-cli.phar
$ sudo mv wp-cli.phar /usr/local/bin/wp


For deployment (installing the project on a remote server), BedRock borrows a tool called Capistrano. Rails developers will be familiar with the tool. Capistrano is a an automatic deployment tool written in Ruby and works with different languages, in this case PHP. RVM is a tool that makes Ruby even more of a pleasure to work with. Let’s set it up RVM now so we can install Capistrano later:

$ \curl -sSL | bash -s stable

After the installation, open a new Terminal and test that RVM installed correctly:

$ rvm --version

At this point, RVM is set up but we don’t have any Rubies installed.

$ rvm list

At the time of writing, the latest Ruby available is Ruby 2.1.2. We’ll use RVM to install it, following hints and instructions during the installation process. The process starts with:

$ rvm install 2.1.2

When the process has completed successfully, test that you have at least one Ruby installed:

$ rvm list

So far so good.

Instead of having a general Ruby setup on my machine, I use RVM with gemsets to specify the exact Ruby setup I want for each project. We’ll see how gemsets work in a little while.


Now that Oracle owns MySQL, MariaDB was developed as a “drop-in replacement” for MySQL. For now, this means that you can have MySQL or MariaDB installed and when actually using the database, you would not be able to tell the difference. They look exactly alike. You can read about the benefits of MariaDB over MySQL in a variety of places on the Internet.

I use the repository configuration tool for the steps for setting up MariaDB on my machine. I chose to use the 10.0 branch. Since I’m in Zambia, the tool chose the nearest mirror to me. The following commands installed the key and APT repository for me. It will likely look different for you:

$ sudo apt-key adv --recv-keys --keyserver hkp:// 0xcbcb082a1bb943db
$ sudo add-apt-repository 'deb precise main'

Then install MariaDB:

$ sudo apt-get update
$ sudo apt-get install mariadb-server

To check that it installed, you can use the mysql command just like you would with MySQL:

$ mysql --version


Nginx is a web server. I switched to Nginx from Apache several years ago and prefer it because I get better resource usage out of it. Yet again, I use a PPA for it and install it thusly:

$ sudo add-apt-repository ppa:nginx/stable
$ sudo apt-get update
$ sudo apt-get install nginx

To check which version of Nginx you have installed use:

$ nginx -v


Finally, Composer is the tool that BedRock uses to pull all the dependencies for a WordPress project together. If you are a Ruby developer, you would no doubt have used Bundler. composer is like bundler for PHP.

$ curl -sS | php
$ sudo mv composer.phar /usr/local/bin/composer

If that was successful, you’ll be able to check the version using:

$ composer --version

Using BedRock to build a WordPress Project

Now that we have all the tools we need in place, we can start working with the BedRock WordPress Stack.

Let’s say we have a folder called Projects and another called Repositories in our home folder (~). Let’s also say we have a client project called Jubilee that we’re working on and we have chosen to use WordPress to do it. The first two commands below will create a folder named Projects and a folder named Repositories if they don’t already exist:

$ mkdir -p ~/Projects
$ mkdir -p ~/Repositories
$ cd ~/Projects

To instantiate a WordPress project with BedRock, we use the following command. For reference and more up-to-date instructions, please have a look at the BedRock project on GitHub:

$ composer create-project roots/bedrock Jubilee

Composer will now fetch WordPress wrapped in some useful tools. Welcome to BedRock!

From the Projects folder, let’s have a look at what that composer command just did for us.

$ ls -a
.   config           .env.example  .gitignore  scripts  wp-cli.yml
..       composer.json  Gemfile  vendor
Capfile  composer.lock  .env             Gemfile.lock   web

If you’ve only ever used WordPress from the download, many files will look unfamiliar. Let’s take a closer look:

$ cd Jubilee
$ subl .

This will open up the Jubilee project in SublimeText. Some useful files to have a look at right away are composer.json, Gemfile, .gitignore and .env. Have a look for now, we won’t make any changes just yet.

Initialising the Git Repository

BedRock uses Git for version control. From inside the Jubilee folder, initialise the Git repository and make the first commit:

$ git init
$ git add .
$ git commit -m "Initial project import."

You will remember that a .gitignore has already been defined in the project so not all of the files have been added. This is a useful to know. If we are working with other people on this project, when they clone it, their version will be missing some critical files that composer fetched for us. Perhaps, it would be a good idea to let other developers on the team know how to get their setup to look exactly like ours. I work alone on my projects but think it’s a good idea to plan for the day I’ll have even just one more developer at Pencil Case Studios. As a habit or convention, I create a folder called _meta to put example configurations and notes for other developers (and myself). Inside _meta, I use README for project notes and hints. TODO is for tasks relating to this project. Let’s set that up:

$ git checkout -b meta
$ mkdir _meta
$ touch _meta/README
$ touch _meta/TODO
$ git add .
$ git commit -m "Added _meta/ stub."

Once we are done, we can commit the change to the master branch and then remove the meta branch:

$ git checkout master
$ git merge meta
$ git branch -d meta

So what would a freshly cloned repository look like? I’ll take you on a roundabout way of setting that up.

Let’s go in to our Repositories folder and set up a Git repository that can be cloned from.

$ cd ~/Repositories
$ mkdir Jubilee.git
$ cd Jubilee.git
$ git init --bare

Now, we can go back to the Jubilee folder and push that in to the Jubilee.git folder. After that, we’ll be able to clone from Jubilee.git. We’ll start by renaming Jubilee:

$ cd ~/Projects
$ mv Jubilee Jubilee.original
$ cd Jubilee.original
$ git remote add origin ~/Repositories/Jubilee.git
$ git push origin master

We can now clone from Jubilee.git like this:

$ cd ~/Projects
$ git clone ~/Repositories/Jubilee.git

Now, we should have a folder called Jubilee.original (where we started our project). We’ll also have a folder called Jubilee (our freshly cloned repository). This is what the two folders have inside them. You’ll notice that the contents are slightly different. The differences are even deeper than they appear and we’ll look more closely at that soon:

$ ls -a Jubilee*
.   config           Gemfile       .gitignore  web
..       composer.json  Gemfile.lock  scripts    wp-cli.yml
Capfile  composer.lock  .env.example     .git          _meta       vendor

.   config           .env.example  .git        _meta      vendor
..       composer.json  Gemfile       .gitignore  web
Capfile  composer.lock  .env             Gemfile.lock  scripts    wp-cli.yml

Working with .env

You’ll notice that the file .env in Jubilee.original is missing from the newly cloned Jubilee. BedRock, uses phpdotenv and .env to load shell environment variables on a per-project basis. This is powerful because you should never store sensitive credentials in your code. In this case the sensitive credentials are things like the database username and password.

To help, .env.example is kept in the repository while .env is left out. I end up moving .env and .env.example in to the _meta folder. To do this, we can:

$ cd ~/Projects/Jubilee
$ git checkout -b init
$ mkdir -p _meta/examples/env
$ cp ../Jubilee.original/.env _meta/examples/env/
$ git mv .env.example _meta/examples/env/

I create multiple versions of .env; one for each deployment environment I’ll be working in. This usually ends up being (for local development), .env.virtual, .env.staging and .env.production. It is overkill but it helps me separate notes that I may need that are specific to a deployment environment.

A this point, changes have obviously been made to the repository. However, git status will show that nothing has changed. This is because of this snippet from .gitignore:

# Dotenv

Effectively, this keeps every file named “.env” and every file whose name starts with “.env.” (except “.env.example”) out of this Git repository. This is a more aggressive setup than we’ll need so let’s trim it down:

# Dotenv

Now, we can commit the changes. You may want to leave a note in _meta/README to explain the new location of the .envs for when a new developer clones this repository.

Using a RVM Gemset

Let’s look at the Ruby side to the BedRock project. Ruby uses gems to provide functionality to a project. It is possible to install gems system-wide. However, because different projects may require different versions of the same gem, it is useful to define project-specific installations of exactly the versions of the gems needed. RVM provides gemsets for exactly this.

Create a file called .ruby-version at the top of the WordPress project:

$ cd ~/Projects/Jubilee
$ touch .ruby-version

In the file add the following line:


Now, whenever we change in to the Jubilee folder, RVM will automatically switch to using Ruby 2.1.2 and the gemset jubilee-wp-bedrock for this WordPress project. Go ahead and commit this change.

Defining Gems

Have a look at the file Gemfile. It defines which gems we need to use in this project. At the start, it looks like this:

source ''

gem 'capistrano', '~> 3.1.0'
gem 'capistrano-composer'

The main gem we need here is capistrano-composer. Gems are able to define dependencies. It turns out that Capistrano is dependency of capistrano-composer. As such, we can simplify the Gemfile to just:

source ''

gem 'capistrano-composer', '~> 0.0.4'

The '~> 0.0.4' allows us to lock the gem to a range of versions using the semantic versioning convention. The file Gemfile.lock keeps a definition of what gems and versions our project is locked to. Since we’ve made a change to the Gemfile, we can update all the gem requirements for our project with one command:

$ cd ~/Projects/Jubilee
$ bundle update

If there are any gems that are no longer required, we can remove them using:

$ gem cleanup

We can also check if the gems in our project fall out of date using:

$ bundle outdated

These changes to the Git repository can now be committed.

Defining a WordPress Version

The version of WordPress that BedRock downloads for us is defined in composer.json. WordPress gets installed in to the web/wp folder. You’ll notice that this folder is present in Jubilee.original and missing in Jubilee. This setup means that WordPress is actually a dependency in our project. It also makes quick work of updating to a new version when one is available.

At the time of writing, BedRock will download WordPress 3.9. Notice the following lines in composer.json:

"name": "wordpress/wordpress",
"version": "3.9",
"type": "webroot",
"url": ""
"wordpress/wordpress": "3.9",

However, WordPress 3.9.1 is available. Let’s update composer.json to make sure that WordPress 3.9.1 is the version that we use for our project. To do this, find and replace 3.9 with 3.9.1 in each of the lines we saw earlier:

"name": "wordpress/wordpress",
"version": "3.9.1",
"type": "webroot",
"url": ""
"wordpress/wordpress": "3.9.1",

I don’t particularly like this process of updating the WordPress version. I could easily change the version of a dependency I didn’t mean to change or miss one line. I think using composer require <namespace>/<packagename> syntax is far more elegant and less error prone. Unfortunately, I have not yet been able to get it to work as my understanding of Composer is still quite shallow.

After composer.json has been updated, the new WordPress can be automatically retrieved using:

$ cd ~/Projects/Jubilee
$ composer update

This will also update composer.lock in a similar way to what we’ve seen with Gemfile and Gemfile.lock.

We can commit the changes to the Git repository at this point.

Notice also that other dependencies where installed or updated as well. These are placed in the vendor folder. You’ll notice that the contents of vendor were until this point present in Jubilee.original and missing in Jubilee.

At this point it is useful to highlight that this is what makes BedRock so powerful. With a very lean repository, we can define what we need and download or update as required. In the past I’ve had to lug around a complete repository full of unnecessary (out of date) themes, plugins and other dependencies. BedRock flips this from inconvenience to elegance.

Setting up Capistrano

Capistrano is the tool that BedRock uses to deploy a WordPress site. In the original Gemfile, recall that capistrano was defined (gem 'capistrano', '~> 3.1.0') and then we removed the line simplify the file.

This did not come with repercussions. In the earlier Gemfile, we were guaranteed to have Capistrano version 3.1.0. Now, we’ll get the latest version of Capistrano available. I prefer this arrangement and right, now the latest version is Capistrano 3.2.1. You can check your version with:

$ cd ~/Projects/Jubilee
$ gem list | grep capistrano

Capistrano 3.2.1 is a little different than earlier versions so lets recreate the configuration for use with our project.

First we’ll remove the existing Capistrano configuration files and settings:

$ cd ~/Projects/Jubilee
$ mv Capfile ~/Desktop
$ mv config/deploy* ~/Desktop

As mentioned earlier, I like to have deployment environments called virtual, staging and production. We’ll use Capistrano, using the cap command, to create a configuration for each deployment environment like so:

$ cap install STAGES=virtual,staging,production

This recreates the Capfile, config/deploy.rb and config/deploy/ with its respective files.

By default, Capistrano does not know about Composer. Since this is critical for BedRock to use during deployment, we’ll need to update the new Capfile by re-adding a line that enables it to use Composer. Add the line require 'capistrano/composer' so that your Capfile ends up looking something like this:

# Load DSL and Setup Up Stages
require 'capistrano/setup'

# Includes default deployment tasks
require 'capistrano/deploy'

# Load tasks from gems
require 'capistrano/composer'

# Loads custom tasks from 'lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

I prefer to have developers create their own Capistrano configuration similar to how they create their own .env. As such, I create example configurations inside _meta/ for Capistrano as well:

$ cd ~/Projects/Jubilee
$ git checkout init
$ mkdir _meta/examples/capistrano
$ git mv config* _meta/examples/capistrano

With the example Capistrano configurations in place, we can make Git ignore the configurations where Capistrano expects to find them. In .gitignore add the lines:

# Capistrano configuration

Next, add notes to _meta/README to allow a new developer to the project to figure out how to get Capistrano set up. The setup involves copying the examples in _meta/examples/capistrano to the config folder and then customising the settings to fit their own environment.

It would be useful to commit the changes to the repository at this point.

We have not yet prepared Capistrano to actually deploy a WordPress site yet. We can do that now. Since we have a .env already defined, lets allow Capistrano to access the variables in it. To do this, we’ll install the dotenv gem. Add the dotenv line to Gemfile:

source ''

gem 'capistrano-composer', '~> 0.0.4'
gem 'dotenv', '~> 0.11.1'

To install the new gem, run bundle install.

Next, let Capistrano know that it can access the contents of .env using the dotenv gem. Update Capfile so that it now includes the dotenv configuration:

# Load DSL and Setup Up Stages
require 'capistrano/setup'

# Includes default deployment tasks
require 'capistrano/deploy'

# Load tasks from gems
require 'capistrano/composer'

# Ref:
require 'dotenv'

# Loads custom tasks from 'lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }

Now, if there was an environment variable in .env named DB_NAME, we can access it in our Capistrano configuration using ENV["DB_NAME"]. I find it useful to add variables in .env that Capistrano can use in deployment. For example:

# Application deployment


# Virtual Deployment
VIRTUAL_SERVER_NAME=virtual_server_name			# E.g. jubilee.virtualbox.local

# Staging Deployment
STAGING_SERVER_NAME=staging_server_name			# E.g.

# Production Deployment
PRODUCTION_SERVER_NAME=production_server_name		# E.g.

These can be added to the example .env configurations. The changes to the repository can be commited at this point too.

Now that we can set and read environment variables, it is a good time to use these in our deployment configurations. We’ll start with deploy.rb in the example Capistrano configuration. Let’s update deploy.rb to look like this:

# config valid only for Capistrano 3.1
lock "3.2.1"

set :application, ENV["PROJECT_NAME"]
set :deploy_user, ENV["DEPLOY_USER"]
set :wordpress_applications_folder, ENV["WORDPRESS_APPLICATIONS_FOLDER"]

set :scm, :git
set :use_sudo, false

set :log_level, :info

set :linked_files, %w{.env}
set :linked_dirs, %w{

namespace :deploy do
  desc "Restart application"
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      # Your restart mechanism here, for example:
      # execute :service, :nginx, :reload

# The above restart task is not run by default
# Uncomment the following line to run it on deploys if needed
# after "deploy:publishing", "deploy:restart"

Useful to highlight at this point are :linked_files and :linked_dirs. Capistrano deploys several versions of a project using Git so that it can rollback to previous versions if necessary. :linked_files and :linked_dirs get symbolically linked and so don’t need to be versioned with the rest of the project. I find it useful to use this setup for the WordPress plugins, themes, uploads folders and and the BedRock .env file.

With this understanding, let’s keep WordPress themes out of the repository. Edit .gitignore by adding the following lines:

# Application themes

The deploy.rb configuration defines the general Capistrano behaviour. For a specific deployment environment, for example the virtual deployment environment, we can update virtual.rb inside _meta/examples/capistrano. Update virtual.rb so it looks something like this:

# Ref:
server ENV["VIRTUAL_SERVER_NAME"], user: ENV["DEPLOY_USER"], roles: [:web, :app, :db]
set :deployment_path, ENV["VIRTUAL_DEPLOYMENT_PATH"]
set :deploy_to, "#{fetch(:wordpress_applications_folder)}/#{fetch(:application)}/#{fetch(:deployment_path)}"

# Don't forget to make this repo on the server
set :repository_server_name, ENV["VIRTUAL_SERVER_NAME"]
set :repo_url, "#{fetch(:deploy_user)}@#{fetch(:repository_server_name)}:/var/Repositories/Git/#{fetch(:application)}.git"

# Don't forget to make this branch in the repository

#set :stage, :virtual

fetch(:default_env).merge!(wp_env: :virtual)

For in-depth explanations of the different Capistrano settings have a look at the website and GitHub project page.

Update your other example deployment configurations as you require and commit your changes to the repository.

*You can now remove Capfile, deploy.rb and the deploy folder from ~/Desktop.

Installing WordPress Plugins and Themes

Since we do not version themes and plugins in the project Git repository, what can we do to make sure that the plugins and themes we want get deployed by Capistrano? BedRock uses WordPress Packagist for this. WordPress Packagist is a project that mirrors the WordPress plugins and themes directories to allow them to be packaged using composer.

To use composer to install themes and plugins, the format is composer require <namespace>/<packagename>. With WordPress Packagist, use the wpackagist-theme namespace for themes. For plugins use the wpackagist-plugin namespace.

For example, to install the twentyfourteen WordPress theme use:

composer require wpackagist-theme/twentyfourteen

To install the wordpress-importer plugin use:

composer require wpackagist-plugin/wordpress-importer

When you are asked to Please provide a version constraint for ..., use the version given on the theme or plugin page on

For a fresh BedRock project, I usually require the following themes:

and the following plugins:

Since using Composer to require components updates composer.json (and subsequently composer.lock), Capistrano will automatically install the themes and plugins with WordPress each time the project is deployed.

If you are using a custom theme, you may want to set up a Capistrano recipe to fetch it during deployment. Automation is what Capistrano was built for so it should not be too difficult to make it work in your unique setting.

Using BedRock to deploy a WordPress Project

With our WordPress Stack built, we can now deploy the WordPress site. I’ll describe in general how I go about it. If you need specifics, let me know your setup and I may be able to help.

First, I install a development version of the WordPress project on my local machine. Capistrano is not necessary at this point. I use Nginx as the web server and create example configurations in the _meta/ folder. I do the same for other configurations that will be useful for other developers on the project to be aware of.

Secondly, I deploy in three stages:

  1. Using VirtualBox, I set up a local virtual machine to deploy to. This is my virtual environment.
  2. Using a password protected, live server, I deploy to this as my staging environment.
  3. Finally, after successful deployment and testing on the virtual and staging servers, it is safe to deploy to the production environment. This is the live version of the WordPress site that is publicly accessible on the Internet.


This article ended up being much longer than I had planned. After all this, I hope you are not put off by what appears to be a lot of configuration just to make a simple WordPress website work. I have deliberately over-explained many of the steps here. Additionally, BedRock is still quite a new project and will most assuredly get better. The beauty of it being an Open Source project is that you can suggest improvements yourself.

The investment in setup pays back in bucket-loads. When the setup is complete, you can deploy updates in a single command.

Hope you found this useful and enjoy using BedRock if you are not already.