Article Cover Image: Two children excited by something on a laptop screen

Dependency Management in WordPress Using Composer

What is dependency management?

Most software and web development projects are broken into components that rely on each other for the finished product to work properly, this may include 3rd party libraries and code. In WordPress, this is likely to be plugins or themes you are using for the project, either that you are making yourself or have gotten from a 3rd party like WordPress.org or theme forest.

These underlying components that your project utilises are called dependencies, and there is no guarantee that they will stay the same. As your project goes on, it is very likely that development on the libraries and plugins will continue, changing how they work, maybe breaking their interface with your work and hence breaking your project. These libraries will probably have more libraries that they depend on as well, you will need to install and manage those as well. So, we’ve got multiple layers of dependencies that, if not kept in sync, will break a project; and potentially affect multiple developers working on a project where they must all be using the same codebase for effective, efficient development.

Dependency management lets you specify what version of a library or plugin to install into a project so you know it will work. It will also install the dependencies’ dependencies plus the dependencies’ dependencies’ dependencies and so on. This lets you get new developers started on a project with all the correct files, libraries, modules, plugins etc from a single command, and provides a way of keeping all team members up to date on changes to the dependencies whenever they are made. It also lets you produce more modular code, as you can now more easily build reusable components inside their own project folders and reuse them later.

Let’s say you have a theme framework you drop into every project, your framework is under rapid development. You’re building project Alpha, a new WordPress site for the local dog rescue center. You use your framework to speed up the development. As you’re building the dog shelter’s theme, another developer is adding new features to the framework. Great, these new features make you even faster. You spend 10 minutes every day copying the new framework updates into your theme. A second developer joins you on the dog shelter project to help it get finished faster. You now both spend ten minutes a day updating the framework, most days. Sometimes you forget to do it, sometimes the other developer forgets and soon you have a mess of code that works with some versions of your framework and others that don’t. That’s going to take a while to redo and slow the whole project down.

If you had been using dependency management you could have updated the framework every day as part of the project. The updates would have been built in and saved you time every day. It could have forced you to use particular versions of the framework and then eventually, when the framework progressed to the point it didn’t make sense for you to keep using it, you could have set it to a particular version. Saving time and effort within the project.

Advantages of dependency management

  • Quickly add new developers to a project
  • Save time by having something automatically work out what needs to be installed for compatibility
  • Disaster recovery when something goes wrong
  • Improved code modularity and reusability
  • Enabled smarter automated deployments of your project

Okay, so how does this work with WordPress?

Unfortunately, and somewhat predictably, WordPress doesn’t make this easy for us but it can be done!

Meet Composer

Composer is the PHP dependency management program of choice. It is PHP’s answer to Bundler in Ruby and NPM for Node.js. Composer is a Command Line tool for managing dependencies built in PHP. It has two parts, the composer.phar – the executable, and composer.json – a JSON file that tells Composer what’s in your project and what to do with it.

In composer every project is called a package and a package can be installed into any other package.

For your package/project, Composer will let you define what other packages it requires to work and will install those packages for you, along with any packages that they require. By default, composer uses the http://packagist.com index of PHP packages to find what you need.

What are our dependencies?

This is where WordPress based projects start to vary a little from traditional PHP software projects that might use libraries and packages we will be using WordPress components.

  • Plugins – Functionality that the site requires, to work as expected.
  • Themes – The presentation layer of the site. Theme usually gets customised, so aren’t a great fit for being managed, but if you are using an out of the box theme or a parent theme it could be added to dependency management.
  • WordPress Core – WordPress itself

Because WordPress does not have internal dependency management for its codebase we do not recommend using Composer to build the dependencies of your plugin or theme (at least in the version that you ship). If you do this you could end up with WordPress trying to load two different versions of the same library and causing chaos.

Composer and WordPress

The first thing that we have to address is WordPress itself and your mental model about it – you are not building a WordPress site. WordPress is just a component of the software you produce, shouldn’t be edited by you, and because it is under active development with frequent releases, should be placed under dependency management.

Installing Composer

Run the following commands in your terminal window.


curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

You have now installed composer and moved it to you user/bin so the composer command is available globally on your computer, otherwise you’d have to install it into every project.

Creating a WordPress Project with Composer

You now have a Composer installed on your computer, let’s use it to install WordPress.
Unfortunately, WordPress isn’t a package for Composer, it lacks the necessary composer.json files, but that’s okay, Composer’s tools can help us out and we can work around that.

Create a new folder for the project on your computer and cd into it.


mkdir composer-wp  && cd composer-wp

Create a composer project with the composer init command. Composer will ask you a series of questions about your project such as Name, Description, Authors, Stability, License and Dependencies. Answer them all and decline the offer to create your dependencies interactively. Composer will generate a composer.son for you based on the answers you have given.


composer init

{
    "name": "stewart/composer-wp",
    "authors": [
        {
            "name": "Stewart Ritchie",
            "email": "stewart@poweredbycoffee.co.uk"
        }
    ],
    "require": {}
}

This is our default composer.son for our project, open it in your favourite text editor. We can now start to define our dependancies by adding WordPress.

As WordPress isn’t listed in the Packagist directory that Composer uses for getting project information, we must tell our local installation about it.

To the composer.son add a declaration “repositories” with the following attributes


