Last updated: March 1, 2019

WordPress has always been the orange cucumber in the room. Everyone knows about it. Some folks hate it. Men want to be it. And yet, the percentage of the web that it powers continues to climb every year.

Maybe it’s due to its user-friendly admin panel. Or, perhaps it’s because anyone with a copy of Dreamweaver CS2 can FTP into a LAMP stack and make changes on the fly.

Regardless, it’s worth considering that the business benefits of developing for WordPress might arguably outweigh the drawbacks of its wonky codebase, questionable practices, and the outdated toolchain used to manage a vast majority of installs.

So, what do we do? How can you develop for WordPress in the 21st century without feeling like a total hack?

Roots to the Rescue

The folks over on the Roots development team have long recognized the quirks with WordPress and have assembled a team of smart brains to do something about it. Their latest project, called Trellis, aims to replace the antiquated approach to creating and managing WordPress environments.

A second Roots project, called Bedrock, provides a WordPress boilerplate with modern development tools, easier configuration, and an improved folder structure. When used in tandem with Trellis, you’ll have all the professional tools in place to take the WordPress world by storm.

This article will show you exactly how to use Bedrock and Trellis together to create, develop for, provision, and manage servers in parity, along with deploying your code to each of those environments, making you a total WordPress badass.

This might take a little while, but you’ll thank me once it’s all set up.

Requirements

1 to 2 hours

A billing address and a credit card

A GitHub account and working knowledge of version control

10GB+ of free HD space

A 6-pack of beer (optional, I guess.)

Let’s get started

First things first: I’m developing on a Mac Mini, using OS X Yosemite. While Bedrock and Trellis can be used on most any operating system and machine, this article will be detailing installation and usage instructions for folks in a similar environment.

In order to get going with using this stack, there are a few other programs that you need to install first. We’re going to use Terminal to install these dependencies.

Terminal offers a command-line interface (CLI), which is a means of interacting with your system where you’ll issue commands in the form of successive lines of text. That’s right baby, no menus or shiny icons here. You’re a real hacker now.

Terminal is located in the Applications/Utilities folder. Alternatively, you can use Spotlight to search for and open it up.

You’ll know you’re ready to go when that big, scary, empty black box pops up. For the remainder of this tutorial, we’ll call this box the CLI.

Installing Dependencies

A quick note: the sections below using a convention of highlighting text to show what you must enter into your CLI. If you see text that looks like this , it means that you should literally type like this into your CLI and press enter.

The following programs are required to be installed on your system before using Bedrock and Trellis:

Homebrew

Git

Ansible 2.4.0.0

Composer

VirtualBox

Vagrant

If you know you have these programs installed already, you can skip down to the Configuring Trellis section below. If not, read on.

Homebrew

The first program that we’ll install is called Homebrew, a package manager for OS X that allows you to install and configure other programs on your Mac. I know, meta, right?

To install Homebrew, copy and paste the following command into your CLI:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

During the installation process, you may be prompted to press Enter or type in your Mac password. Don’t be shy! Just follow the instructions until Homebrew finishes doing its thing.

Once it’s done, you can type the following command into your CLI to ensure everything is set up properly:

brew doctor

Git, Ansible and Composer

Now that we’re ready to brew, let’s use the brew command to install three of our remaining dependencies: Git, Ansible, and Composer. Type the following command into your CLI to install those packages:

brew install git ansible composer

Homebrew will barf out a ton of stats and information, and once it has finished without errors, you’re ready to move on.

VirtualBox

Next, we’ll want to install VirtualBox, an open source virtualization program that we’ll use to create imaginary servers on our development machine. You can download the proper version of VirtualBox from the VirtualBox downloads page.

Once VirtualBox has finished downloading, make sure to double-click the DMG file that was saved to your computer and follow the on-screen prompts to complete the installation.

Vagrant

