Support for Composer Autoloading w/ Custom Fallback

Because it’s a part of my every day workflow, I spend a lot of time thinking about WordPress. And, because I think there are lots of ways that the WordPress codebase could improve from an architectural perspective, I also spend a lot of time paying attention to how other open-source PHP projects are structured. Lastly, because a lot of my day-to-day work involves custom plugin development for WordPress, I think about ways to make things better organized, more streamlined, and easier to follow along so that, when I come back to those projects months or years later, I can easily pick back up right where I left off.

There are a few things I find particularly interesting from a plugin development perspective, and those things are dependency management, plugin structure, plugin bootstrapping, and class autoloading.

I wrote a bit about how I like to approach plugin development a few months ago. At the time, I’d only really considered using Composer’s autoloader – if I was submitting a plugin to the WordPress repository or had plans to otherwise make that plugin available on sites that didn’t use a Composer-based install, my approach was to version control the vendor directory and ship it with the plugin.

In many cases, I still feel that using Composer’s autoloader is the best way to go, because it alleviates the need to write your own custom autoloader for every single project. That said, this week, I had a situation come up where I was forced to implement my own autoloader, and it gave me an idea. Let’s examine.

Here’s an example plugin bootstrap file:

<?php
/**
 * Plugin Name: WP Plugin Starter
 * Description: A boilerplate project to quickly scaffold up new WordPress plugins.
 * Author: Jeremy Ward
 * Author URI: https://jmichaelward.com
 * Version: 0.1.0
 *
 * @package JMichaelWard\WPPluginStarter
 */

namespace JMichaelWard\WPPluginStarter;

if ( ! class_exists( 'JMichaelWard\WPPluginStarter\Plugin' ) ) {
	try {
		require_once plugin_dir_path( __FILE__ ) . 'src/autoload.php';

		spl_autoload_register( __NAMESPACE__ . '\autoload' );
	} catch ( \Throwable $e ) {
		// @TODO Implement actual error handling.
		return;
	}
}

add_action( 'plugins_loaded', [ new Plugin(), 'run' ] );

This example plugin is shipping with a composer.json file that defines a PSR-4 style autoloader. In the bootstrap file, I run a check to see whether the main Plugin class exists at the plugin’s namespace. If it does, great! It’s likely the plugin was installed using Composer, and that the vendor/autoload.php file was required somewhere further upstream, either in wp-config.php or maybe via a loader file in an mu-plugin.

It’s what happens if the class file isn’t found is what I think is interesting. In that situation, we’ll try and require a fallback autoloader class from within the plugin itself, and set up our own autoloader. Here’s what mine looks like:

/**
 * Quick and dirty custom autoloader if the class files are not already available via Composer.
 *
 * This function ignores all non JMichaelWard\WPPluginStarter namespaced classes, then performs a require on the class
 * based on the PSR-4 standard. This presumes that the class file names match the name of the class itself, and
 * is following the directory structure as defined by the namespace.
 *
 * @param string $class_name Name of the class to autoload.
 *
 * @author Jeremy Ward <jeremy@jmichaelward.com>
 * @since  2019-10-12
 * @return void
 */
function autoload( $class_name ) {
	if ( false === strpos( $class_name, __NAMESPACE__ ) ) {
		return;
	}

	$parts     = explode( '\\', $class_name );
	$file_path = implode( DIRECTORY_SEPARATOR, array_splice( $parts, 2 ) );

	require_once trailingslashit( __DIR__ ) . $file_path . '.php';
}

This autoloader bails early if the class name passed into it doesn’t share the same namespace. Otherwise, it explodes the class name into an array – in this case, it would be JMichaelWard, WPPluginStarter, and Plugin – and then recreates the class file path after splicing out the first two values form the namespace, so we’re left with Plugin.php as the include.

In this situation, the autoload.php file is kept in the same src/ directory with the rest of our class files, so the autoloader’s path is relative to all of those classes.

