Twenty years ago I had a few dev plugins I'd drop onto client sites. None of them ever went near WordPress.org. I'd never submitted a plugin for review, never touched the plugin directory's SVN repository, and the thought of doing both for Orbitwrite made me nervous.
This month the Orbitwrite plugin went live on WordPress.org. I built it with Claude, and Claude did most of the heavy lifting.
The brief was a sentence: write the social post for an article inside WordPress, then schedule it or send it now through Orbitwrite. A lot of WordPress has changed since I last wrote a plugin. The block editor didn't exist, so the sidebar is new territory for me, and Claude wrote it in TypeScript with wp-scripts, then mounted the same composer as a box for sites still on the Classic Editor.
Connecting came next. Each WordPress user signs in to their own Orbitwrite account over OAuth, so nobody pastes an API key into a settings page everyone shares. Orbitwrite registers OAuth clients by CIMD, where the client id is a URL to a small JSON document describing the client, and each site serves its own at /wp-json/orbitwrite/v1/oauth-client. That only works on a public HTTPS site with pretty permalinks, so the plugin checks for both and says which to fix before sending anyone off to sign in.
Then the refresh tokens!! Ours rotate, so each one works once, and the block editor fires several requests at the same moment. Two requests that both find an expired token both try to spend it, and the loser disconnects you. add_option() reads and then upserts, so two requests can both take a lock built on it. The plugin takes its lock with a plain INSERT IGNORE on wp_options, which is the kind of WordPress detail I'd never have found on my own.
Images were next.... Bluesky caps an image at 2 MB, X at 5 MB and Instagram at 8 MB, and Orbitwrite refuses an image over the cap. WordPress has already generated a pile of sizes for every upload, so the plugin sends each network the largest one with the same shape that it accepts.
The part that calmed my nerves was the tests. CI runs PHPCS with the WordPress-Extra rules, a PHP 7.4 job for the oldest version the plugin supports, and an end-to-end run that builds a throwaway WordPress on SQLite with a mock Orbitwrite and clicks through connecting, scheduling and auto-share in Chromium. A weekly job checks the slice of Orbitwrite's OpenAPI spec the plugin calls against the live one, so an API change shows up in CI before it shows up for a user. The plugin also passed WordPress's own Plugin Check before I submitted it.
My part was a few forms on WordPress.org and the deploy. That's a GitHub Action using 10up/action-wordpress-plugin-deploy, with my SVN username and password saved as repository secrets, which made me shiver. Pushing a tag like v0.2.0 checks the tag matches the plugin header, the version constant and the readme's Stable tag, builds the plugin and copies it into the SVN repository's trunk and tags/0.2.0. A second workflow pushes banners, screenshots and readme edits to the plugin page whenever they change on main, so I never open SVN at all.
If you've got an old plugin sitting in a client's wp-content folder, it's a few forms and a tag away from WordPress.org. Ours is Orbitwrite, and it shares your next article for you.
