Latest News

Introducing WP Plugin Composer

I’ve been doing custom WordPress plugin development for a long time now. At this point, anyone who’s worked with me, attended one of my WordCamp presentations, or spoken with me at any length about modern development knows just how much love I have for Composer. It’s the de-facto tool for PHP dependency management, and for a great reason: it provides great out-of-the-box benefits, such as class autoloading, dependency suggestions, minimum requirements definitions, events-driven scripts, and more.

Over time, Composer has been seeing more and more use by the WordPress community. I’ve personally worked with it frequently with my agency clients, but something I haven’t really considered is how to leverage its benefits while minimizing its trade-offs when the plugin I’m writing is distributed. You see, some engineers may want to continue to install plugins as part of an automated process, while others might still prefer the manual process of uploading a ZIP file and activating a plugin using the WordPress dashboard.

The challenge is to account for both of these scenarios while also keeping plugin repositories bereft of third-party code. I woke up this morning with my wheels spinning on this issue, and have spent the last few years working on a potential approach: WP Plugin Composer.

The idea here is simple: WP Plugin Composer is essentially a starter kit for Composer-based plugin development. It ships with a composer.phar file, a composer.json file, a light functions.php containing a callback to the WordPress register_activation_hook method and a “maybe” autoloader, and a single, empty Plugin class file in the src directory. The rest? Well, that’s up to the developer the decide.

When developing plugins with this library, engineers should be able to work as they usually would: pulling in useful third-party packages, building out application logic, leveraging Composer’s class autoloading, and committing only the code they write.

When publishing plugins, however, typically need to do one of two things:

  1. Ship that plugin with all of its third-party dependencies
  2. Include a detailed set of instructions aimed at developers about the myriad steps necessary to install and activate the plugin

In theory, by including the composer.phar file and a well-defined composer.json file, we should be able to let WP-CLI or the web server do the work for us.

Using WP Plugin Composer, when the plugin is activated, it checks one thing: can it find its own class file? If it can’t, it locates the packaged composer.phar file, extracts it to a directory within the plugin, then runs composer install on the main plugin directory. This pulls down all of the dependencies into the plugin’s vendor directory, and then the plugin subsequently locates and loads the Composer class autoloader.

If the class file does exist at runtime? Well, we assume that the Composer autoload file has been required further upstream, and that the plugin was also installed using Composer. No need to generate an autoloader, and no need to perform the composer.phar extraction process.

At this point, this idea is primarily a proof-of-concept for me, but something I’m pretty excited to try out in my personal projects in the coming weeks. If you’d like to give it a try and see how it works for you, too, you can do so in one of two ways:

  1. Run git clone [your-plugin-name] inside the plugins directory of your WordPress installation, then follow the steps in the README.
  2. Run composer create-project jmichaelward/wp-plugin-composer [your-plugin-name] -s dev inside the plugins directory of your WordPress installation, then follow the steps in the README.

I’m interested in hearing how this works for folks, and whether it provides the kind of utility I think it does! If you try it out and want to leave me some feedback, feel free to drop me line. I’d love to hear from you.

Silver Linings

I haven’t felt much like writing these days, but I’m taking advantage of the moderate temps, overcast skies, and the fact that there’s a parasol-protected table outside within range of my wifi to give myself an excuse to sit somewhere other than my desk for a change and tap out a few words.

Primarily, I’m excited to let you know that on July 20th, I began a new role as a Software Engineer on the product team at Rocketgenius, the company that makes the Gravity Forms plugin for WordPress.

During the seven-plus years that I’ve spent working in the WordPress agency space, I’ve learned a lot about meeting the demands of challenging projects, and partnering with my clients to help them achieve their business goals. I’ve worked closely with my clients on agile teams, participating in feature-planning discussions, pointing sprint tickets, and collaborating on development efforts to continuously deliver new features and functionality to their web applications.

