Using Composer with WordPress

This post will give you an introduction to Composer and how to manage WordPress core, plugins, and even themes with it. If you already know what Composer is and how to use it and just want to see how to integrate it with WordPress, you can skip straight to the The Solution section below.

Our WordPress project boilerplate, Bedrock, uses Composer for dependency management.

Intro to Composer

Composer is a dependency manager for PHP that has been gaining steam lately. Your first question is most likely “what is a dependency manager and why do I need one?”. Almost any code you write probably ends up depending on 3rd party libraries. All of these libraries (projects, frameworks, files, etc) become dependencies of your project. Composer lets you declare the dependencies for a project and it will install and manage them.

If you’ve used npm for node.js, Bundler for Ruby, or pip for Python, then you’ve already used a dependency manager.

All these tools deal with packages. Every dependency is also a package. What constitutes a package? It can be a local file, local folder, remote zip, local Git repository, remote Git repository, GitHub repository, etc. Most dependency managers also include a global registry of available packages. For Composer, this is Packagist. To get an idea of what kind of packages are available, just browse through Packagist.

I’ll do my best to explain some Composer concepts throughout this post, but the official Composer docs are quite accessible as well. It’s recommended to read them to get a full understanding of Composer.

Installation

Installing Composer is pretty simple with one caveat: It requires PHP 5.3. Follow the instructions for either *nix or Windows.

I suggest installing Composer globally and then you can just use the composer command from anywhere.

Usage

Seeing Composer in action usually solves most of the confusion you might have after reading about dependencies and packages. Let’s go through the most basic example of installing a single dependency to an empty project.

In this case our project is just an empty folder to start with:

$ mkdir composer-example
$ cd composer-example

For Composer, you declare your dependencies in a composer.json file. Create one with the following JSON:

{
  "require": {
    "twig/twig": "1.18.0"
  }
}

For this example we’re only declaring one dependency: Twig, the popular PHP templating engine. Note that every package name includes its vendor name as well for namespacing purposes. In this case they’re both the same.

The next thing to notice is that we also declare what version of the Twig package we want. We’re using the latest 1.18.0 which can be found at https://packagist.org/packages/twig/twig.

Only thing left to do is to actually install our dependencies:

$ composer install

And you’ll get the following output:

Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing twig/twig (1.18.0)
    Loading from cache

Writing lock file
Generating autoload files

Let’s list out some folders to see what actually happened:

$ ls
composer.json composer.lock vendor
$ ls vendor
autoload.php composer twig

We can see that Composer created a vendor/ directory that contains the twig package.

You might be wondering about the new composer.lock file that was generated. The official Composer docs explain it nicely:

After installing the dependencies, Composer writes the list of the exact versions it installed into a composer.lock file. This locks the project to those specific versions.

Advantages

You might still be wondering what’s the point in using Composer and going through all the work above. Composer (and any dependency manager for that matter) has many advantages:

  • your dependencies are explicitly declared in a single place
  • installing and updating is handled by the tool
  • your project is locked onto specific versions
  • you don’t need to include the actual 3rd party code in your version control repository

The last one is huge. Without a dependency manager, you’re stuck doing one of two things:

  • adding the entirety of a 3rd party library into your VCS repo
  • using something like Git submodules

This means that when you’re using Composer, you check the following files into your repository:

  • composer.json
  • composer.lock

That’s it. Add vendor/ to your .gitignore and let Composer handle it. Now whenever wants to setup your project, they just run the standard git clone followed by composer install.

Integrating with WordPress

Finally we’re ready to talk about how you use Composer with WordPress. When you think about a typical WP site, the easiest example of dependencies are plugins. But there’s something more fundamental to realize: WordPress itself is a dependency.

If you think about it, you’re creating a site, or application, that depends on WordPress. The WordPress core is a 3rd party library that is required for your application to work. This is difficult to understand at first due to how WordPress sites are usually structured:

index.php
license.txt
readme.html
wp-activate.php
wp-admin
wp-blog-header.php
wp-comments-post.php
wp-config-sample.php
wp-content
wp-cron.php
wp-includes
wp-links-opml.php
wp-load.php
wp-login.php
wp-mail.php
wp-settings.php
wp-signup.php
wp-trackback.php
xmlrpc.php

You’re probably familiar with the above folder structure. The WordPress core files are in your project’s root directory. wp-content/ actually contains all your application specific code like your theme and plugins.

Thankfully most people realized this wasn’t a good idea and putting WordPress in its own subdirectory has become a common practice. It might look like this:

wp-content
index.php
wp
wp-config.php

A further improvement was including WordPress as a Git submodule. WordPress-Skeleton is a popular example of this. Your folder structure looks the same as above, but at least your wp/ folder isn’t part of your main repository since it’s a separate submodule.

Since you’re reading an article about Composer, you’ve probably realized that Git submodules aren’t the proper way to deal with dependencies either.

The good thing about the above structure becoming popular is that it’s not much different with Composer. In fact, your WP folder structure can be identical. It’s just a matter of using Composer to install WordPress to wp/ rather than using a Git submodule.

How To

There’s a few issues to deal with in order to get Composer to install WordPress to wp/ and achieve the structure we had above.