Phew! Almost done. The last thing we want to install is Vagrant, a program which will allow us to create and configure lightweight, reproducible, and portable development environments. It is an amazing tool for managing virtual machines via a simple-to-use command line interface.

You can download the proper version of Vagrant from the Vagrant downloads page. Once Vagrant has finished downloading, make sure to double-click the DMG file that was saved to your computer and follow the on-screen prompts to complete the installation.

BOOM! Time to move on.

Installing Trellis

Wait, we’re how many words into this article, and we haven’t even touched Trellis yet? I know. Time to change that.

For the purpose of this article, we’re going to create and run our new WordPress site out of the current user’s sites directory (if it doesn’t exist, we’ll create it.) If you already have a directory that you’d like to work out of, make sure to replace any occurrences of ~/sites/ in the remainder of this article with the directory of your choice.

Let’s first create the folder that we’re going to build our WordPress site in. Enter the following commands in your CLI, one at a time, replacing example.com with the actual name of the project that you’re working on.

mkdir -p ~/sites/example.com cd ~/sites/example.com 1 2 3 mkdir - p ~ / sites / example . com cd ~ / sites / example . com

Now that we’ve told our CLI to work out of that new directory, let’s download and install Trellis into it by cloning the public Git repository. Use this command to do so:

git clone git@github.com:roots/trellis.git trellis

You should see a new folder in your example.com directory called trellis which contains the core install of your Trellis repo. Sweet!

Now, let’s fetch the external Ansible roles/packages that Trellis will use when provisioning your virtual machines and servers. You can do so with the following command in your CLI:

cd ~/sites/example.com/trellis && ansible-galaxy install -r requirements.yml

Installing Bedrock

