Latest News

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.


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.