Latest News

WordPress and the Curious Case of PHP Namespaces

For part two of my series on Rethinking PHP Development in WordPress, I wanted to write about three significant elements of object oriented programming: classes, interfaces, and namespaces. A big reason I wanted to write about them together is because I think they’re so integral to understanding the way PHP developers who cut their teeth on WordPress learn their craft. However, I felt that might get a bit verbose and keep me from hitting that “Publish” button, so I wanted to focus on just one segment of that topic today: namespaces.

What is a namespace?

Before we can talk about namespaces, let’s focus on a second on symbols. In computer programming, a symbol is simply something that has a human-readable form. A function is a symbol. Class names are symbols. So are variables. We use symbols in programming because they help us understand what we’re trying to make our programs do.

We have control over what we name our symbols, the same way that our parents named us, and we name our own pets, children, and computer hardware (you’ve named your computer, right?).

In real-life, symbols can be complicated. Have you ever worked somewhere that had more than one Chris, Travis, Sam, or (C/K)arl (I do!). We differentiate between first names by passing down our family names, but sometimes, that’s not even enough. In the U.S., we have Social Security Numbers so we can differentiate – on paper, at least – between the thousands of John Smiths and Jane Jacksons in our country.

Last names and identifying numbers are a type of namespace. Basically, a namespace is a way to ensure that something that must be unique in your system is, in fact, unique.

In PHP, we have to ensure that all of our symbols are unique in order to prevent fatal errors. And, in the WordPress community, at least, we’ve established a couple of different ways of attempting to achieve that goal.

Function prefixes

Everyone who has written WordPress code for any length of time has been told time and time again to “prefix their functions.” What does that mean? Well, let’s say I had a function that registered a product post type:

<?php
function register_post_type() {
    register_post_type( 'product', array( /* My options... */ ) );
}
add_action( 'init', 'register_post_type' );

If you’ve been writing PHP code in WordPress for any length of time, hopefully the problem is evident to you right away, because in this particular example, I’m declaring a function name that is named the exact same as the WordPress core function I’m calling within it. This is called a naming collision, and it PHP, it will generate a fatal error, which causes your code not to complete execution.

They way we’ve gotten around this for years in the WordPress ecosystem is two-fold. First, we prefix our function calls to reduce the chance that someone else (usually another plugin) has declared a function with the same name as us. And second, we wrap that function declaration in some code that checks whether that function has already been declared. Here’s another example:

