Series: Rethinking PHP Development in WordPress

My web development career began in earnest in January 2013 when I took on an internship at a small agency in the Twin Cities during the last semester of my degree program at my local community college. There, I was first introduced to WordPress, Shopify, and CakePHP, the framework that the owner of the company used to create a custom CMS that many of his clients used.

Because I was brand new to development and the agency world, the ins-and-outs of a custom application framework didn’t really resonate with me right away. And, since I was the only employee, my boss didn’t really have time to teach me how to support it. Instead, I took on many of the theme build projects that came through the door where we chose WordPress as the platform. It was at that agency job where I first familiarized myself with everything WordPress had to offer, from hooks and taxonomies and custom post types to the theme and plugin APIs, and everything in between.

The current version of WordPress in January 2013 was version 3.5. Just two-and-a-half years prior, version 3 was released with an updated dashboard, improved custom post types and taxonomies, custom menu management, multisite(!), and more. I wasn’t in anywhere near the beginning, but by the time version 3.5 was released, it was slowly becoming evident of just how much I could achieve as a developer atop this platform.

Change is Slow to Come

Naturally, as with all things tech, a lot has changed in the subsequent years. Useful parts of the WordPress ecosystem like WP-CLI, the REST API, the Customizer, and the Gutenberg editor didn’t exist when I started. Many of these features had been hugely controversial at the time they were released; some, perhaps, haven’t lived up to their promise. But, over time, we generally come to accept the quirks that are there and make our best effort to improve upon the parts we don’t like.

The features of WordPress that have thrived have been a result of passionate developers contributing their time and effort to propose new ideas, advocate for their necessity, and work through a somewhat bureaucratic process that requires lots of coding, discussion, testing, documentation, and – with a little luck – ultimate approval and inclusion in core.

This is the double-edged sword that comes with contributing to a legacy platform that powers such a significant part of the web. “Democratize publishing” has long been the mission of the WordPress project, and what that means is having a platform that’s not only easy to set up and start using quickly, but it also means having one that is intuitive to extend and modify as one sees fit, regardless of their skill set. It’s the latter part that causes some friction within the development community, because there are those (like me) who wish to be able to include the latest and greatest language features into their projects, but when contributing to parts of the platform that can affect a lot of people, we have to be mindful about how much we push the envelope.

Then Along Came Gutenberg

In many ways, the Gutenberg editor project has turned the WordPress mission on its head. This is due to a number of reasons, not least of which I think are enthusiasm around advancements in the JavaScript community in the past 7 years, and with the rise of burgeoning competitors like Squarespace, Medium, and Wix, which were providing more intuitive interfaces with which to build websites than WordPress had been offering in recent years.

In my view, the changes on the JavaScript side of the WordPress sphere have been a great advancement, though they come at a cost. Developers who aren’t as familiar with JavaScript may find it more difficult to build on top of the platform. And, as my friend Michelle Schulp astutely put it, compiled JavaScript makes it more difficult to discover readable code, something many new and aspiring developers use to learn and grow.

As a community, I think we can do better. And, as an engineer, I think we can and should take the learnings from advancements on the JavaScript side and apply them to PHP. What that means to me is that we should be more willing to revisit how PHP code is structured in the WordPress environment, but that we should do so in a way to help educate and elevate developers to learn how to write cleaner, more organized, and more reusable code.

Doing My Part

Since those early days of cutting my teeth at my first agency job, I’ve tried to stay current with developments in the broader web language communities. Like JavaScript, PHP has advanced a lot in the time since WordPress was first written, but the community hasn’t necessarily been able to take advantage of these advancements due to the intense dedication to backward compatibility. Gutenberg, in many ways, has shown us that we can start to take risks, that we can iterate, try new things, and occasionally make a few mistakes with the goal of coming out with a stronger product in the long term.

I’ve started jotting down notes about the various things I’ve learned and observed from working on personal projects, large agency clients, and most recently in my role on the product team at Rocketgenius. My aim over the next several months is to start writing more about these various topics, with the goal of sharing what I know (or think I know) about software development. Additionally, I hope to get us thinking about how we might apply some of these concepts within the WordPress ecosystem, with the longer-term goal of helping level up other engineers build more robust, scalable, easier-to-understand systems.