Because we’re following the PSR-4 convention, which essentially maps file names to the directory structure, this means we can located classes in nested directories, such as JMichaelWard\WPPluginStarter\Content\ContentRegistrar.php, which would be stored in a Content directory within src/. As long as engineers follow the naming convention, classes will be discovered correctly and no errors will be thrown.

The benefit of this approach is that you can quickly scaffold up a plugin following a PSR-4 styled approach, and allow others to install it either by following a Composer-based process, or just by including it in their plugins directory. The downside, of course, is if there are any third-party dependencies – this approach won’t play nice, because you’d need to refactor the autoload.php file to check for namespaces that aren’t your own, and would have to engineer a way to locate those files.

That said, for a quick, lightweight, out-of-the-box solution, I think this one will meet a lot of needs.

You can view the full code for this example plugin on GitHub. I’m working on that repo to create a plugin starter that will ship with a Symfony Console command that will run on the composer create-project event. When installed as a new package, the console will trigger a wizard that will ask a series of questions in order to automatically update namespaces, author details, and more, so that developers can more quickly get to the focus of their project: making the plugin do whatever it needs to actually do. That’s still in progress, so look for another post in the coming weeks.

Upcoming Conferences

This is just a quick post to announce that I’ve been accepted to speak at a pair of upcoming conferences.

First, I’ll be giving a new talk, Lose Your Head! Re-imagining WordPress’s Role in Content Presentation at WordCamp Minneapolis-St. Paul. The conference is being held on August 22-24 at the McNamara Alumni Center on the University of Minnesota Campus, and my session is scheduled for first thing Saturday morning.

In September, I’m flying to California to take part in WordCamp Sacramento, where I’ll be doing a reprise of my presentation, Modernizing Your Development Workflow Using Composer. The schedule hasn’t yet been released, but the conference will be held on September 21-22 at The Falls Event Center in Roseville, CA.

Unfortunately, neither of my submissions were accepted at WordCamp US this year, but I’m looking forward to visiting St. Louis in November, catching up with some old friends, and hopefully making some new ones. If you’re planning on going, give me a shout so we can find some time to get together!

WordPress Plugin Bootstrap Files and Class Architecture

I’ve been casually working on my Board Game Collector plugin off and on for awhile. It’s a fairly basic plugin that registers a custom settings page, post type, and WP-CLI command that allows you to connect to the BoardGameGeek API to pull in data for a given user’s board game collection. I’m still undecided as to the long-term utility of the plugin, so when I work on it, it becomes a playground of sorts for me to try out ideas.

A couple of months ago, I completely refactored the plugin to take advantage of the OOPS-WP library I had written for WebDevStudios, because I wanted it to more closely follow the style I’d established over the years for WordPress projects. This morning, after revisiting it once more, I decided I didn’t fully like the structure of the plugin bootstrap file, so I made a few minor tweaks. I’ve never actually written my approach down anywhere, so I figured a rainy day like today was as good as any to talk about my coding philosophy when it comes to plugin bootstrap files and class file organization.

Anatomy of a Plugin Bootstrap File

First, let’s take a look at the plugin bootstrap file for the Board Game Collector plugin is it exists in the develop branch of the repository this morning:

The main thing to notice here is that I’ve established that the sole responsibility of the bootstrap file is to determine whether WordPress can locate the files it needs to run. Any further plugin behavior is delegated to the main plugin file where services are instantiated, hooks are registered, constants are defined, and so on. Since I’m using Composer for class autoloading, I do want WordPress to check whether that autoloader exists locally within the plugin in case I installed it directly instead of requiring it via composer install somewhere from within the WordPress project.

One thing I changed this morning was moving toward the use of a try/catch block when attempting to initialize the plugin class. Previously, I was running a class_exists check to determine whether or not the plugin can run. But, in working with some enterprise WordPress multisite projects, I’ve come to learn that – depending on the particular configuration – class_exists might return true for a plugin that is deactivated on one site but active on another. In those projects, we had circumvented that behavior by passing in false as the second parameter to class_exists, but I think this try/catch approach is more explicit. If the class files are not loaded, then my plugin will catch the error and handle the notification/deactivation process.