<?php
if ( ! function_exists( 'jmw_register_post_type' ) {
    function jmw_register_post_type() {
        register_post_type( 'product', array( /* My options... */ ) );
    }
    add_action( 'init', 'jmw_register_post_type' );
}

The function_exists method in PHP allows us to check whether someone else has created a function with the same name before we make a declaration for our own. The jmw prefix in this example attempts to further minimize the chance that someone has created another function with the same name.

This approach is perfectly suitable, and has worked reasonably well for many developers over the history of the WordPress project. If you examine the code from the WordPress plugin repository, chances are high that you’ll see this pattern a lot.

Classes as a namespace

Over time, developers began separating their code a bit more, grouping like-functions into separate files, and exploring the use of a class-based system for further namespacing. I think this happened for at least two reasons:

  1. Classes can have the same names as functions, but you can store a lot more information in a class, which means you can make big collections of functions.
  2. WordPress developers, after writing functional code for years, were eager to try their hand at object-oriented programming.

Re-hashing the example from the previous section, we might have something like this:

<?php
class JMW_Custom_Post_Types {
    public static function register_product() {
        register_post_type( 'product', array( /* My options... */ ) );
    }
}
add_action( 'init', array( 'JMW_Custom_Post_Types', 'register_product' );

As with the ! function_exists check in the previous example, we might also wrap the class declaration in a ! class_exists check here, too, just to make sure that our JMW_ prefix is sufficient.

I want to reiterate here: this is fine. The thing about computer programming, particularly in PHP, is that there are a lot of ways to do things, and whatever gets your code shipped and out to the world is more important than which particular approaches you used.

That said, I want to tell you about a third approach, because there is currently not a single* example of it in all of WordPress core.

The namespace keyword

The namespace keyword has been a part of PHP since version 5.3. It avoids the prefixing and class-based approaches ot avoiding symbol collisions in the language. Here’s another example of the function-based approach from earlier, but using the keyword instead:

<?php
namespace JMW;

function register_post_type() {
    \register_post_type( 'product', array( /* My options... */ ) );
}
add_action( 'init', 'JMW\register_post_type' );

Notice anything weird? Well, in this example, I’m prefixing the call to WordPress’s register_post_type function with a backward slash. That’s because I need to tell PHP that I want to use a method from the global namespace, which is to say: I want to use the register_post_type method that didn’t declare a namespace, because WordPress does not currently have any namespace conventions in core.

That said, the code in the above example won’t fail because PHP allows us to have two functions with the same name, so long as we identify distinct namespaces for each of them, just like how two people named Travis can work at the same company (sometimes, you might just give them nicknames, even if they have different last names. Nicknames are another form of namespacing.)!

How is this better?

It may not be evident at first why this makes a difference. Adding a namespace to the top of your file might be more work, but what it really does is frees you up from the way things have always been done. If, for example, you’re a plugin developer and you really like using short, concise function names, you can use them without fear of symbol collision from WordPress core or other plugins. Heck, you can use them without fear of symbol collision from your own code!

Let me demonstrate what I mean with a few more examples:

<?php
namespace JMW\Product_Post_Type;

function register() {
        register_post_type( 'product', array( /* My options... */ ) );
}
add_action( 'init', 'JMW\Product_Post_Type\register' );
<?php
namespace JMW\Faculty_Post_Type;

function register() {
    register_post_type( 'faculty', array( /* My options... * ) );
}
add_action( 'init', 'JMW\Faculty_Post_Type\register' );

The above examples might be two separate functions files name product-post-type.php and faculty-post-type.php, respectively. Although they both contain a register method, you could include them both in your functions.php file without worrying about a symbol collision, because they’re each namespaced differently. This gives developers a lot of flexibility to use short function names without worry that there will be a symbol collision, even within their own codebase.

Summary

These examples only really scratch the surface. In the broader PHP ecosystem, namespaces are frequently used not just to prevent symbol collision, but also to dictate class file organization, such as in the PSR-4 standard recommended by the PHP Framework Interoperability Group. In their configuration, every package (e.g., a WordPress plugin) has both a vendor and a package namespace at the top-level:

<?php
namespace JMichaelWard\MyGreatPlugin;

In PSR-4, the above example would be considered the root namespace, which means any files with that namespace could be located in the root of a directory indicated by the developer. Namespaces with extra levels would map to a sub-directory. Example:

<?php
namespace JMichaelWard\MyGreatPlugin\PostType;

The PostType sub-namespace would suggest that I have a directory named PostType where all of my classes are kept. This approach helps simply class autoloading, which is perhaps another post altogether.

Needless to say, namespacing your function and class files in WordPress, even if core isn’t yet doing it, can provide some great benefits. It allows you to confidently use shorter method names (particularly when paired with the <vendor>/<packagename> approach I just described). It allows you to group code into directories when paired with class autoloading. And, least importantly, but important nonetheless: it allows you to use a language feature that has been available in PHP for nearly 12 years.

I hope this post inspires you to experiment with PHP namespacing, and sets you on your journey for further exploration of the server-side language of WordPress.

Footnotes

* WordPress core contains the PHPMailer library, which in fact, uses the native PHP namespace keyword.

How a Conversation About Filterable Autoloader Paths Pleasantly Derailed My Sunday Afternoon

My good friend Gary Kovar posed a really interesting question on Twitter yesterday:

This led to some conversation both on Twitter and separately on Slack, and I began to realize that this dovetails nicely into that series about re-envisioning PHP development for WordPress I’ve been alluding to for months. Consider this post the first in that series.

Dependency Management in WordPress

Here is a real-life problem I encountered on a client project while I was working in agency: the client was using one plugin to save their media uploads to Amazon S3, and they wanted another custom plugin developed that, when creating a new site in WordPress multisite, a hook would be triggered that creates a new bucket on S3 for that site’s media.

The client had one of the most sophisticated build, testing, and deployment setups for WordPress I have encountered yet in my career. They were using Composer for installing their WordPress plugins, and so naturally, when I began building this custom plugin, I created a composer.json file and required the latest version of the Amazon SDK as a dependency, then got to work on building out the functionality to automatically create the buckets.

Everything was going great. That was, at least, until I got to the point where I’d actually attempted to install my plugin alongside all of the other plugins in their multisite installation. It turned out that the plugin that was uploading media to Amazon was using an older version of the SDK, whereas I had coded my plugin against a new version. When their build processes attempted to pull my plugin into the site alongside the other one, everything appeared to work correctly because the other plugin was shipping the Amazon library alongside its code, instead of downloading it using Composer.

If you’re not familiar with Composer, typically what happens when two libraries (or in this case, WordPress plugins) require incompatible versions of the same library, Composer will exit the install process and inform you of the incompatibility. In this case, because the other plugin wasn’t using Composer, I wasn’t aware of the incompatibility.

There’s an additional wrinkle here, too, because in WordPress, the core application does not have a process to check for and resolve all of the dependencies within a plugin or theme. Thus, if one plugin is installing a library via Composer, and another one ships it with the plugin, it’s possible that whichever plugin loads first will load the dependency. In a well-coded plugin, developers guard against loading a library again if it’s already been loaded to avoid throwing errors in PHP, and well written libraries (such as Amazon’s) can avoid throwing errors if there’s good compatibility in their APIs across versions.

This was the case for this particular project. Ultimately, I came to discover that my code wasn’t working correctly because the other plugin’s library was loading first. We wound up forking that library, checking out its beta version (which used the newer version of the SDK and was nearly released), and went on our merry way.

Why is this a WordPress problem?

The short answer is that it’s complicated. Nearly 40% of the top 10 million websites on the internet today are powered by WordPress. Not every WordPress site is maintained by a developer – in many cases, they’re maintained by non-technical people for whom WordPress was an intuitive solution to help them get their vision online. Those folks don’t care about Composer or PHP dependency resolution or namespace collisions. They (rightfully) just want things to work.

For the rest of us, this means we try to come up with innovative solutions to be able to use the tools that make our jobs easier. Because WordPress core doesn’t have a mechanism for resolving a plugin and theme’s dependencies before it loads them, as plugin developers who work in sophisticated ecosystems like that of my former client, we have to rely on alternative solutions like Mozart or Imposter to package our vendor directory with our project and prefix its class namespaces with our own to avoid naming collisions in PHP.

There has to be a better way, but it’s clear that whatever the solution might be, it’s neither easy nor obvious, or as a community, we may have resolved it by now.

Let’s Talk About Extensibility

So, back to Gary’s question and the conversation that followed, which still pertains to workarounds for the dependency management issues in WordPress, but also includes some nuances around class inheritance, interfaces, and incorporating developer guardrails into open-source projects that I find particularly compelling.

In our conversation, we were discussing class property and method visibility in PHP, and Gary shared with me this filter in the MySQL class of SquareOne, an open-source framework developed by the fine folks at Modern Tribe. Though not about autoloading, I’m hoping the correlation here is clear. Let’s look at this snippet (condensed from the link above):

class MySQL implements Backend {
	const DB_TABLE = 'queue';

	private $table_name;

	public function __construct() {
		global $wpdb;

		$table_name = $wpdb->base_prefix . self::DB_TABLE;

		/**
		 * Filter the table name used for queues on this backend.
		 *
		 * @param string $table_name Table name with $wpdb->prefix added
		 */
		$table_name = apply_filters( 'tribe/queues/mysql/table_name', $table_name );

		$this->table_name = $table_name;
	}

There are two important bits in this example:

  1. The private keyword on the $table_name variable
  2. The call to apply_filters, which provides developers with the ability to override the default value of $table_name

Historically, actions and filters in WordPress have been offered as an easy way to override the default behavior of the code that plugin authors write. Like the end users of WordPress itself, developers who work with the platform have a broad range of experience – especially when it comes to object-oriented programming – and these hooks offer an arguably simpler way of overriding the original programmer’s logic.

A neat thing about PHP, however, is that it also accommodates for changes. Consider this alternative to the snippet above:

class MySQL implements Backend {
    const DB_TABLE = 'queue';

    private $table_name;

    public function __construct() {
        global $wpdb;

        $this->table_name = $wpdb->prefix . self::DB_TABLE;
}

But Jeremy… you just took out the filter.

You got me. :)

In this case, MySQL is instantiated somewhere, and it implements an interface, which means it has a whole set of methods that can be called on it. Instead of filtering just the table name, Modern Tribe could consider allowing for modification of the entire class by filtering the places where it is instantiated, and requiring an interface in that callback.

Here’s a contrived example. Let’s say I’m a developer who wants to extend the MySQL class of SquareOne in my own plugin. Let’s assume, for now, that I only want to override the value of the table name. I could create a class that looks like this:

use Tribe\Libs\Queues_Mysql\Backends\MySQL;

class MyPersonalMySQL extends MySQL {
    protected $table_name;

    public function __construct() {
        global $wpdb;

        parent::__construct();

        $this->table_name = $wpdb->prefix . 'my_personal_queue';
    }
}

Notably, PHP allows you to weaken the access level of class properties and methods for extending classes. Thus, it’s okay here to change the visibility of $table_name from private in the parent class to protected here. Additionally, because I only want to change the table name here, my class can inherit all of the other default behavior from the MySQL class. That said, this does complicate both my approach and Modern Tribe’s. In their case, if they want me to continue to be able to override the class, they have to add a filter to wherever that object is being instantiated. It’d look something like:

$mysql = apply_filters( 'tribe/queues/mysql', new MySQL() );

And I, of course, would need to add the filter myself, AND extend the class, when I could have just filtered the table name in the first place:

add_filter( 'tribe/queues/mysql', new MyPersonalMySQL() );

Versus:

global $wpdb;

add_filter( 'tribe/queues/mysql/table_name', $wpdb->prefix . 'my_personal_queue' );

If extensibility is the goal, then there’s an argument to be made that we as open-source developers could be creating more filters in order to accommodate both procedural and object-oriented developers alike. However, in my mind, the argument for making codebases easier to understand and to raise the bar for WordPress developers alike lies in interfaces.

A Case for Interfaces

In his tweet, Gary asked if there were any open-source examples where the path to a Composer class autoloader is filterable. Using the previous examples as a guide, let’s examine what plugin instantiation might look like from the perspective of a WordPress developer who wants to modify plugins with their own autoloaders. Consider the following plugin:

/**
 * Plugin Name: Incredible Plugin
 * Description: Does something incredible!
 */

namespace JMichaelWard\IncrediblePlugin;

require_once __DIR__ . '/src/IncrediblePlugin.php';

function init( Autoloadable $plugin ) {
    $plugin->init();
    
    return $plugin;
}

add_action( 'plugins_loaded', function() {
    $plugin = apply_filters( 'init_incredible_plugin', new IncrediblePlugin( __FILE__ ) );
    init( $plugin );
} );

The plugin itself might look like this:

namespace JMichaelWard\IncrediblePlugin;

class IncrediblePlugin implements Autoloadable {
    private $plugin_file;

    public function __construct( $plugin_file ) {
        $this->plugin_file = $plugin_file; 
    }

    public function init() {
        $this->autoload();
    }

    public function autoload() {
        require_once plugin_dir_path( $this->plugin_file ) . '/vendor/autoload.php';
    }
}

The beauty here is that this code accomplishes a couple of things.

First, the init method in the main plugin file uses a type-hint against the Autoloadable interface. In this scenario, this means that another plugin author who needs to modify this plugin’s primary class in some fashion could do so simply by extending the IncrediblePlugin class (since it already implements Autoloadable), or that – if somehow needed – they could pass in an entirely new plugin object that meets the requirements of the behaviors for the rest of the plugin, so long as it also extends Autoloadable. If Gary simply didn’t want the autoloader to run, he could override the method and simply have his new class do nothing.

Second, what this achieves – and this is notable because no concept like it exists in WordPress core today – is that because the init method in the main plugin file uses a type-hint, if another developer extended it and forgot to implement that interface, PHP will throw a fatal error and warn that developer that they did not meet the requirements to initialize the plugin.

Believe it or not, errors are good. Great, even. Or, I should clarify, that’s the case when they are part of the development process. Errors provide context for what you haven’t done correctly, and through the process of creating interfaces for your classes, you are establishing a contract for what is required to alter that application, whether you’re the one doing the alteration, or if you’ve created a developer API intended for others to extend.

Conclusion

In this post, I covered the following topics:

  • Challenges associated with dependency management in WordPress
  • Proposed approaches for adopting broader filter usage
  • Weakening restrictive property and method visibility during class extension
  • A case for using PHP interfaces

I expect that a few of these topics will surface again in future editions of this series. For instance, the benefits of interface usage in software development are a significant part of the first 5 principles of S.O.L.I.D. Type-hints, too, help ensure that the values we pass into functions throughout our codebases are of the type we expect, and using them can really help us spot errors during the course of developing new features.

I’ll close this inaugural post in the Rethinking PHP Development in WordPress series by thanking Gary once again for the discussion that helped get my wheels turning. As I seek one or more mentors to increase my own knowledge in 2021, I’m reminded that our friends, colleagues, and peers are often the best mentors of all.

Seeking Mentorship

I’ll keep this short and sweet: one of my professional goals for 2021 is to establish formalized mentorships with one or more of my peers in the tech community.

Through the course of my 8-year development career, I have aimed to increase my knowledge and improve my technical skills in a variety of ways. Like others, I’ve read numerous books to learn about new languages, design patterns, tools, and approaches to engineering. I’ve attended conferences and local meetups to build relationships with others in my field, and of course, to attend presentations and discover what additional tools I can add to my skill set.

In July of last year, I joined the product team at Rocketgenius. There, I work on the add-ons crew where I am responsible for developing and maintaining our collection of WordPress plugins that further extend the functionality of the Gravity Forms plugin.

Moving from the agency space into product has long been one of my career goals, because I think it provides me with the opportunity to apply a lot of the “ideal engineering” scenarios that seem prevalent in all that book-learning: test-driven development, continuous delivery and deployment, domain-driven design, agile development, etc. I’ve had exposure to certain aspects of these concepts in my agency work thanks to working with large corporations that adopt them, but because those projects are so fluid, I’ve typically used what had already been established by our clients instead of working to build something of my own.

Needless to say, I recognize that there are shortcomings in my current skill set that I can work to improve upon in 2021, and I think it would be helpful for me to collaborate with one or more folks over the course of the year. In my mind, this collaboration would entail semi-regular (monthly, perhaps?) calls to discuss challenges working in the technical field, and to share resources and ideas around how to grow one’s professional skill set.

Some initial topics that come to mind:

  • Modernizing legacy codebases (in particular, those which can be extended by end users)
  • Containerization
  • Developing and maintaining custom build processes
  • Test-driven development
  • Domain-driven design
  • Engaging with open-source communities
  • Avoiding burnout

If you have expertise in any of these areas and would be interested forming a mentor/mentee relationship, and especially (but not necessarily limited to) if we already know one another, then please get in touch. I think there’s likely a lot we can learn from one another.

2020: The Lost Year

On March 6th of this year, I posted about leaving my role at WebDevStudios is pursuit of new opportunities. It might as well have been a decade ago.

That weekend, I celebrated “funemployment” by hanging out with some of my closest friends at The Lab in St. Paul, a conceptual taproom of sorts where brewers and beverage makers can try out new recipes in small batches that they can sell to those with adventurous palates. I didn’t have a new role lined up just yet, but I was studying and working through online tutorials to teach myself Python. At the time, I was in the middle of an interviewing process with a company where I’d have the opportunity to branch out beyond both WordPress and agency and finally get to experience the world of product development, all while becoming acquainted with a programming language that was both new and yet somehow familiar to me.

Last winter, lots of tech folks in the Twin Cities had started co-working occasionally at BlackStack Brewing, in large part because of 1) the ample taproom space, and 2) BlackStack’s change in business hours and structure; while still a brewery, they’d also begun marketing themselves as a coffeehouse by day. With fast wifi, a low-key environment, and a staff that was friendly to folks settling in and writing code throughout the day, I made plans for it to be the place where I’d spend my first day with some downtime to write some code for fun.

Much to my surprise, when I showed up to BlackStack that following Monday, I ran into some friends and former colleagues alike. The pandemic hadn’t completely settled here in the U.S., but the news was becoming increasingly scary by the day. Folks were showing up throughout the day, some (such as myself) already very mindful about not shaking hands, but of course, in early March, nobody was wearing masks yet, and a group of us went out for lunch together at The Naughty Greek, a fast casual Mediterranean restaurant just up the street.

Those are probably my last tangible, positive memories of The Before Times, though of course they were already tainted with my experience of working with an epidemiologist for almost 4 years earlier in my career and the worry about what was to come.

Later that week, I hosted my last in-person weekly board game night, something I’d organized for a full four years prior. My friends Nick, Bela, Austyn, and I played Great Western Trail, a game about herding cattle from Texas to Kansas City, where you later ship them off by train. Two days later, on Saturday the 14th, my friend Will was the last invited guest to our home for the entirety of this year. He, my partner Abby, and I played the cooperative game Horrified, which I’d purchased in South Dakota just two months prior when Abby and I visited her folks, oblivious to the fact that a global pandemic was looming.

Of course, we all know the rest. And it’s hardly been just the pandemic that’s resulted in this year being, perhaps inarguably, the most terrible of our lifetimes.

Being Thankful

Employment

The Python job that I was interviewing for in March became suddenly unavailable as a result of the economic downturn from the pandemic. In May, I was fortunate enough to land a position working at a local startup, but it quickly became evident in the subsequent weeks that the culture and development stack wasn’t a right fit for me. I turned in my resignation at the end of June, and starting fresh in my search. That very day, I heard from Steve Henty about an engineering position on the product team at Rocketgenius. After a couple weeks of interviewing with him and various members of the team, and learning more about the company’s mission and vision, I decided that staying in the WordPress space but making the switch over to product was going to be the right fit for me.

Man, am I ever glad I did.

I think I have a hard time articulating sometimes what it is I’m looking for out of my career, or even what I want from an employer. Every company that I’ve worked for in the WordPress agency space has done something smashingly well. Some have given me the opportunity to learn and grow, either by paying for memberships to online tutorial services, or helping sponsor travel to attend or speak at a conference. Some have recognized the benefits and challenges associated with remote work, and have taken great strides to do what they can to make their culture open and inclusive. Some have recognized holidays as official company holidays where others haven’t. Some have granted autonomy and trust to you, as an employee, to make decisions and take actions in the interest of the company, without the need for a special sign-off – making the pitch is usually enough.

I don’t know how they do it, but I’ve been with Rocketgenius now for 5 1/2 months, and somehow they do it all, and I’ve worked at enough places at this point in my career to know not to take this for granted. Every day, I am astounded by the thoughtfulness of my colleagues and leadership, the kind ways with which we interact, and the hard work and care that everyone puts into our products. We plan and communicate and check in with one another in ways that I’ve only seen glimpses of in past roles, and it’s made going to work each day something to look forward to; a welcome distraction from the madness of everything else.

Friendship

Since that festive gathering in the beginning of March, I’ve managed to see my friends a handful of times this year, at extremely social-distanced outings in large backyards, city parks, and the front lawn of the Minnesota State Capitol. I’m grateful for those moments of simply reconnecting with one another, of catching up, of celebrating each other’s wins, and of hoping that we can all hug one another again when we finally get a calendar with a new number on it.

My friends have still managed to make this year special through trivia nights, board game tournaments, scotch nights, meetups, impromptu online gatherings, and the occasional telephone call (hi Josie!).

Love

Above all else, I don’t know what I would have done this year if not for Abby. We celebrated our 12th anniversary at the end of October, and we’ve largely spent the year doing a handful of activities: taking walks around Lake Phalen largely as an excuse to run our car, playing a board game I can talk her into playing, watching a movie she can talk me into watching, finding occasions to use the oven instead of the microwave, and sending each other cute stories we find and as many animal-related pictures and gifs as possible. She supported me by remaining optimstic about my career change, even after it quickly got scarier than I’d expected, and I think what I’ll most cherish about this year is her dedication to getting me out of my comfort zone and encouraging me to take a walk in the neighborhood or go sit in the park for awhile. We started the year playing trivia at our local brewery nearly every Wednesday, and pandemic or not, I’m looking forward to warmer summer nights when we can go hang out in the park some more: the sun for her, the shade for me.

Looking Ahead

There’s a whole lot of stuff that’s going to be the same when we wake up tomorrow morning as it was through most of this year. Still, I think there is reason for optimism and hope, and for the new year, I’m planning on a small set of goals to keep me focused and motivated:

  • First and foremost, giving more than I did last year. I wrote a bit about some of my charitable giving over the summer. I’ve given more since then, both via official and unofficial channels, but I recognize that there’s more that I can do and now that my situation has thankfully stabilized a bit, I’m seeking opportunities to do more of that. One thing I’m considering is a monthly donation to Second Harvest Heartland beginning in January.
  • Reading more. A lot more. I’ve fallen out of the habit, and things were already sufficiently dire before 2020. I only managed to finish three books this year, and two of them I’d started in 2019: We Were Eight Years in Power: An American Tragedy by Ta-Nehisi Coates, Someone Who Will Love You in All Your Damaged Glory by Raphael Bob-Waksberg, and The Answer Is… Reflections on My Life by Alex Trebek. I’m not setting a hard goal, but more non-fiction, non-memoir I think is a good place to start. That said, I’m still trying to get through Exploded View by Sam McPheeters (made all the more difficult since it’s a police story) and The First Bad Man by Miranda July.
  • Writing more. Amazingly, this is my 16th blog post this year! I even got my first-ever reader e-mail the other day, related to my post about Xdebug 3. I’m hoping to write more about technical topics, and in particular, I want to write more about the process of learning. I’ve been less motivated to spend additional time in front of a screen that isn’t something mindless like video games or engaging like playing a board game with my friends, and I feel that my tech exploration has suffered as a result. I’m hopeful that we might start to see things normalize at some point this year, and that I’ll regain that excitement to learn and share what I’m learning more.

That last bullet sorta dovetails into some professional goals I have, too. In a particular, I’m working goals at work to open-source some tools, and a plan for sharing/presenting information about those efforts in some fashion. More on that at another date, I suppose.

To sum things up: so long, 2020. You were terrible, but I’m thankful for the good stuff.

Add Featured Images to Old Posts Using “Set Post Thumbs” for WP-CLI

Hey y’all! While I’ve admittedly been delaying my series about rethinking PHP development in WordPress first because of this global pandemic and all the election nonsense, and now more recently because of sheer procrastination because I’m not entirely sure how to start it, I wanted to take a minute to let you know that I made a thing!

Early this year, I got together with my buddy and former bandmate, Matt Semke, to talk about his website, Cats Will Eat You. For a number of years that I’m sure I should know by now and will surely get wrong (14, I think?), Matt has been publishing new art on his website every single day. But, even though his site was getting a lot of love content-wise, it wasn’t getting much attention from a web development and maintenance standpoint.

Matt and I got together over a couple of beers to talk about updating his website from WordPress 3.4(!) to the latest version, getting him onto a better hosting plan, and brainstorming some ideas about how to improve his site overall and make it better for both him and his visitors. This is one of my favorite (and only, at the moment!) freelance projects for a couple reasons: it means I get to help out a good friend who makes cool art, and it’s a low-impact obligation on my time, because I pretty much check in on it periodically and work on it when I have the interest and energy.

That said, there’s one other cool thing I love about this project: it gives me the opportunity to generalize stuff I work on specifically for Matt, and open-source the reusable bits. This weekend is the first such instance of that.

The Problem

With over 14 years of every-day art, Matt’s got thousands of posts on his site. He’s been using WordPress for a very long time; so long, in fact, that the content on his site predates the existence of features we take for granted today, like custom post types, featured images, the REST API, and so on.

In reviewing his theme over the weekend, I realized that I wanted to move some of his data around, get rid of some of the cruft, and, most importantly, set a featured image on each of his posts. So, I spent some time working on a solution, and then as I realized, “hey, some other folks might like this, too”, I started extracting out the parts that weren’t specific to his site, but to anyone’s. And then I made a repo. And then I connected that repo to Packagist. And then I learned how to make it installable using WP-CLI, because even after all this time, I’ve still never done that.

The Solution: Set Post Thumbs

In short, you can now do these two things:

  1. Run wp package install jmichaelward/set-post-thumbs from the command line of your WordPress project.
  2. Run wp thumbnail set --all, and WordPress will query all of the posts on your site that do not have a featured image, and then check whether there are images in your post. If there are, it’ll attach the first one.

The utility comes with a couple of additional commands to report back on which posts had more than one images, and which posts couldn’t set a featured image because it didn’t have any. And then you can run a cleanup command at the end to clear out all the excess meta.

It’s a little thing. It does a fairly specific task, and not everyone might need it. Additionally, I’ve tried to set it up so that it’s extensible, so that you can make modifications to the default way the tool works, in case your featured image lookup requirements differ.

What I really enjoyed about working on this is that I could take something I was building for a friend and open-source it to the broader community. Drop me a line if you wind up trying it and if you have any questions or run into any issues. I recommend using it only on a development environment where you have the opportunity to review the changes you’ve made. But, if you’ve got a site that has lots of posts without featured images, and you need a way to attach something to those posts, this should do the job for you.