As you saw in our simple Twig example, Composer installs all dependencies to vendor/. Unfortunately, this won’t work for WordPress since it needs to be our root directory (WP will only look for wp-config.php in its own directory or one directory up limiting its location).

A regular Composer package can only be installed in vendor/. You can’t pick and choose where you want each package installed to in your project.

Of course there’s a workaround otherwise this post wouldn’t exist. Composer by default doesn’t let you override a package’s install path, but Composer has plugin packages that can define their own install paths which is exactly what we need.

Here’s a WordPress Core Installer package which would let us configure the install path like this:

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

Problem solved right? We can just implement the wordpress-core-installer package and we’re good? Unfortunately the biggest issue remains:

WordPress itself doesn’t have a composer.json file so it’s not a Composer package yet.

There’s been a very long discussion about adding a composer.json file to WordPress but it hasn’t happened yet and isn’t likely to anytime soon.

The Solution

The best solution right now is to use a “fork” of WordPress with composer.json already added. https://github.com/johnpbloch/wordpress is currently the most popular/accepted package.

It’s simply an auto-updating fork (syncs every 15 minutes with the official WP repo) that includes composer.jsonwordpress-core-installer package. You can view it here.

Now we can finally get to the working composer.json file that we need:

{
  "require": {
    "php": ">=5.4",
    "johnpbloch/wordpress": "4.2"
  },
  "extra": {
    "wordpress-install-dir": "wp"
  }
}

That’s it. We just require johnpbloch/wordpress with the version of WordPress that we want and then tell Composer we want WordPress installed to wp.

Installing

Now that we have our working composer.json file, let’s actually install WordPress. Once again, run composer install. Here’s what you should see:

Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing johnpbloch/wordpress-core-installer (0.2.0)
    Downloading: 100%

  - Installing johnpbloch/wordpress (4.2)
    Downloading: 100%

Writing lock file
Generating autoload files

And our resulting directory looks like:

$ ls
composer.json composer.lock vendor wp

At this point, we need to follow the instructions about giving WP its own subdirectory found here. Once that’s done, our project should look like this:

wp-content
index.php
wp
wp-config.php

And we’re back to what we originally wanted. Only 1600 words later.

More on Packages

I said earlier that all packages are installed to vendor/ unless they use another plugin package to allow overriding. Before we used one specifically for WordPress core, but there’s another more general one which defines more package types and install paths: composer-installers.

composer-installers lets a package specify its type and a custom install location. They have a few types already included that we care about:

  • wordpress-plugin => wp-content/plugins/{$name}/
  • wordpress-theme => wp-content/themes/{$name}/
  • wordpress-muplugin => wp-content/mu-plugins/{$name}/

So any package with a type of wordpress-plugin will get installed to wp-content/plugins/{$name}/ by default.

Plugins

So we’ve got WordPress installed and now we want to add some plugins. Thanks to composer-installers we can install them in the proper location right?

Yes, but we’re limited to plugins that have a composer.json, require composer-installers AND have their package type set correctly. Obviously there aren’t many plugins that actually do this yet. But you can find an example here.

Let’s add that to our composer.json from before (only showing the requires section):

"require": {
  "php": ">=5.4",
  "johnpbloch/wordpress": "4.2",
  "fancyguy/wordpress-monolog": "dev-master"
}

After running composer install, you’ll see that wordpress-monolog was installed to wp-content/plugins/wordpress-monolog.

WordPress Packagist

Fortunately, the awesome people at Outlandish have created a repository of WordPress plugins called WordPress Packagist.

This site provides a mirror of the WordPress plugin directory as a Composer repository.

Basically, they mirror every WordPress plugin and add a composer.json file that requires composer-installers and sets their package type to wordpress-plugin.

Their instructions are simple too:

  1. Add the repository to your composer.json
  2. Add the desired plugins and themes to your requirements using wpackagist-plugin or wpackagist-theme as the vendor name.
  3. Run $ composer update
  4. Plugins are installed to wp-content/plugins/ or wp-content/themes/

Our composer.json will look like this now after adding some plugins:

{
  "repositories": [
    {
      "type": "composer",
      "url": "http://wpackagist.org"
    }
  ],
  "require": {
    "php": ">=5.4",
    "johnpbloch/wordpress": "4.2",
    "fancyguy/wordpress-monolog": "dev-master",
    "wpackagist-plugin/advanced-custom-fields": "*",
    "wpackagist-plugin/posts-to-posts": "1.4.x"
  },
  "extra": {
    "wordpress-install-dir": "wp"
  }
}

It took a lot of work to get here, but if you look at the composer.json above, it’s actually pretty simple and self explanatory.

Get the Screencast $12

Topics Covered

This screencast gives an in-depth introduction to dependency management in PHP using Composer and more importantly, why you should use it with WordPress.

You’ll learn all the basics from the start which will let you manage your WordPress install and plugins with Composer. Learn how Composer will make development more reliable, help with team collaboration, and how it helps maintain a better Git repository.

  • Intro to Composer
  • Basic installation and Usage
  • Retrofitting a Legacy Project
  • Composer Concepts
  • Custom Installers
  • Integrating WordPress
  • Usage with Git
  • Managing Plugins

Preview & More Info

  • Length: 50 min
  • No DRM – H264, AAC, 720p
  • 613 MB

Get our latest updates & occasional tips on building better WordPress sites

Follow @rootswp on Twitter