What excites me about my new role at Rocketgenius is having the opportunity to contribute to those efforts from the inside. As inclusive and collaborative as my client teams have been, there’s nothing quite like being directly on staff that communicates with your customers and defines the roadmap for what features you plan to add to your product. I’m thrilled to join my new team, and work closely with my colleagues and our customers to help deliver functionality that they’ve been dreaming about for years.

For the first few weeks, I’ve primarily been learning the ropes: reading documentation, setting up my development environment, running our testing suite, learning how to work, and slowly ramping up to tackle a couple of open tickets. My team has been amazing: they’re thoughtful, inquisitive, collaborative, and kind. As an added bonus, I’m reunited with some old friends from previous agencies, so while I’m the new kid on the block, I’ve got some familiar faces with me to help me along the way.

Thus far, things have been amazing, and I’m really looking forward to seeing what the coming months and years will bring with this crew. And we’re still hiring! If you’re seeking the kind of change I was, perhaps consider putting in an application?

What a Year This Month Has Been

…and what a life this year has been.

My last update was posted on the day that George Floyd’s life was taken by four officers of the Minneapolis Police Department. The week that followed his murder was filled with justifiable anger and protest, and subsequent retributional attacks on the minority-owned businesses all through our communities. Neighborhoods came together to help with clean-up efforts, and though the news coverage has dissipated once the violence has lessened, protesters continue to call for change every day here in the Twin Cities and nationwide.

I cringe looking back on that update, knowing how trivial it all is. I, too, cringe thinking about writing right now, knowing that I’m not yet doing enough myself to contribute back to the broader efforts to enact change in this country.

Change runs through all of us.

Before I switched to a career in software development, I’d worked for 3 1/2 years as a project coordinator at a small healthcare research company in St. Paul. My boss, Cori, was an epidemiologist by training, and her particular focus was on influenza vaccination and why nurses choose not to get them. My first week on that job started just as H1N1 was beginning to surface in Mexico, and I quickly went from knowing next to nothing about epidemiology to sitting on weekly media calls with the Centers for Disease Control (led by Anne Schuchat, even then!), listening to them answer questions and allay fears about the virus and giving practical advice for what we can all do to keep it from spreading.

Naturally, with the Coronavirus rampant in the U.S., I think about that job and all the time, and how those few short years directly affected the trajectory of my own life. Between learning about pandemic preparedness, regularly getting my flu shot (even before I worked there!), and subsequently switching to remote work for the last 4 1/2 years, I’d never felt more “ready” to tackle a situation like we’re all in right now.

I’m not ready, though. As I write this, the U.S. has reached 126,000 deaths caused by COVID-19, with millions more infected. We know next-to-nothing about this disease, and particularly its long-term effects, and so I’m surprised to see how cavalier some of us are about mask usage, calling for businesses to re-open and demanding haircuts as if somehow staying home longer would kill us, when the reality is that the reverse is true.

We don’t talk about fear much, and it’s perceived as an unbecoming quality to have. But I argue that it’s healthy to talk about, and that understanding the things we fear make us better equipped to tackle them. I’m already a homebody, and I fear contracting an illness with unknown long-term effects. I wear masks in public knowing that it does a far better job of protecting others from me than it does protecting me from them, and so I’m thankful to my neighbors who put in the effort, because it shows me they care, and that they’re scared, too. Our collective fear, in a way, is a strength, because it will help keep us safe in this particular instance.

This is a fairly long-winded way of saying that I’m thankful to the people who are out there protesting and continuing to fight for justice that is long overdue in this country. My partner and I attended a clean-up effort on Lake St. in Minneapolis, and it was heartening to see so many people who care about our neighbors in these cities. However, my anxiety ran high being out in public for the first time in months, so potentially exposed to my own undoing.

The week before our world change completely again for the umpteenth time this year, my first paycheck cleared from my new job, and I received my second one as well. It’s a popular saying in open-source that there are many ways to contribute – through time, effort, documentation, etc. At the end of the day, if you don’t want to or are unable to contribute in those ways, the last thing you can do is donate money. I want to play a part in affecting change in this country, and I also recognize that I am scared for my health. So, I opted to donate. It literally is the least someone can do, and I hope that if you’re reading this, and you feel like you want to help out, but you’re scared too, I hope you’ll consider researching BIPOC businesses and movements and making a financial contribution. In the meantime, I want to give you a head-start.