And that, in a nutshell, is the entirety of the bootstrap process. Just about every plugin I write nowadays incorporates some version of this structure:

  1. Check for the presence of a local autoloader
  2. Try to instantiate the main plugin class on the plugins_loaded action and run it.
  3. Display a notice and deactivate the plugin if anything went wrong.

Class File Organization

Next, let’s take a look at the file structure for this particular plugin.

Class file structure of the Board Game Collector plugin

By adhering to the PSR-4 standard for class autoloading, I’m able to organize the various classes that power my plugin into groupings relevant to their responsibilities. All class files at the root of the src/ directory have a namespace of JMichaelWard/BoardGameCollector, and from there, the namespace matches the relative path to the file. So, for instance, my CliService class, located at src/UI/Cli/, has a namespace of JMichaelWard/BoardGameCollector/UI/Cli.

The benefits of this approach are two-fold. First, when I need to make a change to a particular part of the plugin – say, updates to the API connections – I know exactly where I need to go, because everything is organized into top-level directories that describe what they are responsible for. Second, any classes referenced outside of that grouping can be easily located, because their namespace matches the file structure.

Today, many WordPress plugins still rely on a flat class structure which, sure, makes it easy to locate all of the class files, but I find that understanding the relationships between classes is far more challenging. This particular approach works for me, and perhaps it will work for you, too.

The Main Plugin File

Finally, let’s check out the main plugin file and see how things are structured.

There’s kind of a lot going on here, but in many ways, the main class file is a lot like the bootstrap file. Its job is to define a set of “services” – basically, processes for which the plugin is responsible for starting up – and make sure that those services are run. At this point in time, the Board Game Collector plugin has 5 primary services:

  • A ContentRegistrar, which is responsible for registering custom post types and taxonomies with WordPress.
  • An ApiService, which is responsible for registering custom API endpoints within WordPress and for communicating with the BoardGameGeek API.
  • A CliService, which is responsible for registering custom WP-CLI commands.
  • A CronService, which is responsible for setting up tasks that need to trigger at given intervals.
  • The Settings service, which is responsible for registering admin interfaces for working with the plugin inside of the WordPress dashboard.

Beyond that functionality, there are a few additional things I’d like to point out in this class file.

First, I’m using a Dependency Injection container called Auryn in this project. Auryn is, simply put, completely magical. On line 79 of the gist, the call to $this->injector->make passes in the current service class name to Auryn and leaves the instantiation of that object to it. If the class defines any other classes within its constructor, Auryn will load an existing instance of it if it finds one, otherwise, it will instantiate that dependency for you. The benefit is that your class constructors can be properly defined with the actual objects your class needs, making it easier to understand later what an object is made of. Auryn probably deserves a whole separate blog post of its own, so I’ll leave it at that for now.

Second, within the register_services method, I’m calling array_column on the resulting set of services and reassigning it to the $services property. This turns the indexed array into an associative array instead, and allows me – should I need it – to request a particular service object by its class name.

Lastly, after each of the service objects are instantiated, I pass the actual services to a register_service method, which passes in the main plugin file path to the objects that require it, and finally, calls their run methods to trigger the processes for those services. The benefit here is that register_service is type-hinted to the Service abstract class in OOPS-WP, meaning that if I add a service class name to the array inside of th main class, but forget to actually extend the abstract class, PHP will throw a fatal error. Errors are extremely helpful when attempting to abide by a given standard, and putting these guardrails in place for myself overtime have made me a better developer and made my own code a little more foolproof.

Summary

Hopefully this post gives you some ideas about approaches you can take to structure your own projects. I absolutely love working with object oriented code, and I’m hoping that as time goes on, we start to see more WordPress developers incorporating object-oriented practices into their plugins and themes. Clearly separating the responsibility of your code into sections, as I’ve demonstrated above, can make it easier for other engineers (or even your future self!) to understand what’s going on within your application, thereby reducing the time it takes to make fixes or to create brand new features.

If you happened to read this post and found it helpful or informative, please give me a shout on Twitter and let me know!

