I have been doing this ever since WordPress was the new kid on the block. Back when it was a fork of b2/cafelog and adopting it was a bit risky, like backing a band who had performed in your local pub. When themes consisted of one index.php file and a stylesheet. When wp-config.php file was salt-less and security was more about attitude. When WordPress was a blogging platform that ran on something north of 40% of websites, and I was secretly building on top of it all the while.
Plugins? Written many. Themes? Too many to count, at least two of which I’m obliged to describe as “of their era.” Sites for clients, custom post types, hacks, kludges and functions.php files which grew like knotweed. Twenty years of programming muscle memory.
So when I finally created something useful, something really worth being shared instead of some bespoke solution to a weird requirement from some client, I assumed getting it listed on the WordPress Plugin Directory will be a breeze. My victory parade. Just upload the plugin to WordPress.org, wait for the fireworks.
Reader, it was not a victory parade.
The Review: A Humbling
This is what no one tells you about years of experience: much of it is years of habit formation. And habit? Habit is mistake with tenure.
The function of the plugin review team is to take your beautifully written code and examine it as an inspector does your belongings at customs. And every single issue raised elicits the same response, in the same order:
- Mild outrage. “I’ve been doing this long enough that these guys were still learning to walk when I was doing it.”
- Then reading the guideline they cited.
- “…Oh, right, that’s how you do it. Well, I never.”
Repeat until approval or death.
The Greatest Hits
Sanitize everything, escape everything. I’ve known this. Naturally, I’ve known this. I’ve known it for years, the same way you know you’re supposed to floss. But knowing about sanitize_text_field() and making sure to run each and every single $_POST variable through the appropriate function in the appropriate manner, both sanitization and then escaping – esc_html(), esc_attr(), esc_url(), make the right choice, no you can’t just use esc_html() for everything – before sending it back to the screen, even the outputs “that couldn’t possibly” have anything malicious in them? That’s a different religion altogether. The reviewers are its ministers, and they will spot the one line where you didn’t echo appropriately. They spotted mine. In a little admin notice I had copy-pasted from something I wrote in 2011.
Prefix everything. Functions, classes, options, transients, hooks — all of them have your unique prefix, because you are coming into a communal house and bringing with you nine thousand neighbors and if both of you decide to use a function called get_settings(), everything will burn down in flames. My function was called — and believe me, I am truly ashamed of this — init_options(). Twenty years later. It’s like a plumber coming without a wrench.
Enqueue your scripts the right way. No, you cannot just drop a script tag in the footer. Yes, I understand, I understand how well it worked and yes, since 2009. This is the reason wp_enqueue_script() exists: to enable WordPress to handle dependencies and versioning and to make sure your jQuery doesn’t hit another jQuery in a parking lot. As soon as you start doing it the right way, you’ll see how elegant the dependency system actually is and that you’ve been missing out on something for the past fifteen years.
Nonces. Real nonces. Properly checked. Not just something added to the form to make it look official, like the burglar alarm box outside a house. wp_verify_nonce() and checking for capability, because the point of a nonce is to tell you where the form came from, not whether someone should be able to use it. The difference was something that had obviously eluded me for some time. Fine. FINE.
No direct file calls. Each PHP file starts with if ( ! defined( 'ABSPATH' ) ) exit; at the top, since somewhere out there is an apathetic teenager making a direct request to your PHP files to see what comes out. This one I already knew. I’m claiming it as a victory. I need the victory.
Readme.txt. Oh, readme? The only file format with its very own unique header syntax, “Tested up to” field that you won’t remember to update for each release from here to eternity, and a validator that looks down on you like an angry parent. Get the stable tag incorrect and your plugin directory will happily distribute the wrong version to all your users – what a great way to learn about SVN!
SVN. In the year two thousand something or other. I have Git skills hardwired into my skeleton, and plugin directory gives me Subversion as if it was giving me a fax machine. trunk, tags, no pull requests, no CI, just you, a checkout, and a growing certainty that you are about to commit the vendor directory. (I did. And I barely stopped myself.)
The Bit Where I Admit They’re Right
Here is the plain truth behind all the complaints: everything they pointed out about the plugin improved it.
The review process is irritating just like a good code review should be – someone with a new perspective who will judge not the intention but the actual code you’ve written. Twenty years of development practice mean twenty years of assumptions and approaches that you haven’t questioned since then. Reviewers’ sole purpose is to do exactly that.
The things that I thought were “a matter of course” were neither assumptions nor knowledge. They were scars that formed from “this works and therefore I haven’t bothered with checking how it works for many years.” And the humbling part of it is the fact that the proper approach has been in the developer documentation all along, fully described and with examples, patiently waiting for me to get too experienced to look there.
As a result, the plugin was finally approved, in the end, through the email exchange that had its own table of contents. It is a better piece of code than I could have delivered on my own. I am a better developer because of this review process. Which is frustrating to admit.
Some habits have seniority.

Comments (0)