"repositories": [{
    "type": "package",
    "package": {
    "name": "wordpress",
    "version": "4.2.2",
    "dist": {
        "type": "zip",
        "url": "https://github.com/WordPress/WordPress/archive/4.2.2.zip"
    },
 }]

Now we have told composer that we want to get the package “wordpress”. Lets tell it that we want to use it as well.

Edit the require statement in composer.json to include this line,


"wordpress": "4.2.2",

From terminal run the composer install command. Composer will now parse your composer.json and install WordPress for you


composer install

Provided everything went well and you set composer up correctly you should now have in your directory something like this.

Composer has created a directory, /vendor, installed its own dependencies in there and created a folder /wordpress where it has installed WordPress.

In our composer.json we have told Composer to look for new package by editing the repositories array. we have told it to add WordPress as a package, even though it doesn’t have its own composer.json. We then told Composer to install WordPress at version 4.2.2 into this project, which it did at /vendor/wordpress.

Thats good, but I don’t really want WordPress to be in /vendor/wordpress, I want it in /wordpress. We’re in luck – https://github.com/johnpbloch/wordpress-core-installer lets us choose where Composer installs WordPress.

Lets add the WordPress installer to our project. Our project depends on it in that we require it fro WordPress. Lets add it to the WordPress package as a requirement. Edit the WordPress package statement in composer.json to reflect.


{
        "type": "package",
        "package": {
            "name": "wordpress",
            "version": "4.2.2",
            "type": "wordpress-core",
            "dist": {
                "type": "zip",
                "url": "https://github.com/WordPress/WordPress/archive/4.2.2.zip"
            },
            "require": {
                "johnpbloch/wordpress-core-installer": "~0.1"
            }
        }

This will tell composer to install wordpress-core-installer. WordPress core-installer is a plugin for composer that lets us tell it where to install things should we for example not want to use /vendor. Tell composer where to install wordpress by adding the “extra” property to composer.json


"extra": {
        "wordpress-install-dir": "wordpress"
    }

What we’ve done here is added a new dependency to the WordPress package we created, `wordpress-core-install` and added a new declaration to composer.json – “extra” that will allow us to control what file path WordPress is installed to.

Update your composer.json and run `composer install`


composer install

You should now see WordPress has its own directory along site /vendor.

Installing WordPress Plugins and Themes using Composer

Okay, we have successfully installed WordPress core using Composer, what about adding those plugins and themes.

Just like WordPress-Core, very few plugins or themes have been created as Composer packages. We could set up every plugin or theme we wanted to use as a package within composer.json like we did with WordPress but that would get tiresome.

Fortunately, the team at Outlandish put their thinking caps on and came up with WordPress Packagist, a complete mirror of the WordPress.org Theme and Plugin repositories that injects Composer Package support into each plugin.

So, lets install some plugins.

First we need to add a declaration to or composer .json that tells it to use a new composer supported repository. Add the following to the top of your repositories array, just above the declaration about WordPress itself.


{
        "type": "composer",
        "url": "http://wpackagist.org"
    }

Now composer will search wpackagist for any packages you specify.

Add a plugin to your “require”: array.


"wpackagist-plugin/advanced-custom-fields": “*”

Run composer install again and you should be presented with this. Again, we have a problem through, the plugins have been installed to /wp-content/plugins.

As we can now rebuild the site anytime we want by running Composer it becomes even more important that we never change any file inside of WordPress. This is a problem as within the /wordpress directory we might want to install plugins and make changes to the wp-config file.

We can add another Composer plugin that lets us control where we install the plugins too. Add composer/installers as a requirement to composer.json


"composer/installers": “v1.0.6",

Add to the extra property the following object that controls where composer installs more general dependencies.


"installer-paths": {
            "content/plugins/{$name}/": ["type:wordpress-plugin"],
            "content/mu-plugins/{$name}/": ["type:wordpress-muplugin"],
            "content/themes/{$name}/": ["type:wordpress-theme"]
        }

When we install items from WPackagist they add a “type” declaration to the plugin of wordpress-plugin or wordpress-theme.

You’ll notice a bit of a strange problem now. We have our WordPress installation in /wordpress and our extras in /content. We would have to go to /wordpress to access our site but thats a bit ugly. Create a new file “index.php” in the root of your project containing the following.


// WordPress view bootstrapper
define( 'WP_USE_THEMES', true );
require( './wordpress/wp-blog-header.php' );

WordPress will look for wp-config up one directory from the bootstrap file. Copy the wp-config.pp file up a directory. Now we need to edit the file to tell WordPress that we aren’t using its normal file structure. WordPress has two constants that are useful here WP_CONTENT_DIR and WP_CONTENT_URL. Edit wp-config.php to reflect your new directory structure and content URL, edit your database credential at the same time.


define( 'WP_CONTENT_DIR', dirname( __FILE__ ) . '/content' );
define( 'WP_CONTENT_URL', 'http://' . $_SERVER['HTTP_HOST'] . '/' . CLIENT . '/content' );

Going to the root of our project will now load WordPress as you expect and allow you to install it.

To recap we have covered the basics of ..

  • What dependency management is and why its valuable
  • How to install the PHP dependency manager, Composer.
  • How to install WordPress into a custom directory using Composer
  • How to install Plugins & Themes using composer
  • How to move important files outside of WordPress to improve Git workflow.
  • How to move the wp-content directory outside of WordPress

Dependency management can be complicated when you get started but soon you’ll start to see the benefits of it when you integrate it fully into your workflow.

Stewart Ritchie Lead developer and founder of Powered By Coffee. Stewart has been building websites for 15 years and focusing on WordPress for 5. He founded Powered By Coffee in 2011 after finishing is masters degree. He lives in Guildford Surrey with his wife Sydney and their two cats.

Signup to our mailing list