“So, we’ve installed Trellis and a hundred other programs, but what about our friend Bedrock? Also, are we almost done installing things? I only have 200MB left on my hard drive :(

Yes, I promise you the installation process is coming to an end. But, not before we run the following command to download the Bedrock repo and place it in our example.com folder:

cd ~/sites/example.com && git clone git@github.com:roots/bedrock.git site

Heck yeah, son! You’ve gotta be a Git pro by now.

A Word about Composer

The cool thing about Bedrock is that it enables support for managing your WordPress themes, plugins, and core install via Composer, which is yet another package manager made specifically for PHP packages.

So what does that mean for you? Well, instead of updating WordPress core from the admin panel, or letting your plugins run amuck with updates on the admin plugins page, you can define your site requirements and dependencies entirely within a single composer.json file.

Ultimately, It will make development more reliable, help with team collaboration, and help you maintain a better Git repository. Trust me, this rules.

Let’s grab the WordPress core now with the following command:

cd ~/sites/example.com/site && composer install

Configure WordPress

Okay, so we have WordPress installed. Let’s get our connection settings configured and actually get that sucker running, whaddya say?

Open the file located at trellis/group_vars/development/wordpress_sites.yml in your preferred text editor. I’m using Sublime Text which allows me to run the following command to open the correct file automatically:

subl ~/sites/example.com/trellis/group_vars/development/wordpress_sites.yml

The contents of this file will define our WordPress development environment settings, including the url of your site, database connection details, admin info, and other environment variables.

For now, we only care about setting the connection details to our future development site and database. Look for the below settings, and change them so that you replace any instance of example with your actual site name.

wordpress_sites: example.com: site_hosts: - canonical: example.local redirects: - www.example.local local_path: ../site # path targeting local Bedrock site directory (relative to Trellis root) site_title: Example Site admin_email: admin@example.local # You can set ssl enabled: false if you don't want to require https # Otherwise, Trellis will generate a self-signed certificate for you. ssl: enabled: true provider: self-signed multisite: enabled: false cache: enabled: false 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 wordpress_sites : example . com : site_hosts : - canonical : example . local redirects : - www . example . local local_path : . . / site # path targeting local Bedrock site directory (relative to Trellis root) site_title : Example Site admin_email : admin @ example . local # You can set ssl enabled: false if you don't want to require https # Otherwise, Trellis will generate a self-signed certificate for you. ssl : enabled : true provider : self - signed multisite : enabled : false cache : enabled : false

We’ll also want to add our WordPress admin password and MySQL database password to our vault file, which is specifically meant to hold sensitive data. Open the file located at trellis/group_vars/development/vault.yml and make sure to configure the following settings:

# Variables to accompany `group_vars/development/wordpress_sites.yml` vault_wordpress_sites: example.com: admin_password: example_wordpress_admin_password env: db_password: example_dbpassword 1 2 3 4 5 6 7 # Variables to accompany `group_vars/development/wordpress_sites.yml` vault_wordpress_sites : example . com : admin_password : example_wordpress_admin_password env : db_password : example _ dbpassword

Make sure to save once you’ve made the proper changes.

Alright, I’m sick of all this code configuration BS, and I’m sure you are too. It’s time to provision our virtual development machine. Let’s run the following command to get everything up and running:

cd ~/sites/example.com/trellis && vagrant up

At this point, your computer will start doing things that Alan Turing could only dream of. Trellis is gonna use Vagrant and Ansible to go through all of its default settings and create an awesome virtual web server in an isolated container on your machine, using a modern LEMP stack that can be further configured, if desired.

Near the beginning of this process, you’ll be prompted to enter your system password which will give Vagrant permission to write to your system’s /etc/hosts file. Vagrant will create an entry that allows your browser to route incoming requests for your site’s URL to the virtual machine that is being configured.

Go get a beer, and once this process has finished without errors, type your site URL in your favorite browser.

Feeling like a goddamn champion yet?

Adding WordPress plugins

If you’ve made it this far, it’s now time to start seeing the fruit of all your hard labor. Let’s go over how to install WordPress plugins on our newly configured site.

I’m sure it has happened to everyone: you or a client notice a update is available for one of your WordPress plugins in the admin dashboard. Sweet! You go to get the latest version, and soon after were wishing you never clicked “Update” – bombarded by errors, or, worse, a blank screen with nothing at all.

Installing untrusted and untested code on your website is a terrible practice and habit. Bedrock will prevent the use of updating plugins from the WordPress dashboard, and instead, moves this process to your development environment using Composer.

This allows you to check your plugin updates into your version control system and easily find the issues and perform a rollback to working code if an update goes sour.

To add a plugin, open the file located at site/composer.json in your preferred text editor.

subl ~/sites/example.com/site/composer.json

In this file, you’ll see a block of code that resembles the following:

"require": { "php": ">=7.1", "composer/installers": "^1.4", "vlucas/phpdotenv": "^3.0.0", "oscarotero/env": "^1.1.0", "roots/wordpress": "5.0.3", "roots/wp-config": "1.0.0", "roots/wp-password-bcrypt": "1.0.0" }, 1 2 3 4 5 6 7 8 9 "require" : { "php" : ">=7.1" , "composer/installers" : "^1.4" , "vlucas/phpdotenv" : "^3.0.0" , "oscarotero/env" : "^1.1.0" , "roots/wordpress" : "5.0.3" , "roots/wp-config" : "1.0.0" , "roots/wp-password-bcrypt" : "1.0.0" } ,

This code is defining the required packages that your WordPress site depends upon. These dependencies will all be installed/updated on your server whenever you or ansible runs the composer install and composer update commands in your CLI.

Every WordPress plugin on wordpress.org is mirrored by a nifty little service called wpackagist. We’ll use this service as the host from which to install our WordPress plugins.

Let’s add a line to this block to install the Vimeography video gallery plugin:

"require": { "php": ">=7.1", "composer/installers": "^1.4", "vlucas/phpdotenv": "^3.0.0", "oscarotero/env": "^1.1.0", "roots/wordpress": "5.0.3", "roots/wp-config": "1.0.0", "roots/wp-password-bcrypt": "1.0.0", "wpackagist-plugin/vimeography": "2.0.6" }, 1 2 3 4 5 6 7 8 9 10 "require" : { "php" : ">=7.1" , "composer/installers" : "^1.4" , "vlucas/phpdotenv" : "^3.0.0" , "oscarotero/env" : "^1.1.0" , "roots/wordpress" : "5.0.3" , "roots/wp-config" : "1.0.0" , "roots/wp-password-bcrypt" : "1.0.0" , "wpackagist-plugin/vimeography" : "2.0.6" } ,

As you can see, we told Composer to look for a wpackagist-plugin called vimeography and to use version 2.0.6 – if we always wanted to use the latest version, we could instead use dev-trunk in place of the version number, but I like to be explicit about which versions I use.

Now, back in your CLI, we’ll tell composer to refresh all of our required packages by running this command:

composer install && composer update

Head back over to your WordPress dashboard and visit the plugins page to revel in your success.

Time to Go Live

Up until now, we’ve been working on our website locally, meaning that it isn’t actually published anywhere that is publicly accessible. Let’s change that and get you running on a real live webserver.

Digital Ocean

For the purposes of this tutorial, we are going to set up the WordPress site on a VPS over at Digital Ocean. It’s a great alternative to traditional shared hosting because it is built on super fast solid state drives and it is very friendly on the wallet.

If you’re new to Digital Ocean, you can sign up through this link and receive a free $10 credit, good for two free months of WordPress hosting.

After you’ve created and logged in to your Digital Ocean account, it’s time to start setting up the server.

Create a New Droplet

DigitalOcean calls its virtual private servers droplets; each droplet that you spin up is a new VPS for your personal use. The setup is very easy – let’s create one now.

Note: you’ll want to have an SSH key ready to access your new droplet. An SSH key is basically a password that tells your droplet to allow incoming connections from your computer. You can learn how to make one from the GitHub help page

Start by clicking the green Create button at the top of the page and selecting Droplets.

Choose an Image: Click on the Distributions tab, and choose Ubuntu on 18.04.1 x64 – it should be selected by default.

Click on the tab, and choose – it should be selected by default. Choose a Size: Next to Standard Droplets , page left to select $5/month

Next to , page left to select $5/month Add Backups: Only if you’d like (there’s an extra charge)

Only if you’d like (there’s an extra charge) Add Block Storage: None

None Choose a Datacenter Region: New York 2

New York 2 Select additional options: None

None Add your SSH Keys: (Optional) Click New SSH Key and paste your SSH key here

(Optional) Click and paste your SSH key here How Many Droplets? 1 Droplet

1 Droplet Choose a Hostname: My Example Site

Once you’re selected the options above, click the big green Create button at the bottom of the page.

After about a minute, your new droplet will be created and ready to rock. It will also be assigned an IP address, which you can find on the droplet details page. Copy this IP address down and save it somewhere safe.

Domain Forwarding

Now that you have a droplet ready to go, you’ll need to configure your domain name so that it sends you over to your new server when you visit the site in your browser.

To do this, you’ll need to Add a Domain to your DigitalOcean account by clicking on the Networking menu item.

If you don’t have a domain name yet, I’d recommend Hover as a quick and easy way to purchase a new domain name and get it set up quickly.

There are 2 values you’ll need to enter for your new domain:

Domain: example.com (replace with your actual domain name)

example.com (replace with your actual domain name) Select a Workspace: You can change this or leave the default selected

Click Add Domain and take a swig of your beer (or water.)

Now, you’ll add an A record for your new domain to tell incoming traffic which droplet the domain is connected to.

Under Hostname, enter the @ character. Then, under Will Direct To, select the droplet that you just created. Finally, click Create Record.

Pushing to GitHub

If you’re not familiar with the concept of version control, now is a great time to get started. You’ll need to push your code up to your GitHub account so that Trellis can copy it over to your live droplet. GitHub also makes it easy for multiple developers to work on the same project at once.

Head on over to GitHub and create a new repository, making sure to uncheck the box next to “Initialize this repository with a README.”

Now, let’s add your WordPress site to GitHub using the CLI by entering the following commands, one by one:

cd ~/sites/example.com/site # replace the line below with your actual remote repository URL git remote add github git@github.com:example/example.com.git git push github master 1 2 3 4 5 6 cd ~ / sites / example . com / site # replace the line below with your actual remote repository URL git remote add github git @ github . com : example / example . com . git git push github master

If all goes well, you should see a message similar to the one below in your CLI:

Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 315 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) To git@github.com:example/example.com.git b17da4e..96a91c1 master -> master 1 2 3 4 5 6 7 8 Counting objects : 3 , done . Delta compression using up to 4 threads . Compressing objects : 100 % ( 3 / 3 ) , done . Writing objects : 100 % ( 3 / 3 ) , 315 bytes | 0 bytes / s , done . Total 3 ( delta 2 ) , reused 0 ( delta 0 ) To git @ github . com : example / example . com . git b17da4e . . 96a91c1 master - & gt ; master

