WordPress

Cleaner JSON endpoints in WordPress with a proper plugin structure

WP

A couple of years ago we hacked together JSON endpoints in WordPress with raw rewrite rules and query vars, and it worked but it was fragile every time WordPress core changed something underneath it. We rebuilt it properly this year as a small, dedicated plugin.

The core idea didn't change much, still rewrite rules mapping URLs to a callback, still json_encode() on the way out, but we structured it as a proper plugin class instead of loose functions in functions.php, and added a basic API key check on every request rather than leaving it wide open.

Why the old version kept breaking

The original version lived as loose functions dropped into a theme's functions.php file, which meant every theme update or theme switch put the endpoint at risk of silently disappearing, since functions.php isn't meant to be a permanent home for functionality that should survive independent of which theme happens to be active. A plugin, by contrast, keeps working regardless of theme changes, which is the more correct place for this kind of site-level functionality to live in the first place, something we understood in principle a couple of years ago but hadn't bothered to act on until this rebuild forced the question.

What structuring it as a class actually bought us

Wrapping the endpoint logic in a plugin class rather than a handful of loose functions gave us a clean, single place to register hooks, store configuration like the API key, and add new endpoints later without polluting the global function namespace, a real risk in a codebase with several plugins active simultaneously, any of which might define a function with the same name and cause a fatal collision. It's a small structural change but one that's already made adding a second endpoint, for a different data type the client needed exposed, noticeably faster than the first one was to build from scratch.

Where we're keeping this simple deliberately

There's a full JSON API plugin ecosystem starting to appear that we're keeping an eye on, but for the handful of endpoints most of our client projects actually need, our own small plugin is still easier to reason about than adopting something larger, with its own configuration surface and update cadence to track. We'd revisit that decision the moment a project needs something our simple plugin can't reasonably do, real authentication beyond a shared key, proper routing with parameters, but we're not building toward that need speculatively before a project actually requires it.

← Back to the journal

Have a project in mind?
Let’s talk.

Tell us where you are and where you want to go. We'll map the fastest route between the two.

Currently accepting new clients