You are on page 1of 37

9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

An Intro to Bedrock for WordPress


Alessandro Vendruscolo on
May 17, 2016 (Updated on Jul 1, 2016)

The following is a guest post by Alessandro Vendruscolo (https://twitter.com/misterjack) , who


wrote to me excited to write a guest post about a WordPress tool that I didn’t know much
about: Bedrock (https://roots.io/bedrock/) . It’s not a theme, it’s a way to install, configure,
and manage WordPress with security and modern development practices in mind.

Bedrock (https://roots.io/bedrock/) is an open source project made by Roots


(https://roots.io) that you use as base for WordPress projects.

(ads via Carbon)

https://css-tricks.com/intro-bedrock-wordpress/ 1/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Why should you care about Bedrock? Let’s take one step back and think about a typical
way to work on a WordPress project.

(#classic-wordpress-workflow) Classic WordPress Workflow


https://css-tricks.com/intro-bedrock-wordpress/ 2/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

You can download and install WordPress both on your local machine and production
server. You can have a git repository for your theme. Deployment can be FTP transferring
of theme or git pulling the repo from the server. For some projects, you might want to
keep the entire site (even WordPress files) under git as well.

This has issues:

Updating WordPress/plugins from production may break your production site


You have to manually keep track of WordPress/plugin versions
Deploys can be cumbersome
Configuring WordPress is difficult, because the wp-config.php can’t be under version
control

Here’s an example of what I mean. You update a plugin locally because you need some
new functionality that the updated plugin provides. You write code based on that new
functionality. Now it’s time to deploy. You:

1. Install or update the plugin on the production site (make sure it’s the same version!)
2. Compile assets
3. Update the theme on the remote server (using whatever deployment method)
4. If it’s a new plugin, make sure it’s been activated on the production site

https://css-tricks.com/intro-bedrock-wordpress/ 3/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

This is a rather manual approach and can be quite error prone. Most importantly, it can
cause downtime or fatal errors. For instance, you update the plugin and it’s not
backwards-compatible, so it throws errors until the deployment is finished. Or you deploy
first and the site throws errors until you update the plugin.

(#enter-bedrock) Enter Bedrock


If the issues above sound like something you have dealt with in the past, you’ll like
Bedrock. It brings:

Explicit dependencies tracked by Composer (https://getcomposer.org)


Easy configuration with phpdotenv (https://github.com/vlucas/phpdotenv)
Easy one-command deploys with Capistrano (http://capistranorb.com)

You’ll end up with a self-contained WordPress project that installs an explicit version of
WordPress and required plugins (composer install) which can be easily configured. All
configuration is kept in a .env text file) and deployed (cap production deploy).

Less troubles and more automation! Even onboarding a new developer is easier.

https://css-tricks.com/intro-bedrock-wordpress/ 4/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

You also get a multistage environment for free. You can have a development configuration
for working locally and, a staging configuration for tests, and a production configuration
for the live site. You can also define custom configuration, such as backup where you can
have a 1:1 copy of the production environment, on a different server.

(#requirements) Requirements
Here are the requirements for working with Bedrock:

You should be comfortable working on the command line.


You need shell access to the server: if your site is hosted on shared host you’re probably
out of luck1 (#footnote-1-down) .
PHP >= 5.5
You need Composer (https://getcomposer.org) on the server (install instructions
(https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx) ).
You need to have a working Ruby and gem environment on your machine to perform
deploys.
You need to have WP-CLI (http://wp-cli.org) installed locally and on the server if you plan
to use it. It’s not required, but you’ll see later that’s useful (install instructions (http://wp-
cli.org/#install) ).

https://css-tricks.com/intro-bedrock-wordpress/ 5/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

This is in addition to all the normal WordPress server requirements, like MySQL.

(#getting-started) Getting Started


Let’s assume a brand new WordPress project. First, you’ll need a copy of Bedrock, which
you can get from its repository (https://github.com/roots/bedrock) .

(#should-i-clone-or-download-the-repo) Should I clone or download the repo?


Bedrock’s README (https://github.com/roots/bedrock#installation) tells you to clone the
repository, but in my opinion you’re better off downloading it. If it’s something that you
plan to regularly keep up to date, go for the clone route; if it’s something that you plan to
set-and-forget, go for the download route.

Keeping Bedrock up to date is certainly a good thing (improvements, security, etc) but it
can be tricky. You may need to hand-pick changes or try to merge two upstreams. Since it
is a starting point, downloading it means you can set it up once and forget about it.

(#installation) Installation
Now that you have downloaded the repo, you can initialize your own repository for the
project.

https://css-tricks.com/intro-bedrock-wordpress/ 6/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Command Line Steps


wget https://github.com/roots/bedrock/archive/master.zip

unzip master.zip

rm master.zip

mv bedrock-master ~/Sites/example.dev

cd !$

git init

I keep all my web projects in the Sites folder in my home directory (I develop on OS X) and
keep them indexed by their name. I use the `.dev` TLD so I can configure nginx with
virtual hosts. This way, even when working locally, I have a configuration that’s almost
identical to the live website. (Bonus points compared to using localhost: you get a new
environment to work on: cookies, local storage, URLs for caching, etc are not shared with
any other site you previously worked on.)

On my machine, I use this minimal configuration to instruct nginx how to host the
website. Please note that the root folder isn’t the same as the project. Bedrock puts all
public files in the web folder.

nginx Configuration
server {

listen 80;

server_name example.dev;

root /Users/MJ/Sites/example.dev/web;

location / {

try_files $uri $uri/ /index.php;

https://css-tricks.com/intro-bedrock-wordpress/ 7/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

location ~ .php$ {

try_files $uri =404;

fastcgi_split_path_info ^(.+\.php)(/.+)$;

include fastcgi.conf;

fastcgi_intercept_errors on;

fastcgi_pass unix:/tmp/php5-fpm.sock;

Now we need to run a command to let the magic happen:

Command Line
composer install

As you can see by the output, Composer will install dependencies listed in the
composer.lock file, including WordPress itself2 (#footnote-2-down) .

(#so-whats-happening) So, what’s happening?


If you’re new to Composer, I’ll quickly explain what it is and how it works.

Composer is a tool written in PHP that lets you manage PHP dependencies (just like Ruby
gems, npm modules, CocoaPods, etc). These days all languages have a dependency
manager.

You declare the packages you need in the composer.json file, then declare them with
constraints (https://getcomposer.org/doc/articles/versions.md) . Having constraints lets
you define how Composer will update them when you run composer update.
https://css-tricks.com/intro-bedrock-wordpress/ 8/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

For example, Bedrock requires an explicit version for WordPress (4.5 at the time of
writing) and any version

greater than 2 but less than 3 for phpdotenv.

Every time you execute composer update Composer will try to update your packages to
the latest version allowed, and will write down that version number to the composer.lock
file.

Now, when you run composer install (just like you did earlier) it’ll install that specific
version no matter what, reading from the composer.lock file (This is a reason that using
Composer is very safe, just like gem and CocoaPods, and unlike npm, unless you use the
shrink-wrap feature).

If you now list the contents of the web and web/wp directory, you will see something you’re
familiar with: Composer has moved the wp-config.php file to web and all WordPress files
are in the web/wp folder. If you inspect that file you can understand why it’s there.

We’ve everything in place, it’s now time to configure WordPress.

Copy the `.env.examplè to `.env` and edit it:

Command Line
cp .env.example .env

vim .env

https://css-tricks.com/intro-bedrock-wordpress/ 9/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

It asks you for:

1. The name of the database you use (I’ll use example_development)


2. The username that will be used to connect to the database (on my machine I have just one
root user)

3. The password of that user


4. The host of the database (127.0.0.1 or localhost is fine)
5. The environment of this installation (development is fine, you can set whatever you want:
usually you have development, staging, and production)
6. The homepage URL that WordPress will use to build URLs among other things (I set
http://example.dev)

7. The URL for the admin page. Leave it as it is and you’ll access WordPress admin pages at
http://example.dev/wp. If you change this you’ll also need to move the wp folder contents
accordingly
8. Authorization keys and salts that you can generate online (https://roots.io/salts.html)

After you’ve saved the file you can proceed to install WordPress (it needs to create all the
tables in the database!). You can do this by visiting the website on http://example.dev/
or by using WP-CLI (http://wp-cli.org) :

Command Line (WP-CLI)


wp core install --url='http://example.dev' --title='Example' --admin_user='admin' --admin_password='enter' --admin_email='<admin_email>'

WordPress has been successfully installed!


https://css-tricks.com/intro-bedrock-wordpress/ 10/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

We can commit what we did (git add . && git commit -m 'First commit').

Let’s recap that process:

1. Download Bedrock;
2. Run composer install;
3. Edit the .env file;
4. Install WordPress (automated with the wp core install … command).

If other developers later join the team, they’ll clone the project’s repo and start at step 2.

(#working-on-your-project) Working on your project


At this point we have a default WordPress installation, and we can start customizing it!

If we inspect the folder structure you can see how Bedrock organizes the files:

File System
.

├── config

│   ├── application.php

│   └── environments

│   ├── development.php

│   ├── production.php

│   └── staging.php

https://css-tricks.com/intro-bedrock-wordpress/ 11/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

├── vendor

├── web

│   ├── app

│   │   ├── mu-plugins

│   │   ├── plugins

│   │   ├── themes

│   │   └── uploads

│   ├── wp

│   └── wp-config.php

config: this is where you configure WordPress. These files can’t be accessed from the
Internet, because we set nginx to serve files from the web folder.
config/application.php: this file contains the usual WordPress configuration and is
intended to include base settings that are common to all environments.
config/environments/*: these contain environment-specific settings. For example in
production it disables errors output.
vendor: dependencies managed by Composer will be installed there, except WordPress
plugins and themes; if you inspect the composer.json file you’ll see that these kind of
packages will be moved in web/app/{mu-plugins,plugins,themes}/.
web: files included in this directory are publicly available

— only the files that are required are in the web folder (see config above).
web/app: this is the old wp-content folder. It’s been renamed to better reflect its content
(this also matches other frameworks conventions, such as Rails and Symfony). This is
where your plugins and themes will end up.
web/wp: the whole WordPress package. This should be put in vendor but can’t be
because of WordPress limitations.
https://css-tricks.com/intro-bedrock-wordpress/ 12/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

web/wp-config.php: this file is well-known, but in Bedrock it acts as a loader (it loads
settings from the config directory). It needs to stay here because WordPress core hard
codes paths.

(#configuration-and-environment-variables) Configuration and environment variables


As we saw earlier we have multiple configuration files under the `config̀ directory, and we
also have the `.env` file where we put the username/password for the database.

The key aspect is this: if it’s something that’s sensitive (a password or an external service
access key) you should put that in the `.env` file and read that with the env('<name>')
function. Sensitive information will never be stored in your git repository (the `.env` file is
ignored by git) which is a huge benefit. It also allows you to define a different
password/key for each machine. Imagine if every developer has to generate their Twitter
consumer key or has to generate a new one for testing purposes: if the key is stored in a
file that’s tracked by git you have to remember not to add that file to the staging area.

The solution is to add it to the .env file:

.env configuration
[…]

DB_PASSWORD=<password>

[…]

and read that value in the configuration file:

https://css-tricks.com/intro-bedrock-wordpress/ 13/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

PHP
define('DB_PASSWORD', env('DB_PASSWORD'));

Remember that environment-specific files (`config/environment/.php`) are required


before the main (`config/application.php`). This means that you can’t override
settings. Say that you have the same configuration for development and staging but a
different one for production. You can:

define it in every environment file (`development.php`, `staging.php`, `production.php`,


etc).
put it in the `.env` file and define it in the main application (`application.php`) file.

(#plugins) Plugins
If your plugin is available in the official plugin registry, you can install using Composer
and WordPress Packagist (https://wpackagist.org) , which is a Composer repository that
mirrors WordPress’ official plugin and theme registry.

Bedrock already added wpackagist’s repository, so installing a plugin is just a matter of


running the following command to install the latest version:

https://css-tricks.com/intro-bedrock-wordpress/ 14/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Command Line
composer require wpackagist-plugin/<name>

git add composer.json composer.lock

git commit -m 'Install <name> plugin'

Plugins are prefixed with wpackagist-plugin/ so the plugin Memberful WP


(https://wordpress.org/plugins/memberful-wp/) becomes wpackagist-
plugin/memberful-wp.

You can provide a constraint for the version (the previous command would use the ^
constraint (https://getcomposer.org/doc/articles/versions.md#caret) ):

Command Line
composer require wpackagist-plugin/memberful-wp ~1.0

git add composer.json composer.lock

git commit -m 'Install Memberful plugin'

You can achieve the same if you manually edit the composer.json file and run composer
install.

If your plugin isn’t available on the official registry (like custom or paid plugins), you will
need to put it in `web/app/plugins̀ and remove it from the ignore list:

Command Line
mv ~/Downloads/my-plugin web/app/plugins/

echo '!/web/app/plugins/my-plugin' >> .gitignore

git add .gitignore web/app/plugins/my-plugin

git commit -m 'Add my AWESOME plugin'

https://css-tricks.com/intro-bedrock-wordpress/ 15/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Even better, if you have a git repository for the plugin, you can use Composer directly.
Add the following to the repositories array of the composer.json file:

composer.json
{

"type": "git",

"url": "<repository url>"

The repository needs to contain a `composer.jsoǹ manifest file in the root, such as this:

composer.json
{

"name": "macstories/wp-push-plugin",

"description": "MacStories' implementation of Safari Push Notifications",

"type": "wordpress-plugin",

"license": "proprietary",

"require": {

"php": ">=5.5",

"composer/installers": "~1.0.12"

When everything above is set, you can run composer require macstories/wp-push-
plugin to install it. Composer expects to have at least one git tag on that repository.

Now we have the plugin in place, we can enable it. Head over the WordPress admin page
or once again use WP-CLI (http://wp-cli.org) :

https://css-tricks.com/intro-bedrock-wordpress/ 16/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Command Line
wp plugin activate memberful-wp

This time we don’t need the wpackagist-plugin prefix, as WordPress doesn’t know about
Composer.

If plugins need to create files or folders, they should be ignored by git, adding them in the
.gitignore file. One example of this is WP Super Cache: it creates two PHP files
containing settings.

If plugins ask you to modify the wp-config.php file, move those new settings to
`application.php` (or the environment specific one) as explained earlier.

(#themes) Themes
Themes work the same way as plugins, with two differences:

1. Their directory is web/app/themes;


2. Composer’s vendor name is wpackagist-theme.

If you use a theme that’s available on the official WordPress registry you can install it with
Composer:

https://css-tricks.com/intro-bedrock-wordpress/ 17/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Command Line
composer require wpackagist-theme/activello

If you’re going to develop your own theme, create its folder under web/app/themes and
you’re ready to go. There’s no need to exclude it from the .gitignore file.

In your theme you can query the current environment and take advantage from that. For
example, on MacStories (https://www.macstories.net/) (a site I developed with Bedrock), I
don’t include the minified assets in development:

PHP
$main = '';

if (WP_ENV === 'development') {

$main = macstories_asset_url( '/dist/main.css' );

} else {

$main = macstories_asset_url( '/dist/main.min.css' );

// use the $main variable

Another difference is analytics. I only include Mint Analytics in production, using an


approach similar to above. Google Analytics is available even in development or staging,
but these two environments use a different site ID, so it’s easier to perform tests.

(#upgrading-wordpress) Upgrading WordPress


https://css-tricks.com/intro-bedrock-wordpress/ 18/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

At the time of this writing, WordPress is at 4.5.2. Let’s say 4.5.3 version comes out. We
need to change the required version. You can edit the composer.json file and run
composer install or you can just issue the following command:

Command Line
composer require johnpbloch/wordpress 4.5.1

It will update the `composer.jsoǹ file (and also the lock file, since we upgraded a
dependency) and install the dependency.

Usually after each WordPress update there’s a database schema upgrade to be performed
which you can do by visiting the WordPress admin page. But that’s tedious, so WP-CLI
has a command to perform that:

Command Line (WP-CLI)


wp core update-db

There’s also another thing to keep in mind when upgrading the database schema: if you
use the web UI to do that, and the operation takes too much time, you may encounter
HTTP timeouts. WP-CLI skips the HTTP layer and performs the operations running PHP
from the command line, which doesn’t have any timeout issues.

https://css-tricks.com/intro-bedrock-wordpress/ 19/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

(#upgrading-plugins) Upgrading plugins


Upgrading plugins is similar to upgrading WordPress: if you used Composer to install
them, use Composer to upgrade them.

You can run composer require wpackagist-plugin/<name> <version> to upgrade a


given plugin to a specific version or, even better, use composer update to update every
package to their latest version that satisfies the constraints set in the `composer.jsoǹ file.

When you composer require <package> something (without specifying a version),


Composer will by default use the ^ constraint
(https://getcomposer.org/doc/articles/versions.md#caret) : running composer update will
update the package to the latest version that’s not a new major version. Easy peasy.

(#deploying-your-project) Deploying your project


At this point you should have a working WordPress site on your machine. But that’s
almost useless, unless your machine is on the Internet
(https://twitter.com/oising/status/298464920717099009) .

https://css-tricks.com/intro-bedrock-wordpress/ 20/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Capistrano (http://capistranorb.com) is the de-facto tool used for deploys, and you can
use it to deploy WordPress sites.

(#what-is-capistrano) What is Capistrano?


Capistrano (http://capistranorb.com) is a powerful tool written in Ruby used mainly3
(#footnote-3-down) to perform deploys. Originally it was born to deploy Ruby on Rails
web applications, but then it grew to deploy any kind of web application, with plugins to
run custom tasks or connect to external services.

There are plenty of guides on the Internet and many conference talks, but to sum it up:
Capistrano will connect to your server using SSH and then follow this flow
(http://capistranorb.com/documentation/getting-started/flow/) to update a repository on
the server and run tasks. You add hooks on every task to perform what you need.

It’s designed to work with SSH keys (so you don’t have to use passwords) and it should
connect to the server as an unprivileged user. It can issue sudo commands, but if you need
to do that, there’s probably something wrong with your setup. You can learn more about
this on the Authentication & Authorisation
(http://capistranorb.com/documentation/getting-started/authentication-and-
authorisation/) documentation page. I use SSH agent forwarding so Capistrano is able to
pull from the git host using my local SSH key.

https://css-tricks.com/intro-bedrock-wordpress/ 21/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

On the server, Capistrano works by keeping multiple directories in the directory you set as
the target of deploys:

Project File Structure


.

├── current -> releases/20160420173015

├── releases

│   ├── 20160420173015

│   ├── 20160412113015

├── repo

└── revisions.log

├── shared

current: this is a symlink to the current version deployed (either the latest one or a
previous one if you rolled back).
releases: every time you deploy Capistrano will create a new folder with a timestamp.
You can configure the number of releases to keep, and Capistrano will clean up old
releases (defaults to keeping 5 releases).
repo: Capistrano keeps the repository on the server and checkouts the correct revision on
the server — nothing is transferred from your machine to the remote server.
revisions.log after every deploy or rollback this log will be updated.

shared: contains files and folders that must be shared between releases, such as user
uploads.

Each deploy is run in isolation and has its own folder in the releases folder. If something
goes wrong, nothing happens to the current version. When it’s done, Capistrano will

https://css-tricks.com/intro-bedrock-wordpress/ 22/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

update the symlink to the version that was just deployed.

In your project you’ll have a Capfile that requires the tasks to run (see the example from
the flow (http://capistranorb.com/documentation/getting-started/flow/) ) and a
deploy.rb file that contains settings.

(#if-you-dont-want-to-use-capistrano) If you don’t want to use Capistrano


Bedrock supports Capistrano, but it’s not required. If Capistrano doesn’t compel you, or
you prefer to use a different tool, or prefer to use no tool at all, you’re free to do so.

The only requirement is that you run composer install on the server, so Composer can
pull down WordPress, plugins, and any other dependency your site needs. Otherwise
you’ll have a sort of zombie website with just application code but not the application
itself.

(#deploying-with-capistrano) Deploying with Capistrano


OK, I convinced you to try Capistrano, let’s go on!

The Roots team (the team behind Bedrock) created a separate repository
(https://github.com/roots/bedrock-capistrano) to host the Capistrano integration for
Bedrock. This is because Capistrano is not required by Bedrock but can be added at any
time.

Create or edit a Gemfile file in the root of the project and paste this content:
https://css-tricks.com/intro-bedrock-wordpress/ 23/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Gemfile
source 'https://rubygems.org'

group :deployment do

gem 'capistrano', '~> 3.4'

gem 'capistrano-composer'

gem 'capistrano-wpcli'

end

Now run bundle to have it install the gems. This differs a bit from Roots’ setup, because we
grouped these gem in the deployment group and also installed the WP-CLI extension.

Capistrano will be installed by Bundler (https://bundler.io) and be treated as a


dependency just like we did with WordPress and Composer earlier. This is useful because
every project can use a different version of Capistrano and will not depend on a globally
installed one. Also, if there are multiple developers on the team, a locally installed (and
synchronized) version of Capistrano ensures that everything will be as smooth as
possible4 (#footnote-4-down) .

Commit both `Gemfilè and `Gemfile.lock` – just as with Composer:

Command Line
git add 'Gemfile*' && git commit -m 'Install Capistrano'

Now we need to set up Capistrano. Capistrano’s configuration will be kept in the git repo.
You have to copy the Capfile file and the contents of the config directory from the

https://css-tricks.com/intro-bedrock-wordpress/ 24/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

repository (https://github.com/roots/bedrock-capistrano) . This is the equivalent of


running bundle exec cap install and editing Capistrano’s configuration files.

Since we also installed the WP-CLI plugin, we have to require it in the Capfile. Add the
following line after we required the Composer plugin:

Capfile
require 'capistrano/wpcli'

Edit the config/deploy.rb and set the :application and :repo_url variables and remove
the :deploy_to line. If you want, you can also change other settings here. There are many
code comments and the documentation (http://capistranorb.com/documentation/getting-
started/configuration/) is great.

The :linked_files and :linked_dirs variables are important. If you recall from earlier,
Capistrano will create on the server a shared folder (shared between deploys). By default,
we’ll share the `.env` file and the `web/app/uploads̀ folder.

The `.env` file contains application settings and needs to be shared for the site to work,
and also because this file isn’t under version control. The `web/app/uploads̀ folder is the
old `wp-content/uploads̀ folder and needs to be shared because otherwise uploads would
exist only within a release.

https://css-tricks.com/intro-bedrock-wordpress/ 25/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

You can probably ignore the rest of the config/deploy.rb file. After line 22 it defines two
custom tasks. The first is empty and disabled by default. It can be used for example to
restart the web server. If you have something to restart after a deploy, update the task and
enable it.

The second task has been added by the roots team and is disabled by default. It’s used
update the stylesheet_root and template_root options of WordPress. I’ve never had a
reason to change them.

Edit the `config/deploy/<stage>.rb` file to set per-stage settings.

You have to update the server setting, because the production env is likely to be on a
different server than the staging one.

We’ll move the :deploy_to path setting here, as your staging path is probably different
from the production one. You can also override settings set in the main `deploy.rb` file.
The rationale of these files is the same as Bedrock environment files.

Now we configured Capistrano and everything should work. Capistrano comes with a
check task that, well, checks that everything works.

Run the following command to perform the check:

Command Line
bundle exec cap staging deploy:check

https://css-tricks.com/intro-bedrock-wordpress/ 26/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Capistrano will:

1. Log in on the server with the user you defined (so you’re sure the SSH connection works)
2. List repository remote files (so you know Capistrano is able to connect and authenticate
with the git host)
3. Create the directory structure
4. Create linked folders
5. Check for linked files

Here’s an example of a Capistrano error we might see:

"
ERROR linked file /path/to/:deploy_to/shared/.env does not exist on <host>

Create that file (you can use scp .env <user>@<host>:<value of


:deploy_to>/shared/.env to upload your development `.env` file to the server. At this
time, we’re interested in having the file, not having the correct file) and when you’re done
check again that everything works. Hooray it works!

Push your changes (otherwise Capistrano will clone an empty or old repository) and run
the following to perform a real deploy:

Command Line
bundle exec cap <stage> deploy

https://css-tricks.com/intro-bedrock-wordpress/ 27/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

This is the command that you’ll need to remember and run every time you’ll want to
deploy your site.

(#configuring-the-remote-wordpress) Configuring the remote


WordPress
You will have to update the `.env` file on the remote server to set the correct database
information and, most importantly, the WP_ENV and WP_HOME settings.

If you deployed to production that must be WP_ENV=production (I don’t know your


WP_HOME value).

Your web server needs to serve contents from the current folder, so if locally you had this
this setting for nginx:

nginx Configuration
root /Users/MJ/Sites/example.dev/web;

on the server you’ll have to update it in this way:

nginx Configuration
root <value of :deploy_to>/current/web;

https://css-tricks.com/intro-bedrock-wordpress/ 28/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Installing WordPress on the remote server is just a matter of doing the same things you
did on your local machine. You can use the web UI or use WP-CLI, even from within
Capistrano.

When you deploy a new version and in that version you install a new plugin, you can use
the following command to enable the plugin:

Command Line
bundle exec cap <stage> wpcli:run['plugin activate <name>']

To perform database migrations:

Command Line
bundle exec cap <stage> wpcli:run['core update-db']'

(#hooks) Hooks
You can define custom tasks for Capistrano to run, but before doing so, search for an
existing solution. Capistrano comes with many official plugins, like Bundler
(https://github.com/capistrano/bundler/) , npm (https://github.com/capistrano/npm/)
and many other community driven plugins
(http://capistranorb.com/documentation/third-party-plugins/) .

https://css-tricks.com/intro-bedrock-wordpress/ 29/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

For example, say you have a build script that compiles Sass assets. Because of the benefits
we talked earlier, you should require Sass in the Gemfile with:

Gemfile
gem 'sass', '~> 3.4'

Now we need to do two things when we deploy:

1. Ensure the sass gem is installed


2. Run our own build script

(#capistrano-bundler) Capistrano-bundler
The first step is easy to achieve: we’ll require the capistrano-bundler gem by adding this
line to the :deployment group:

Gemfile
gem 'capistrano-bundler', '~> 1.1.2'

After that you run bundle to install the gem and also edit the Capfile to require it:

Capfile
require 'capistrano/bundler'

Done. Every time we deploy, Capistrano will run bundle install on the server, after the
deploy:updated task.

https://css-tricks.com/intro-bedrock-wordpress/ 30/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

If you want, set the :bundle_without variable in the `deploy.rb` file:

deploy.rb
set :bundle_without, %w{deployment development test}.join(' ')

Doing so will exclude those groups of gems from being installed. Bundler will install less
gems (that we won’t need!) and our deploys will be faster.

(#running-custom-scripts) Running custom scripts


I don’t know how your build script is structured. I’m a fan of make, but you can have
anything you want: a shell script, npm scripts, Grunt/Gulp tasks, etc. No matter what, we
have to run them, otherwise our site will be without assets.

We can create a custom task easily. Create your .cap (e.g. make.cap) file in
lib/capistrano/tasks to have it automatically loaded (otherwise you’d have to explicitly
require from the Capfile) with this content:

Capfile
namespace :make do

desc "Runs make all"

task :all do

on roles :all do

within release_path do

execute :make

end

end

end

https://css-tricks.com/intro-bedrock-wordpress/ 31/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

before 'deploy:updated', 'make:all'

end

Capistrano will run our task before the deploy:updated task. Since we used the within
release_path do … bit, this command will be executed in the correct
release/<timestamp> directory that Capistrano is deploying.

Check out Capistrano’s documentation (http://capistranorb.com/documentation/getting-


started/tasks/) for more. Hot tip: be sure to use the colon before any argument (it has to
do with shell escaping).

(#adding-a-new-stage) Adding a new stage


Bedrock comes with three default environments:

1. Development (Bedrock only)


2. Staging (Bedrock and Capistrano)
3. Production (Bedrock and Capistrano)

You can add a new stage if you need to. An example could be a backup environment that is
100% equal to the production one. The database could be synced periodically or you

https://css-tricks.com/intro-bedrock-wordpress/ 32/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

could setup MySQL replica functionality. In case of failure you’d update your DNS to point
to the different host and nobody will notice anything.

To add a new stage:

1. Create a new environment for Bedrock: `config/environment/backup.php` (you can copy


an existing one and update what’s needed)
2. Create the Capistrano stage configuration: `config/deploy/backup.rb` (again use an
existing one as a base)
3. Setup the server (web server, database, etc)
4. Deploy the project (bundle exec cap backup deploy:check and bundle exec cap
backup deploy)

5. Be sure the `.env` file contains WP_ENV=production

(#migrating-an-existing-project-to-bedrock) Migrating an existing


project to Bedrock
In this tutorial we created a new project, but Bedrock can be used with existing projects.

If you have an existing WordPress site and want to convert it to Bedrock, you can treat it
as if it was a new project:

https://css-tricks.com/intro-bedrock-wordpress/ 33/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

1. Install Bedrock
2. Configure WordPress
3. Restore your theme
4. Install plugins with Composer

If you didn’t modify WordPress core files you’re done. If you modified WordPress core
files you’ll have to keep your custom WordPress version under version control (you’ll lose
easy-Composer-driven WordPress updates, but still have every other feature).

(#gotchas-and-tips) Gotchas and tips


Some tips:

1. Remember that if [something] created [something else], you shouldn’t manage it. This
includes for example: files created by plugins, files installed by a package manager, files
uploaded by users, etc — don’t add them to git. If you ignore them, there’s also an high
chance they should end up in the linked_files setting of Capistrano.
2. Don’t store sensitive information in git.
3. Don’t forget to git push before deploying: I’ve deployed multiple times the same version
before realizing that I forgot to push (on the server Capistrano was pulling the same
version over and over again).

https://css-tricks.com/intro-bedrock-wordpress/ 34/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

4. Use WP-CLI whenever possible: it’s faster and can be executed by Capistrano. Examples
include:
wp plugin activate <name>

bundle exec cap <stage> wpcli:run['plugin activate <name>']

wp core update-db

bundle exec cap <stage> wpcli:run['core update-db']

5. You can set Capistrano branch (config/deploy.rb) to set :branch, ENV['BRANCH'] ||


:master: doing so lets you easily deploy a branch by doing BRANCH=my-feature bundle
exec cap <stage> deploy (remember to push, see tip #3); if you don’t provide the
BRANCH=<branch> environment variable, Capistrano will fall back to deploying master.

6. Using Slackistrano (https://github.com/phallstrom/slackistrano) you can post to a Slack


channel after every successful deploy.

(#recap) Recap
I hope you followed and enjoyed this tutorial. I encourage you to create a new site on your
local machine to have something to experiment with.

To recap, these are the advantages that Bedrock brings:

Self-contained repository

https://css-tricks.com/intro-bedrock-wordpress/ 35/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

Easy deploys
Easy multi-stage support
More consistency between environments
Separation between configuration files and everything-else

Congrats on making it through this tutorial. Sorry if it was long and difficult. It’s definitely
not for beginners! Hopefully along the way you learned some new tools and leveled up
your understanding of all the different moving parts.

The benefits of working like this are well worth it, in my opinion. Now go create
something nice!

[^1] (#footnote-1-up) : That’s not because you can’t ssh <user>@<host> (some hosts
permit that) but because you can’t install some of the required software — if you’re using a
script that runs on the server to build the assets you’re probably fine.

[^2] (#footnote-2-up) : Unfortunately at this time it doesn’t exist an official version of


WordPress distributed via Composer. Bedrock uses this fork
(https://github.com/johnpbloch/wordpress) that syncs every 15 minutes.

[^3] (#footnote-3-up) : In fact, you can deploy whatever you want with Capistrano: you’re
not constrained to web apps, you could deploy iOS apps to a remote server, if that makes

https://css-tricks.com/intro-bedrock-wordpress/ 36/37
9/20/21, 7:21 AM An Intro to Bedrock for WordPress | CSS-Tricks

sense to you.

[^4] (#footnote-4-up) : Later you’ll see cap commands prefixed by bundle exec: doing so
ensures that the local gem is used instead of a globally installed one (which might not
exist). You should do the same for Sass or any other gem.

https://css-tricks.com/intro-bedrock-wordpress/ 37/37

You might also like