Onward!

Configuring your Live Settings

Remember your Droplet IP Address from before? It’s time to put it to use. Copy that IP address, and then, back on your computer, open up the file located at trellis/hosts/production in your preferred text editor. In this file is where we’ll tell ansible to deploy all of our WordPress code.

# Add each host to the [production] group and to a "type" group such as [web] or [db]. # List each machine only once per [group], even if it will host multiple sites. [production] # Swap the line below with your *actual* droplet IP address your_server_hostname [web] # Swap the line below with your *actual* droplet IP address your_server_hostname 1 2 3 4 5 6 7 8 9 10 11 # Add each host to the [production] group and to a "type" group such as [web] or [db]. # List each machine only once per [group], even if it will host multiple sites. [ production ] # Swap the line below with your *actual* droplet IP address your_server _ hostname [ web ] # Swap the line below with your *actual* droplet IP address your_server _ hostname

Now we’ll configure our live site settings, just like we did with our development site settings earlier in this article. Open trellis/group_vars/production/wordpress_sites.yml in your preferred text editor.

subl ~/sites/example.com/trellis/group_vars/production/wordpress_sites.yml

We’re going to go through the same process with this file as we did with the group_vars/development/wordpress_sites.yml version, only, we’ll be a little more specific and secure about the settings we’re using here.

