How to install Wordpress as a dependency in your project, without including the WP install in version control.
In the spirit of The Twelve Factor App, we want to "explicitly declare and isolate dependencies". Wordpress doesn't really promote this idea out of the box, so we have jump through a few hoops to do it. This document describes a simple method to include Wordpress as a dependency in this way.
We'll define and manage WP as a dependency using Composer. We also want to keep Wordpress out of version control (because it's a dependency). The things we do want to keep in version control will likely be the theme or plugin we're creating. The default Wordpress directory structure doesn't lend itself to keeping these two things separate, since the wp-content
folder (where themes, plugins, etc. live) is actually inside the Wordpress install folder.
We could simply make a build script to create symbolic links to our theme, plugin, etc. However, we would need to manage these links when deploying, updating, etc. and it would end up being a bit of a pain. The good news is that Wordpress allows us to host the wp-content
folder in a separate folder than the default. In this way, we can install Wordpress in its own folder, which we tell our version control system to ignore, and host our project code in its own folder that our VCS tracks.
This is what the directory structure of your web folder will look like, after following the steps below.
composer.json
index.php
wp-config.php
/content # plugins, themes, etc.
/wp # this is where Wordpress is installed
-
Create
composer.json
in the web folder of your project:{ "repositories": [ { "type": "package", "package": { "name": "wordpress", "type": "webroot", "version": "4.5.2", "dist": { "type": "zip", "url": "https://wordpress.org/wordpress-4.5.2.zip" }, "require" : { "fancyguy/webroot-installer": "1.0.0" } } } ], "require": { "php": ">=5.5.0", "wordpress": "4.5.2", "fancyguy/webroot-installer": "1.0.0" }, "extra": { "webroot-dir": "wp", "webroot-package": "wordpress" } }
This tells Composer to install Wordpress in the
wp
folder (relative tocomposer.json
). -
Install Wordpress:
$ composer install
To update Wordpress, you would just change the version number in
composer.json
and runcomposer update
. -
Since Wordpress is installed in the
wp
folder, we need to copyindex.php
out of it, and into the same folder ascomposer.json
. This will allow Wordpress to load itself.$ cp wp/index.php .
-
We also need to make one small change to
index.php
, to includewp-blog-header.php
from thewp
folder. The entireindex.php
can look like this:define('WP_USE_THEMES', true); require( dirname( __FILE__ ) . '/wp/wp-blog-header.php' );
I like to keep
index.php
in version control, since it's actually specific to my project (it's not the sameindex.php
file as the one installed by Wordpress). -
Create a folder named
content
in the same folder ascomposer.json
. This is where your themes, plugins, etc. will go. Initially, it's easiest to just copy thewp-config
folder from the Wordpress install.$ mkdir content
OR
$ cp -R wp/wp-content ./content
If you create the folder by copying from Wordpress, be sure to delete any themes or plugins you don't want in your project.
-
At this point, we need to configure Wordpress and tell it where our content folder resides and where Wordpress is installed. We don't want our
wp-config.php
file to be clobbered every time we update Wordpress, so we need to move it out of thewp
folder and into the same folder ascomposer.json
.$ cp wp/wp-config-sample.php ./wp-config.php
Wordpress is smart enough to find it here.
Remember to tell your version control system to ignore
wp-config.php
since system-specific configuration should not be tracked in version control. -
Now, edit
wp-config.php
and set the following constants, to tell Wordpress where the content folder is and where Wordpress is installed:ABSPATH
,WP_SITEURL
,WP_HOME
,WP_CONTENT_DIR
, andWP_CONTENT_URL
. I've found it useful to create aHELPER_BASE_URL
constant and use it for the web-related constants. For example:define('HELPER_BASE_URL', 'http://localhost'); // no trailing slash if ( !defined('ABSPATH') ) define('ABSPATH', __DIR__ . '/wp/'); // trailing slash define('WP_SITEURL', HELPER_BASE_URL . '/wp'); define('WP_HOME', HELPER_BASE_URL); define('WP_CONTENT_DIR', __DIR__ . '/content'); define('WP_CONTENT_URL', HELPER_BASE_URL . '/content');
With this configuration, I only need to change the
HELPER_BASE_URL
constant. Everything else is defined using other constants.Of course, you still need to set all of your other Wordpress configuration stuff.
-
Now you can have Wordpress install itself in the database. The admin area URL is e.g.:
https://yourprojecturl.com/wp/wp-admin
-
That's it!
After going through the steps above, to install Wordpress again on another machine, all you have to do is:
-
Clone your repo.
$ git clone path/to/myproject.git $ cd myproject
-
Install Wordpress.
$ composer install
-
Set up
wp-config.php
$ cp wp/wp-config-sample.php ./wp-config.php $ vim wp-config.php
-
Install the database at e.g.
https://yourprojecturl.com/wp/wp-admin
If you want to automate the installation of Wordpress into the database (e.g. as part of an automated build process), you can use a great tool called WP-CLI. After you install wp-cli
(when I install it, I name the executable wp
), you can run some commands like this:
$ wp core install --path=./wp --url="<base url to site>" --title="Site Title" --admin_user=<username> --admin_password=<password> --admin_email=<email>
$ wp option update blogdescription ""
$ wp option update permalink_structure "/%postname%/"
$ wp option update timezone_string "America/Los_Angeles"
$ wp option update start_of_week "0"
This example has some options that I like, but you can set any Wordpress options you want using these commands.
Setting up Wordpress using a build script like this has a few advantages:
- It saves you the trouble of manually going into the Wordpress admin area and installing Wordpress into the database.
- You don't need to remember all of the options you want to set.
- It keeps you from making mistakes or forgetting something, since the setup is automated.
- A script like this serves as documentation of your setup process. If you ever forget how your site is set up, just look at your build script.
If you want to add wordpress.org plugins/themes as dependencies in composer.json
, check out https://wpackagist.org/. It manages wordpress.org plugins/themes as a Composer repository.
To add private/third-party plugins to composer.json
, check out WordPress Plugins with Composer.