Using Composer with WordPress

How and why you should use Composer to manage your dependencies for WordPress.

This tutorial will give you a brief introduction into Composer and how to use it with WordPress.

What is Composer?

ComposerComposer is a dependency management tool for PHP. A dependency is a separate library or package which your project relies on – in the context of WordPress project these are going to be plugins and themes (most of the time). In fact, WordPress itself is a dependency for your project.

Each time you add a new plugin or theme (a dependency) to your project, Composer makes a record of that dependency and the version of the dependency. This allows us to move our project between different hosting environments safe in the knowledge that each instance is using the same dependencies of the same version.

Installation

Before we can begin, we need to install Composer. Composer requires PHP 5.3.2+ to run and can be installed for both Linux / Unix / macOS or Windows. You will need to install Composer on both your development and production servers.

For the purposes of this tutorial, I am going to assume you have installed Composer globally.

Packagist and WordPress Packagist

Before we can get started, it is worth introducing Packagist. Packagist is the main Composer repository. It aggregates public PHP packages and makes them installable with Composer. I like to think of Packagist as the “Yellow Pages” (a very large telephone book for the sake of the young-ens) for dependencies. Each time we request a dependency via Composer, it will request from Packagist where the source code can be found and what versions are available.

Usually when we create a new package it would be up to us as the package maintainer to submit it to Packagist. This would then allow anyone using Composer to install our code via Composer. For a package to be compatible with Packagist, the source code needs to include a valid composer.json file.

As it is, theme and plugin developers have no obligation to create their themes and plugins with a composer.json file or submit it to Packagist. Fortunately for us, there is WordPress Packagist which mirrors the WordPress plugin and theme repository and makes them available to Composer.

Creating composer.json

From the root of your project directory – this should not be inside your document root (or public directory). Create a new file called composer.json.

Inside this file you will be adding JSON code. JSON stands for JavaScript Object Notation and is a lightweight format for storing or transferring data.Quick Tip It is not possible to have comments inside your composer.json. It is not part of the standard and therefore will result in an error when Composer tries to read your composer.json file.

As a PHP developer, the JSON syntax should be reasonably familiar to you as a multidimensional associative PHP array. Everything inside the composer.json file should be encapsulated inside curly braces.

The composer.json file is made up of several sections which we will go over now.

Repositories
{
    "repositories": [{
        "type": "composer",
        "url": "https://wpackagist.org"
    }]
}

Firstly, we need to define where our dependancies can be found. Because we are dealing with WordPress, we need to point it to the WordPress Packagist. You can define more than one, but for our purposes, this is sufficient.Quick Tip Composer is by default already configured to use Packagist and therefore does not need to be defined.

Require
{
    "repositories": [{ 
        ... 
    }],
    "require": {
        "php": ">=7.3",
        "composer/installers": "^1.7",
        "johnpbloch/wordpress": "^5.3",
        "wpackagist-plugin/advanced-custom-fields": "^5.8",
        "wpackagist-theme/twentynineteen": "^1.4"
    }
}

This is where we define our dependencies. Firstly I define that I am using PHP and I want to make sure its at least version 7.3 or greater. While PHP isn’t a Composer package, it is a dependency on our project. Composer will error when our environment does not meet this dependency.

The following 4 dependencies are Composer packages and the syntax of them is as follows "<vendor>/<package-name>": "<acceptable-version-constraint>".

By default, all composer packages are installed into a folder called vendor. The package composer/installers allows us to define custom locations as defined below in the extra section.

As previously mentioned, WordPress is a dependency on our project and we include it by referencing johnpbloch/wordpress. While johnpbloch isn’t the author of WordPress, they have synced the WordPress repository in order to make it compatible with Composer.

Next we have an example plugin and theme as a dependency. Because WordPress Packagist is simply mirroring the WordPress repository and the vendor names (the package author) has not been defined, WordPress packagist will always define the vendor name as wpackagist-plugin or wpackagist-theme.

The plugin wpackagist-plugin/advanced-custom-fields provides a user friendly user interface for editing post meta.

The theme wpackagist-theme/twentynineteen is the latest theme to be shipped with WordPress.Quick Tip The composer.json file is not sensitive to whitespace – meaning it will still work if not indented correctly. That being said, keep it indented correctly and it will make it a lot easier to read and maintain.

Require Dev
{
    "repositories": [{ 
        ... 
    }],
    "require": {
        ...
    },
    "require-dev": {
        "wpackagist-plugin/debug-bar": "^1.0",
        "wpackagist-plugin/monkeyman-rewrite-analyzer": "^1.0"
    }
}

Typically when I am building a website, there is a handful of plugins that I find useful during the build but I do not want to install on the production server. You can define these plugins here.

The Debug Bar, when active, adds a debug menu to the admin bar that shows query, cache, and other helpful debugging information.

The Monkeyman Rewrite Analyzer is a tool to understand your rewrite rules. It is indispensable if you are adding or modifying rules and want to understand how they work (or why they don’t work).

Extra
{
    "repositories": [{ 
        ... 
    }],
    "require": {
        ...
    },
    "require-dev": {
        ...
    },
    "extra": {
        "wordpress-install-dir": "public/wordpress",
        "installer-paths": {
            "public/wp-content/mu-plugins/{$name}/": ["type:wordpress-muplugin"],
            "public/wp-content/plugins/{$name}/": ["type:wordpress-plugin"],
            "public/wp-content/themes/{$name}/": ["type:wordpress-theme"]
        }
    }
}

Usually when we install packages via Composer, it will place all the code inside a vendor folder. This vendor folder for security reasons should never be inside the public directory. Because we are dealing with WordPress and WordPress relies on a particular directory structure, we need to tell Composer where to install our plugins and themes.Quick Tip This tutorial assumes your document root is in a folder called public (historically this has been called public_html). Rename all occurrences of public if you use something else.

Config
{
    "repositories": [{ 
        ... 
    }],
    "require": {
        ...
    },
    "require-dev": {
        ...
    },
    "extra": {
        ...
    },
    "config": {
        "sort-packages": true
    }
}

And the last thing I would add which isn’t technically needed but helps to keep things pretty is telling Composer to record our package names alphabetically inside the require directive. It just helps to keep things more readable and therefore maintainable.

From the blog

Contact me