As of right now, my list of topics in this series will include the following:

  • Using objects instead of arrays for data structures
  • PHP namespaces
  • Type-hinting method parameters and return values
  • Reducing the number of different return types within methods
  • Reducing conditional code complexity
  • Creating more (and more descriptive) methods in place of clarifying comments
  • The first five principles of S.O.L.I.D., with an emphasis on single-responsibility
  • Class file organizational hierarchies
  • How to spot code smells
  • Abstracting shared and repeated behavior

It’s likely that going through the process of distilling my thoughts in these areas and how they specifically apply to the way things are frequently done in the WordPress ecosystem will lead to even more thoughts worth exploring. I hope you’ll join me on this journey, and that it will spark some additional online discussion. I’m looking forward to it.

WP-CLI for multi-language development

This week at Rocketgenius, I was working on some visual refinements in one of our Gravity Forms add-ons. Because our suite of plugins supports multiple languages, part of my ongoing education is learning all about the tools and processes required to build our products for international support.

I’m just getting back into the swing of things again with full-stack development, and this week was the first time in my career where I’ve styled front-end components with internationalization in mind. It’s been an eye-opener for me just how limiting the web can be without this extra attention to detail, and I’m eager to start looking at my personal projects with fresh eyes, figuring out how I can make them accessible to an even broader audience.

One major aspect of internationalization is to style your user interfaces so that they can be read both left-to-right, such as for Latin-based languages, as well as right-to-left, for languages such as Arabic, Hebrew, Pashto, and so on.

Naturally, WordPress has multi-language support, but if you don’t know other languages (and perhaps don’t have every aspect of the user interface memorized), it can be challenging to find your way to the language switcher, then to the part of the admin you want to test (and then back again!). Thankfully, WP-CLI has some helpful commands that can ease this transition for you. Let’s review them.

Installing Languages

First, you’ll need to make sure whichever language you want to use is installed in your site, plugin, or theme. WP-CLI has a top level command called wp language which, when you run it, will reveal sub-commands for core, plugin, and theme! Running wp language core --help will show you all the commands you can run on core. The --help flag, of course, will show you available subcommands for the other commands, too.

Initially, these commands are going to be most useful:

  • wp language core list shows you the list of available languages, their english name, native name, installation status, the last update date, and whether an update is available.
  • wp language core install <language> will install one of the languages for you, where language is the identifier for a particular language. For instance, if I wanted to install Arabic, I would run wp language core install ar.

I encourage you to give these commands a try, and also explore the rest of the CLI commands available to you to see how you can work with languages you have already installed.

Switching Languages

Once you have a language installed, you can easily switch between them using a different CLI command: wp site switch-language <language>, where language is once again the identifier from the list command I mentioned previously.

Thus, if you installed Arabic in the previous step, you can run wp site switch-language ar, and WP-CLI will set the language of your WordPress site to load in Arabic instead. Simply refresh your browser page!

Styling Components

If your admin screen contains components with your own custom markup, and you haven’t considered right-to-left languages for your styles before, you might be surprised at the appearance of those components on the screen. In particular, directional margins and padding will be waaay off, because your properties were written with a left-to-right presentation in mind.

Thankfully, WordPress knows at the time you’ve activated a right-to-left language that it needs to provide you with the tools you need to style these components according. The html element includes a dir attribute when languages are read from right-to-left. Thus, any adjustments you need to make can be done by nested your element selectors in an html[dir="rtl"] selector.

To avoid needing to write lots of additional overwrite rules for the right-to-left counterparts, I prefer wrapping directional-specific properties in an html:not([dir="rtl"]) property. Here’s an example:

html:not([dir="rtl"]) .sidebar {
    margin-left: 1rem;

html[dir="rtl"] .sidebar {
    margin-right: 1rem;

Were I not to include the the wrapper for the left-to-right rule, I’d need to override the value of margin-left in the right-to-left selector. If you have lots of directional values, that can quickly add up.

Bash Aliases

Once you have a single right-to-left language installed, you can make it even easier to switch between your preferred left-to-right and right-to-left languages. Create a couple of Bash aliases, and reload your terminal!

alias ltr="wp site switch-language en_US"
alias rtl="wp site switch-language ar"

Then, when you need to switch between directional language types, it’s as easy as typing ltr or rtl in the command line. Nice!


Multi-language development opens up a whole realm of possibilities for your website. Paying attention to the UX presentation, in addition to providing text translation (naturally, not covered by this article), makes your content available to a much wider audience. Hopefully this small collection of commands will give you the extra encouragement you need to keep internationalization in mind when you work on your next project.

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.