# Documentation: https://github.com/roots/trellis#wordpress-sites wordpress_sites: example.com: site_hosts: - canonical: example.com redirects: - www.example.com # enter the path to your website's Git repo repo: git@github.com:example/example.com.git # You'll also want to comment out the line below # since our code exists at the repository root folder on GitHub. # repo_subtree_path: site ... ssl: enabled: true provider: letsencrypt cache: enabled: true duration: 30s 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # Documentation: https://github.com/roots/trellis#wordpress-sites wordpress_sites : example . com : site_hosts : - canonical : example . com redirects : - www . example . com # enter the path to your website's Git repo repo : git @ github . com : example / example . com . git # You'll also want to comment out the line below # since our code exists at the repository root folder on GitHub. # repo_subtree_path: site . . . ssl : enabled : true provider : letsencrypt cache : enabled : true duration : 30s

We’ll also want to set more secure passwords and secret keys, which can be done by editing the vault file located at trellis/group_vars/production/vault.yml :

# set vault_mysql_root_password to something more secure # Documentation: https://roots.io/trellis/docs/vault/ vault_mysql_root_password: * GENERATE A SECURE, RANDOM PASSWORD HERE * vault_users: - name: "{{ admin_user }}" password: * GENERATE A SECURE, RANDOM PASSWORD HERE * salt: * GENERATE A SECURE, RANDOM SALT HERE * # Variables to accompany `group_vars/production/wordpress_sites.yml` vault_wordpress_sites: example.com: env: db_password: * GENERATE A SECURE, RANDOM PASSWORD HERE * # Generate your keys here: https://roots.io/salts.html auth_key: "generateme" secure_auth_key: "generateme" logged_in_key: "generateme" nonce_key: "generateme" auth_salt: "generateme" secure_auth_salt: "generateme" logged_in_salt: "generateme" nonce_salt: "generateme" # Any other custom environment variables can be defined below my_super_secret_api_key: "dont_tell_anyone" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # set vault_mysql_root_password to something more secure # Documentation: https://roots.io/trellis/docs/vault/ vault_mysql_root_password : * GENERATE A SECURE , RANDOM PASSWORD HERE * vault_users : - name : "{{ admin_user }}" password : * GENERATE A SECURE , RANDOM PASSWORD HERE * salt : * GENERATE A SECURE , RANDOM SALT HERE * # Variables to accompany `group_vars/production/wordpress_sites.yml` vault_wordpress_sites : example . com : env : db_password : * GENERATE A SECURE , RANDOM PASSWORD HERE * # Generate your keys here: https://roots.io/salts.html auth_key : "generateme" secure_auth_key : "generateme" logged_in_key : "generateme" nonce_key : "generateme" auth_salt : "generateme" secure_auth_salt : "generateme" logged_in_salt : "generateme" nonce_salt : "generateme" # Any other custom environment variables can be defined below my_super_secret_api_key : "dont_tell_anyone"

