- SQLite3 in php — some notes
- APCu in php — some notes
- php’s microtime() function
- In php, empty arrays are falsey, not truthy
- php composer, WordPress, and plugins
At the request of a user I configured the Index WP MySQL For Speed plugin to use php’s composer package manager for installation. That plugin has a mu-plugins component because it sometimes needs to intervene in core and plugin updates. Ordinarily, activating it puts the the code into the mu-plugins/ directory. But some WordPress installations want this done as part of setting up WordPress with composer.
This post covers some things I learned creating and testing that feature. This is my attempt to pull together a bunch of scattered lore about using WordPress with composer.
Packages and repositories
Most composer packages are available from the Packagist.org repository. That includes the package for WordPress core itself, which can be found at johnpbloch/wordpress.
All the themes and plugins published in the wordpress.org repository are mirrored as composer packages from the WPackagist.org repository. My particular plugin is at wpackagist-plugin/index-wp-mysql-for-speed on that repository.
WPackagist has a nice little feature, a refresh button. If you just updated a plugin or theme, you can get WPackagist to fetch the update immediately using that button.
Installing WordPress core with composer
Once you have installed php and composer on your system you can use composer to fetch the WordPress core files. To do that, first create a directory for the work.
Then, create a composer.json file in that directory. To just install WordPress and my plugin, it should look like something like this.
{
"name": "yourname/install-test",
"description": "Test project for WordPress stack via Composer",
"type": "project",
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org"
}
],
"config": {
"vendor-dir": "wp-content/vendor",
"allow-plugins": {
"johnpbloch/wordpress-core-installer": true,
"composer/installers": true
}
},
"require": {
"johnpbloch/wordpress": ">=6.8",
"wpackagist-plugin/index-wp-mysql-for-speed": ">=1.5.5"
},
"extra": {
"wordpress-install-dir": "wp"
}
}
Once you create the composer.json file issue the command composer install --prefer-dist and the files will be copied into the current directory. And, a composer.lock file is created, containing the actual versions of the packages and dependencies composer fetched. If you use npm, you’re familiar with the concept of a lock file.
Putting composer support into a plugin
Composer can install plugins (and themes) even if they don’t have any explicit composer support in them. But, if you need specific support you can put a composer.json file in your plugin, in the same top-level plugin directory where you put your readme.txt file. That composer.json file needs to be included in your .zip package. The composer.lock file does not, unless your plugin uses composer to satisfy its own dependencies.
The composer.json file for my plugin looks like this:
{
"name": "olliejones/index-wp-mysql-for-speed",
"version": "1.5.6",
"description": "Speed up your WordPress site.",
"type": "wordpress-plugin",
"license": "GPL-2.0-or-later",
"require": {
"php": ">=5.6.20",
"composer/installers": "*",
"ext-mbstring": "*",
"ext-ctype": "*",
"ext-json": "*"
},
"scripts": {
"install-mu-module": [
"mkdir -p ../../mu-plugins",
"cp code/assets/mu/index-wp-mysql-for-speed-update-filter.php ../../mu-plugins/"
]
},
"config": {
"allow-plugins": {
"composer/installers": true,
"johnpbloch/wordpress-core-installer": true
}
}
}
Notice that it contains a scripts block called install-mu-module. That’s the code that handles the mu-plugins code. This is the reason my plugin has a composer.json file, to define that script.
To get the script to work it is necessary to add a scripts block to your composer.json file. That block is
"scripts": {
"install-wp-mysql-mu-module": [
"@composer --working-dir=wp-content/plugins/index-wp-mysql-for-speed install-mu-module"
],
"post-install-cmd": [
"@install-wp-mysql-mu-module"
],
"post-update-cmd": [
"@install-wp-mysql-mu-module"
]
}
Testing
You can get composer to load modules from zip files on your own file system when you’re testing. I have a directory with a whole mess of files called things like index-wp-mysql-for-speed.1.5.5.zip in it. New versions, old versions, etc. By adding to the repositories block I can get composer to look in that directory. Here’s what it looks like, with a type of artifact and a URL with the file system path.
"repositories": [
{
"type": "artifact",
"url": "/home/ollie/src/"
},
{
"type": "composer",
"url": "https://wpackagist.org"
}
],
Credit
I used guidance from https://composer.rarst.net/recipe/site-stack/ to figure this out.
Great post! I’ve been using Index WP MySQL For Speed for a while now and it’s made a massive difference in my client site’s performance. It’s awesome to see you making it easier to manage through Composer.
For those of us moving toward a more ‘headless’ or automated deployment, do you see any issues with using this setup in a CI/CD pipeline (like GitHub Actions) to automate the plugin updates?
Thanks for the kind words.
Indeed, CI/CD is the point of the Composer support. I implemented Composer support for a user who wanted it to do CI/CD. But, CI/CD isn’t in my wheelhouse so I don’t know how to test it with this plugin and confirm it works right.
If you want to do that …. I would be grateful. Pull requests make my heart sing! https://github.com/OllieJones/index-wp-mysql-for-speed