Scorekeeper React

I’m excited to announce that my rewrite of my Scorekeeper app is finally live! Looking at the commit history in the repository, I realized I started the project in earnest well over a year ago, and it sat for a long (long) time. That was, of course, until I attended the free JavaScript for WordPress conference that Zac Gordon put on this week, where I not only learned some new skills I’m ready to start incorporating into my day-to-day work, but I also reaffirmed the knowledge I’d already gained from my infrequent experimentations with React.

If you haven’t used Scorekeeper before, it’s a really basic score tabulation app – enter some people’s names and apply some numbers to the active player and adjust their scores. It’s handy for when you have an internet connection but no pen and paper and need to calculate player scores across a set of various criteria. On iOS, you can add the site to your home page as an app, and clicking on it will trigger a new instance of the app in your browser. I use it all the time, so it was very important to me that the look and feel of the app remained largely the same.

One new feature I added in this rewrite was the ability to reset the current state – basically, starting over and going back to selecting how many players there are. It’s a small detail, but it’s something that will enhance my own personal usage of the app.

As an engineer who works primarily within PHP during the day, it’s taken a while for me to really dig into the React documentation and feel comfortable enough with state and props to build something dynamic in the browser. I really enjoy working in JavaScript, and am hoping that this tiny accomplishment will lead to more opportunities to work with dynamic UIs in the future. I pretty much gave up the need to do any front-end development when I joined WebDevStudios as a back-end engineer couple of years ago, and if I’m being honest, I don’t miss most of it – wrestling with site appearance across a number of browsers and viewports doesn’t excite me. But, I do miss the UX/UI aspects of front-end, and I’m starting to see how better familiarizing myself with frameworks like React can branch into interesting work in the future, both within WordPress (see: Gutenberg) and outside of it.

On Vacation

Today is the last day of a 10-day vacation. During my time away, I went to Chicago and St. Louis to spend time with friends out of town and see the band Flipper celebrate 40 years of existence. I watched four movies – Spider-Man: Into the Spider-Verse, John Wick, Boyhood, and Toy Story 4. I spent a day playing board games – Russian Railroads, Tiny Towns, Gùgōng, and Solenia, as well as several rounds of Red 7 over the week with my partner and best friend. I celebrated National Hot Dog Month, first with a visit to Devil Dawgs in Chicago, and then all through last week with subsequent Chicago Dogs at Bulldog in Lowertown, Chicago Taste Authority on West 7th Avenue, and Portillo’s in Roseville. I rode my bike a little, took a couple of walks here and there, played rounds of pinball at Tilt and Ox Cart, attended the St. Paul Board Game meetup, hung out at my favorite taproom, and otherwise did whatever I felt was necessary to unplug and take some proper time away from work.

Importantly, I spent the vast majority of my time completely logged out of my work Slack and e-mail, breaking down only yesterday afternoon to see what I’d missed in the week prior (hint: it wasn’t anything that couldn’t wait until tomorrow). I worked on a client-side app for my micro-blogging/Twitter alternative plugin, Into the Void, and reviewed Zac Gordon’s course about Headless WordPress on Udemy for inspiration and to level-up my own skills. But, for the most part, I didn’t spend much of this time in front of a text editor, and I think my vacation was better for it.

Tomorrow, I go back to work, and there’s still so much I didn’t get around to doing that I’m going to have to take care of in the coming weeks and months. I have talks to prepare and refine, new skills to learn, and personal projects to push along. The time off has been rejuvenating, though, and I feel better equipped to tackle these additional tasks after taking that time away than I did before.

Before this past week, it’d been five months since I’d last taken a scheduled PTO day. If you’re in a similar situation, I highly encourage you to give yourself a break, even if it just means taking a long weekend. Get out of town, enjoy the weather, read a book, or do whatever you enjoy doing that helps you unwind and takes your mind off your daily work tasks. You’ll come back refreshed and ready to tackle the challenges ahead.

Life moves fast; enjoy it. Work will be there for you when you get back.