Connecting your GitHub Account

We’re nearing the end. Can you taste the victory?

We need to tell ansible about your GitHub account so that all of your code in your GitHub repo can be successfully copied over to your live server. Simple enough – open the file located at trellis/group_vars/all/users.yml in your preferred text editor.

subl ~/sites/example.com/trellis/group_vars/all/users.yml

This file tells Trellis which users should be authorized to perform certain actions, such as provisioning the live server, or deploying WordPress sites.

We’ll need to modify this file so that Trellis knows which GitHub usernames are allowed to communicate with your live server.

Change the contents of this file by modifying all of the lines that look like this:

# - https://github.com/username.keys

Uncomment the line (remove the # symbol) and replace the username in username.keys with your actual GitHub username (go figure).

Those lines should now look something like this:

- https://github.com/davekiss.keys

Tasty Provisions

Our hard work is done. Now it’s time to let the robot army take over and set up a professional live site environment with a single command. Enter the following command in your CLI to set up your droplet with all of the required software.

cd ~/sites/example.com/trellis && ansible-playbook server.yml -e env=production

Trellis and ansible will provide you with some feedback throughout this process so that you can see exactly what is going on. You can either watch and learn what it is doing, or, go have another beer. No really, it’s fine. I’ll drive.

Once completed successfully, your new droplet will be ready for your incoming WordPress site.

Deployment

As you proceed to make some awesome website code stuff, you’ll eventually want to push it out to your live droplet so that you can share your work with the world.

The first thing you’ll want to do is make sure that all of your latest and greatest code is up on your GitHub repository. You can do that by committing to your repository and pushing it to GitHub by issuing the same command that we did before:

cd ~/sites/example.com/site && git push github master

If everything looks good, we can launch your code over on your droplet by using this command in your CLI:

cd ~/sites/example.com/trellis && ./bin/deploy.sh production example.com

Visit your site and begin to cry tears of joy.

Success!

YES! BEER! You have a professional development environment all set up, and you’re paying $5 a month. Your new development process should now look like this:

write your code/tests and make sure everything works on example.local

commit your code to your repository and push it up to GitHub

when ready, send your code to your live server with ./bin/deploy.sh production example.com

rinse and repeat

Questions or comments? Use the comments below or hit me up on Twitter, @davekiss