These are the organizations I donated to in May and June:

There are tons more organizations and people that you can give to. Donating (and volunteering, and shopping, etc.) is personal, and that’s why it’s important to do your own research. Here are a few more links that could be potentially helpful for you as you consider ways in which you can contribute to these efforts:

  • PB Resources – resources for activism, learning, and donation.
  • Amplify Black – an online directory of Black-owned businesses and organizations.
  • Black Lives Matter – information about petitions, current protests, resources, and places to donate.

If you choose to donate, recurring donations are always more helpful to organizations than one-time payments. It gives them a sense of their continuing monthly income, and allows for better long-term forecasting and planning.

Unfortunately, all of my donations in the last month-plus have been one-time, as I wasn’t sure yet what my own ongoing income situation would look like. In my last update, I announced that I’d started a new job; in this one, I’m announcing that I’ve left that job, as I came to understand that it just wasn’t what I was looking for. I’m in the process of applying and interviewing at a few different companies, and once I land somewhere new, I intend to set up several recurring monthly payments to some of the organizations above. I hope you’ll consider doing the same.

We’re all in this together. If you’re reading this, stay safe, wear a mask, fight injustice, and hold me and one another accountable to do the right thing.


You know the Potpourri category of Jeopardy, how it’s mostly a hodge-podge of general knowledge questions? That’s this post, because it’s been over a month since my last update, and I just wanted to give everyone a quick update about what I’ve been up to.


Something that isn’t changing with my new role are the languages in which I use to do my work, the primary one of which is PHP. Readers of this space know that I’ve been digging into learning Python this year, and I’m going to continue to do so within side projects for the foreseeable future. Yesterday, I purchased a Humble Bundle of 14 Python books, one of which is Automate the Boring Stuff Using Python by Al Sweigart, the book I’d borrowed from the library just before the pandemic began. Of the 14, there are 9 that are pertinent to what I want and need to learn, so there’s plenty of study time ahead of me. If you’re interested, the bundle is live for another 7 days, so you can get your study on with me.


I created a Twitch account several years ago, but never really used it all that much. However, during these uncertain times (is anyone else sick of hearing variations of that phrase?), I decided it was a great time to start streaming my daily runs of The Binding of Isaac, which for some reason has become the only video game I play, more-or-less, over the past seven years. If you’re interested in seeing what it’s all about, give me a follow. I’m also considering live-streaming some personal coding projects, but I haven’t convinced myself that I’m ready for that just quite yet. Baby steps.

Of Mice and Men

To help me celebrate my first pay day in two months, I ordered myself a Logitech MX Master 3 wireless mouse. And, can I just say, I wish I had done this a long time ago. When I picked up a Linux desktop a few months back, I wasn’t sure I’d ever been able to get back down to one keyboard and one mouse to use between it and my laptop, but lo and behold, the MX Master 3 lets you sync with up to three devices. As if that wasn’t enough, it’s got some nice features, such as built-in forward/back buttons for browsers, a horizontal scroll wheel, and the ability to get a few hours of life out of a single minute of charge. Not only am I happy to finally go down to a single mouse between devices, but I finally get to ditch the poorly designed Apple Magic Mouse when using my laptop. Never again will I need to take a break when my mouse runs out of juice!


It wouldn’t be a true potpourri post without a miscellaneous list of links. Here’s some other cool stuff:

And… that’s about all that comes to mind right now on this overcast Memorial Day holiday. I can’t believe it’s almost June.

A Bold Claim Explained

Two days ago, I tweeted:

Vastly oversimplified opinion: all programming languages are the same.

It is, of course, vastly oversimplified, but borne out of the continuous education I’ve dedicated myself these past few weeks, and of conversations I’ve had with recruiters and potential employers alike.

