A modern Composer workflow with WordPress

Updated on 27th August with different methods for getting WordPress packages

This is a guide on how to incorporate a modern Composer workflow into your WordPress builds. This aimed at people who run WordPress websites as a service – typically bespoke theme developers who want to get a bit more out of WordPress as a tool.

This article prerequisites an understanding of Composer; Composer is a great PHP package manager so if you haven’t used it before give it a look. I won’t go into the specifics of how to use it or set it up as there are plenty of great guides on how to do that.

Composer by default installs it’s packages in /vendor/ and adds the contents to the PHP autoloader. When we want to install WordPress, that’s not so much what we want. This article should be useful for anyone that wants to install PHP packages that don’t necessarily follow the composer format.

fancyguy/webroot-installer

fancyguy has done a great job creating a composer plugin that installs specific composer packages into a predefined webroot, and then install packages of a defined type into specific locations – say for example WordPress plugins.

Webroot

In the extra section of our /composer.json file, webroot-installer allows us to install WordPress in a “webroot”. In actual fact, our webroot is going to be /web, but composer doesn’t need to know this – we want WordPress to be installed in /web/wordpress.

We can also define types of composer package that are installed into specific places. In this example we take every package with the type wordpress-plugin, and install them into /web/wp-content/plugins.

This means that if the only code being put into the plugins directory is from composer, we can gitignore the entire directory. And we can also gitignore WordPress itself. We can build ourselves into a situation where we commit nothing third party into our repository, other than the auto-generated code composer outputs to composer.lock.

WordPress core and private/paid plugins

Unfortunately there is no official WordPress package in Packagist yet, but there are efforts to get a composer.json into the codebase. There are a few options for this:

If we host our own, it’s easy with the aid of Satis. With Satis, we define our packages as if we were setting up custom repositories in a composer.json, and then Satis creates a fully fledged packages.json structure that we can point a composer.json to. It needs hosting somewhere, and you may want to pop HTTP Basic Auth on the top of it if you want to store private or paid plugins here too. This is what I do for including paid for plugins such as Gravity Forms or ACF-Repeater. Another option for a Satis repository for plugins is SatisPress, which is a very simple WordPress install, which allows for the self-updating features of private plugins.

The other alternative to setting up Satis is to point to a very simple raw packages.json maintained by yourself. At Carbon we have one of these on GitHub, however I wouldn’t recommend you use that one as there’s no guarantee it’ll be updated.

WordPress.org plugins

Another great tool in the arsenal to set this up is WordPress Packagist. WordPress Packagist is a Composer repository which mirrors plugins.svn.wordpress.org and themes.svn.wordpress.org. This means that every plugin and theme hosted on WordPress.org is available as a composer package. Take the slug of a plugin from the URL of it’s page (e.g. advanced-custom-fields from https://wordpress.org/plugins/advanced-custom-fields/) and use a * as the version number in our composer.json to get the latest stable version.

Project set up

This will be our directory structure when we're finished

This will be our directory structure when we’re finished

Now we can treat WordPress’s internal code like a black box, but now we need to communicate with it to instantiate WordPress.

This starts with our frontend controller that delegates requests to the WordPress code. This is exactly the same as WordPress’s frontend controller:

Note, we have full control over this; if we want to write our own PHP application next to WordPress, we can implement a router inside this file that only delegates certain requests to WordPress.

Thankfully, this sort of setup is not uncommon and WordPress knows this. By default, wp-load.php looks in the directory above itself if it cannot find a wp-config.php in the same directory. This means that we can place our wp-config.php outside /web/wordpress, and have our install point to a separate wp-content/ directory.

Take your normal wp-config.php file and replace the following defines:

This will let WordPress know where to find stuff in our new directory structure.

One final file you may need to set up is a wp-load.php file. Sometimes a plugin or theme may rely on the fact that it can include wp-load.php by saying  require __DIR__ . '/../../../wp-load.php'; , so you may need to set up something to bounce the requests back to /web/wordpress/wp-load.php, like so:

So that’s all there is to it. It should all function as a completely normal WordPress install, with the only caveat being that the admin is now loaded from http://yoursite.com/wordpress/wp-admin/. It’s useful to set up a 301 redirect from /wp-admin/ to /wordpress/wp-admin/ if any of your clients/users are quite used to WordPress.

Next I’ll write about how to incorporate PSR standard autoloading into your WordPress builds, and what advantages that can bring.

A quick thanks to Antti-Jussi Kovalainen who helped me figure out the loading of WordPress as a blackbox in his article WordPress as a submodule, and whose wp-config.php settings you’re seeing here.

6 thoughts on A modern Composer workflow with WordPress

    1. Of course. I should have written that as “official WordPress package”. I’ll include John Bloch’s repository in the article. I still have the same reservations as I have with other’s pointing to our packages.json … That said, the exact same can be said for WPackagist!

      Reply
  1. Pingback: How do you manage your dependencies in WordPress… | MotionBump

  2. Pingback: | Sawant Shah

Leave a Reply

Your email address will not be published.