September 27, 2015

WordPress Dependency Management

Recently I’ve been thinking a lot about WordPress and Composer (see my recent series on using WordPress with Git & Composer over on Delicious Brains) and how WordPress might implement dependency management at the core level. As more and more plugin developers start making use of Composer to manage their plugin dependencies this is going to become a bigger and bigger problem. Why?

Let’s start with an example

Say you have a WordPress site where you are using two different plugins (A and B) that both make use of the same package that has been installed via Composer. Each plugin will come bundled with the vendor/package folder which will then be loaded in each plugin via some code that will look like this:

if ( ! class_exists( 'ExamplePackageClass' ) ) {
    // load our class if it doesn't already exist
    include_once( dirname( __FILE__ ) . '/vendor/package/ExamplePackageClass.php' );

Great so far. However what happens when plugin B requires a higher version of the package? Plugin B will update the package in their plugin and ship it with the latest version of the plugin. The problem is that WordPress doesn’t know anything about the versions of the packages being included in each plugin. It will simply load ExamplePackageClass in whichever plugin it finds first.

This means that, if plugin A is found first, the older version of the ExamplePackageClass will be loaded and used for both plugin A and plugin B, possibly breaking things in plugin B. This is a problem.

So what do we do about it?

For dependency management to work properly there needs to be a single repository for all packages. As we’ve seen above, having multiple locations for Composer packages just doesn’t make sense. I think it would make far more sense if WordPress itself had a composer.json file with a single vendor location, either in the root folder or the wp-content folder.

We could then use the Composer Merge Plugin to read the composer.json files in each plugin and install the dependencies in the main vendor location, and not in each plugin folder. Packages could then be autoloaded (using PSR4 or equivelant) so that they would be available to use in all plugins (and themes).

You might be thinking “Great! Why don’t we just do this?”. This is the first step in the process, however we haven’t even fully solved the above problem yet.

The next steps

Two major problems still remain with the above proposed setup:

  1. What happens if there is a package version conflict (i.e. plugin A requires “ExamplePackage” v1.3.0 and plugin B requires “ExamplePackage” v2.0.0)? One of the plugins would need to be disabled and the user (site owner?) would need to choose which one it was. This means there would need to be a UI for package conflict resolution.
  2. How should WordPress handle package updates? Again if an updated package causes a conflict how would the user decide which plugin gets disabled?

Ryan McCue has written at length about how he see’s a solution being implemented and Coen Jacobs has even started to put together some initial proposals on GitHub.

Obviously this is a big topic and will be an even bigger undertaking to implement in WordPress. However I think this is a pressing problem that is only going to become more apparent as time progresses.

Looking for more?

Subscribe to my newsletter to get infrequent updates in your inbox. Or follow me on Twitter.