But I Digress…

As I’ve written about in this space, I have been studying Python. Two weeks ago, I created a repository for an app I named py-bgg, and my goal was to use it as a place to commit my experiments with the language, and refamiliarize myself with some general web development concepts such as API development and database schema design, which I wrote a bit about in my last update.

The main foundation of the py-bgg project is built on Flask, a web framework. To get started, I needed to learn a little bit about how Flask’s routing system worked. Since my app was going to connect to BoardGameGeek, that I’d be pulling down information about users and their collections of games, and that I’d like to reference that data locally, I knew I needed to create a database schema as well. I’d need to know how to connect Flask to my data source, and also how to query against it.

This wasn’t much for a small project: a web framework, a database, some custom routes, and then some basic templates using Jinja2. Somewhere along the way, a friend of mine mentioned he liked working with flask-smorest, a Python module that includes SQLAlchemy and Marshmallow, the former an SQL Toolkit and Object Relational Mapper (ORM), and the latter a library for serializing and deserializing object data.

This introduced a few problems for me. First and foremost, I haven’t worked with an ORM before. As soon as I started integrating flask-smorest with my project, I quickly felt a bit over my head. Suddenly, I wasn’t just learning Python and a web framework, but I was also learning about ORMs and how they replace the need to write database queries (a negative for me, in some ways, since part of this project was to reacquaint myself with writing them), and how to incorporate a serialization/deserialization library into all of it.

Thankfully, some peers in my tech community are also teaching themselves Python right now, and one person in particular and I had both come across “The Flask Mega-Tutorial” by Miguel Grinberg. Chapter 4 in the series talked about SQLAlchemy and ORMs. Unfortunately for me, I was working on a custom app with an incomplete understanding of what I was doing, and I needed to understand how to tear apart the work I had done to that point just to get things back up and running again.

I’m here to report that I eventually got there, and about a week ago, I got my app into a basic state that includes some forms with which to interact to connect to the BoardGameGeek API, pull down some user data, and display a user’s list of games at a particular route. It’s neither production-ready nor something I would ship, but it has served its initial purpose, which was to help me gain some familiarity with how things are done.

All Languages Are The Same

Since I created that initial Python app, I started having ideas for other things I can build, and what else I want to learn next.

I started a small project that involves creating a WordPress plugin to publish my content to an external API, with the idea that I might someday convert this very site to a headless implementation.

I revisited the PHP web framework, Laravel, and as I examined its architecture, thought about building basic web forum software so I could gain a better understanding of how it functions.

I started teaching myself Node.

Through all of this, I came to the conclusion that, beyond standards and syntax, there isn’t any meaningful difference between languages — particularly in the context of software development for the web.

Most web applications require routing so that it loads an expected set of data when visitors access a given URL. They need one or more data sources to store and access information. They often require a caching layer so routes can load that data quickly. They might need user authentication and role-restricted access to some data. They need templates to present that information, styles to make things look nice and interactions to make the app delightful to use. And they need well-structured information architecture on both sides of the application so it’s logical for users and developers alike.

The languages that power the services we all use — PHP, Python, Go, Node, Java, .NET, Ruby, and so on — each contain modules as part of their standard libraries to achieve common tasks. Every language is going to have a way for importing libraries, for scanning filesystems, for connecting to data sources, and for reading and writing to files. The basics of computer science — expressions, conditional statements, data structures, design patterns, algorithms, and so on — are all transportable between languages, leaving you only the syntax and the standards left to discover on your own. On the web, an app is an app is an app, and at some point, it’s all a matter of defining the right tool for the job.

I’ve been having a lot of fun learning Python in particular. This week, I’m giving Node.js the long-overdue attention it deserves. Next week, I might give Go a try. While the syntax will change, the needs of a given project won’t truly fluctuate much.

Next up, figuring out how I can convey that in interviews so I can land my dream job, even if it happens to require a language I don’t yet know.