“Democracy is the worst form of government except for all those other forms that have been tried.”
Winston Churchill, plagiarized
Composer for PHP is much like democracy, except for there are no others.
So I have always hated Composer, for many reasons. And my views on Composer are admittedly in stark contrast with many others who absolutely love it in the WordPress developer community. And there currently exist many articles on how to use Composer for WordPress developers.
My views, however, are not completely uncommon; there are at least a few others with whom I am aligned on opinions related to using Composer with WordPress.
Still, I use it for Composer with practically every WordPress project I have worked on in recent years simply because nothing better exists, and it is better than nothing.
And I have even created several open-source projects to support working with Composer, albeit mostly to address its many downsides.
So why do I dislike Composer for use with WordPress so much? Let me count the ways:
1. Ill-suited architecture assumptions
While Composer is good for projects using PHP frameworks like Laravel ((though it is still not great) , it sucks for WordPress as it is far too opinionated and its opinions don’t align well with WordPress’ architecture and use-cases.
2. Ignores WordPress’ target users
Composer is designed to be used by developers and/or devops to build all the dependencies for a PHP project into a complete solution prior to deployment to a web server (in a website context, of course, which is what compares to WordPress.) This is in stark contrasts with how WordPress was designed to be used as WordPress allows end-user administrators to download, install, activate, deactivate and uninstall and delete plugins and themes throughout the hosted life of the site.
3. Requires non-standard directories
For Composer to compose WordPress core, you cannot use WordPress’ standard directory layout with WordPress files and directories like wp-load.php
, wp-admin
, wp-includes
and wp-content
all in the webroot. Instead you must move WordPress to its own subdirectory, except for wp-content
which cannot be in the same subdirectory as the rest of WordPress.
Here is one example layout, and is the layout I have used in client projects for years.
To be fair, this is a WordPress problem not really a Composer problem, but when used together it becomes a problem of using Composer with WordPress.
Managed WordPress hosts frequently “dislike” non-standard layouts
The upshot is many managed WordPress host assume the standard directory structure, and which in most places you can change them doing so is swimming upstream, if not impossible. Which means you need to have a build solution which can transform your layout for deployment, and it means your production site will be running a subtly different layout from your local development (you do develop locally, right?)
More plugins and themes have bugs with “non-standard” WordPress
Further — and to be fair I have not seen this as often — but plugins which were not tested with a non-standard layout can occasional exhibit subtle or even overt bugs which running in a non-standard environment.
Chalk this to up mostly annoyance, much like the annoyance produced by developers who write plugins and themes with WP_DEBUG
set to false
. But I digress…
4. PSR-1 / PSR-4 no good for WordPress
Further, Composer assumes use of a PSR-1 or PSR-4 autoloader, which is not aligned with WordPress’ architecture, an architecture that expects plugins and themes to be self-contained entities. Composer on the other hand wants to install all PHP classes in a /vendors
directory, which what PSR-1 and PSR-4 expect and thus what Composer supports.
This unfortunately means that none of the classes in WordPress core, the theme, or any of the plugins can be autoloaded via the autoloader.php
file Composer generates.
5. Plugins and themes duplicate autoloader
Compounding the issue is when a plugin and/or theme developer chooses to use use PSR-1 or PSR-4 to autoload the classes in their projects, they are contributing to a convoluted and inefficient class autoloading scheme for any sites that use their plugin or theme.
The autoloader.php that Composer generates can easily run 10 or 20 or more lines of code for each and every class it attempts to autoload. If your website has 25 plugins each of which that use a Composer autoloader then every time a new class need to be loaded your site might run upwards of 250 lines of code or more — and with lots of time consuming file_exists()
checks — every time it needs to load a new class. On each page load.
Not to speak of the PITA it can be to try and use XDEBUG to work on a site that has so many PSR-1 / PSR-4 autoloaders.
This, IMO, is madness.
6. Unfortunate composer.json
prerequisite
Besides the runtime issues with Composer, there are many issues with just using it. One of the worst things about using Composer is that every dependency is required to have its own composer.json
file that defines the dependency, instead of just assuming a logical set of defaults for dependencies where the file is not included.
You can’t compose without a composer.json
The upshot is you cannot use Composer to “compose” any dependency which was not explicitly prepared to be used with Composer.
You can’t compose from wordpress.org
And perfect examples are every plugin and theme available for download via wordpress.org; they cannot be composed from their repo URLs with Composer because very few have composer.json
files included.
You can’t compose most repos from github.org
Another example are WordPress plugins and themes hosted on Github. From what I have witnessed at best about only one (1) in five (5) of these plugins and themes are packaged with a composer.json
file.
At the time of this writing, googling for “site:github.com wordPress plugin
” resulted in seven (7) links to actual WordPress plugins of which only two had composer.json
files. (And given that so many WordPress developers call using Composer a “best practice” I would has assumed better adherence for the plugins listed on Google’s first SERP.)
Worse, in my experience getting most any of those developers to acknowledge a simply pull request to add a composer.json
file let allow accept it is an exercise in futility most of the time.
Yes WPackagist exists for wordpress.org plugins…
Fortunately for those using Composer with WordPress there is the intermediary WPackagist.org which adds the necessary composer.json
file to WordPress.org’s plugins and themes.
WPackagist was set up by Outlandish and from what I have witnessed most WordPress developers who use Composer have projects that depend upon WPackagist.
…though not for GitHub plugins or themes…
Unfortunately though, WPackagist does not help for any of those plugins on GitHub without a composer.json
.
…and what happens if WPackagist goes away?
Which brings up a very interesting concern. What happens to all those project using Composer that has their dependencies pointing to WPackagist when Outlandish gets tired of funding the free WPackagist service?
Or what happens it Outlandish gets acquired, and its new owners do not see the value in continuing to fund this endeavor?
7. Configuring composer.json
a nightmare
Configuring a working composer.json
is not for the faint of heart. When I originally tried to use Composer — probably around seven (7) years ago — I continued revisiting it for months before I was finally able to get a composer.json
file that worked for one of my project.
You must fight Composer to write dependencies where they need to be
The first issue was trying to get Composer to work with the directory structure needed by WordPress, specially trying to get plugins and themes to be placed in their respective directories. Because the defaults Composer assumes, you must duplicate dependency info with a non-obvious syntax in order to achieve a working composer.json
file to place plugins and themes correctly, and especially for placing plugins in the /mu-plugins/
directory.
Duplication, thy name is Composer
The next issue is that Composer loves to force you to duplicate information, as I alluded to above.
In a composer.json
file if you have a dependencies hosted in a Git repository you need to specify not only the dependency in a "require"
section but also list the Git URL in a "repositories"
section, and for WordPress must-use plugins you also have to reference in a "extra"
section.
Not only is this tedious and annoying, it is also error problem, and difficult to figure out if you do not have a lot of experience with Composer.
Version constraints giveth, and they taketh away
The final issue here is that Composer supports what they call “version constraints” which are implemented using a very terse and impossible to memorize syntax, at least for me. And it is not like I have not tried.
The problem with version constraints, especially when you are trying to set up a working composer.json
file the first time for a project is that you can easily create one that Composer won’t work with, and the error messages are so cryptic as to be peak the blood pressure of even the calmest of individuals.
Yes you can figure it out, but should it be this hard?
Sure, after you spend an inordinate amount of time learning how Composer works these become less problematic. But then consider if you add someone to your team who has not already spent that time to learn Composer your organization will likely have to pay for them to generate enough experience for them to get past these kind of issues with Composer, too.
The Emperor has no clothes
(As I wrap up this post I feel I have forgotten to include at least one addition significant point, but at the moment I can’t think of it. If I do think of something else, I will probably amend this point to include it later.)
Anway, based on all the above — in my opinion — there is simply too large of an impedance mismatch for Composer to be considered a great tool for working with WordPress.
But what else can are we as WordPress developers to do? Time will tell I guess…
Thanks for your article. I’m currently working with an existing WordPress plugin project that uses Composer and have been feeling quite moronic over my struggles to get the plugin capable of running unit tests.
I’ve done it a million different ways, posted questions on SO, overcome one obstacle only to immediately run into another…and it isn’t done yet…but now at least, I know I’m not just being obtuse (right? :)).
@Dave Mackey,
Absolutely. IMO it is Composer that is obtuse, not you!
Incredible points. Sound arguments. Keep up the great work.
@Sheron Dienhart — thanks.
I hate composer. I hate that so much relies on it. And I hate that it wants to load everything all at once. I only need to load HTML2PDF at very specific times, it doesn’t need loading everytime a page opens
You are so right. The worst part it’s a huge memory hog and will frequently not work due to running out of memory.