What fixing other people’s WordPress plugins taught me about my own code

Christopher Ross

6 min read

WordPress & CMS engineering · Fort Erie, Ontario

The reply was three words. “Thanks @thisismyurl!”

It landed on a small fix I’d given the edit-flow plugin: stale links in the module help sidebars, a broken GitHub org link in four modules, HTTP to HTTPS across all six. Not clever work. The kind of patch a maintainer can read in thirty seconds and merge before lunch. GaryJones merged it and said thanks, and I closed the tab feeling good about my evening.

Then I remembered what edit-flow is to me.

It’s the plugin my own editorial tool is forked from.

A few years ago I took edit-flow, renamed the fork editloft, and bent it to how I actually plan and schedule writing. To me that will always be the beautiful thing about WordPress and open-source tools. I found a tool that was amazing; it did 90% of what I needed it to do, and I was not only allowed but encouraged to make it my own. I’d been living in my copy for so long that I’d stopped thinking about the upstream at all. Fixing the parent sent me back to read the child, and I read it more carefully than I had in months. That turns out to be the whole lesson of the week, so let me back up to how I got there.

Eighteen pull requests, one merge

I spent most of my evenings this week giving small, correct patches to WordPress plugins I don’t own. Eighteen of them, as of the Wednesday I sat down and counted: eighteen pull requests submitted across the ecosystem, one merged so far, the rest open and waiting on maintainers who have day jobs.

Most were the same humble shape. A URL written straight into HTML without esc_url() wrapped around it. An input read without sanitize_text_field() on the way in. The unglamorous half of WordPress security, the part that never makes a conference talk because there’s nothing to demo. You find one, you fix one, you write a commit message that explains the why for the next person, and you move on to the next repo. This week that meant new ground for me: pressbooks, wp-migrate-db, nginx-helper, login-with-google, safe-redirect-manager, WP-Job-Manager, Sensei, ElasticPress, code-snippets. First time filing against most of them.

Some of the older batch had already landed. An unescaped SoundCloud iframe src in Jetpack. An inverted isset() check in xwp/stream that quietly made the search box ignore whatever you typed, merged the same day. A PHP 8 TypeError in Simple History where wp_get_referer() can return false and the code fed it straight into strpos(). My first-ever merge into antispam-bee. And four esc_url() fixes sitting open against WordPress core block renderers, on post-author-name, post-date, and post-featured-image, tied to a couple of Trac tickets. Those are core, so they wait, and honestly they should.

Not everything landed, and I think the honest version matters more than the highlight reel.

Two PRs were closed with no reply at all. One repo I’d carefully built a branch for turned out to have been archived since 2020, so I discarded the work. One maintainer took half my fix and declined the other half, with a reason I disagreed with and merged anyway because it’s their house. That’s the real texture of contributing to other people’s code. You are a guest. The wins are quiet and the rejections are quieter.

What changed this week was that I stopped doing it ad hoc. I built the tooling to make the push repeatable: a pre-flight validator that checks a patch against a repo’s own contribution rules before I open the PR, an advisor that verifies my targets against the GitHub API so I’m not filing against a dead fork again, and a contribution ledger that records every submission, every merge, and yes, the one “Thanks.” I’d been losing track of my own work. Now I don’t.

Reading the parent taught me to read the child

So I went back into editloft with the same eyes I’d been using on everyone else’s code all week. And I found two bugs.

The first: a draft was showing up in two places at once, on the calendar grid and in the “unscheduled” sidebar at the same time. Two queries with quietly overlapping definitions of what “unscheduled” even means. The second was worse, and better. Attempt to read property "slug" on null. The function get_default_custom_status() could return null, and the code three lines down read ->slug off it anyway. Right above that line, in the original authors’ own hand, was a comment: // @todo Check to make sure that the default exists.

They saw it. They wrote it down. And then they left it, and the fork carried that gap forward into my copy, where it sat for years until this week.

I fixed both today. Reading edit-flow taught me to read editloft. I don’t think I’d have found either one if a stranger hadn’t said thanks for a thirty-second patch on Monday. Last week the work was all about keeping a platform and a curriculum moving in step; this week it was the opposite direction, the smallest possible patches pulling my attention back to my own foundations.

That thanks kept working on me after I closed the tab.

There’s a donate page on this site where I rank the ways people can help, and contributing to the open-source projects sits at number two, above money. I wrote that ranking believing it. I’m less sure now that I had the direction right. I keep telling people that helping with the projects is good for the projects. What I didn’t say, because I hadn’t noticed it yet, is how much it gives back to whoever does the helping. The same instinct runs through the work I take on for clients: the patch you submit to a stranger’s code and the audit you run on your own end up teaching you the same things.

The @todo is gone now. I’m still thinking about how long it sat there with someone’s eyes on it.

Keep reading

Working through something on your own site? Get in touch →

Leave a Reply

Your email address will not be published. Required fields are marked *

Your rating (optional)

Your name and email are stored with your comment; only your display name is shown publicly. See our privacy policy.