WordPress

Building a theme options page with the Settings API instead of raw options

WP

Our early custom themes had homegrown options pages, a form, a save handler, manual sanitization, cobbled together fresh for basically every project. It worked but every project reinvented it slightly differently, which made maintenance annoying, especially handing a theme off to the other of us to fix six months after building it.

Switching to WordPress's built-in Settings API took a day of reading unfamiliar documentation but now every theme options page follows the same register_setting, add_settings_section, add_settings_field pattern. Nonces, sanitization callbacks and error messages come along for free, generated consistently by the API rather than hand-rolled slightly differently each time.

The learning curve was real

The Settings API's documentation, what exists of it, assumes a level of familiarity with how WordPress hooks and callbacks chain together that took us a genuinely confusing first afternoon to work through. The pattern of registering a setting, then a section, then individual fields, each with its own callback function that echoes the actual form markup, feels needlessly indirect coming from writing a plain HTML form and a save handler directly. It clicked eventually, but "eventually" here means a full day lost to trial and error before the first working options page came together.

The tradeoff

The tradeoff is it's more verbose to set up a single field than our old shortcut method was, several functions and callback registrations for what used to be one line of raw HTML plus a value in $_POST, but for anything with more than three or four options it pays for itself immediately, especially when a client half-fills a form and the sanitization catches it instead of a broken value hitting the database.

We've also noticed one quieter benefit: because the Settings API generates markup consistently, our theme options pages now all look and behave the same way regardless of which of us built them, down to how validation errors are displayed. That consistency alone has probably saved as much support time as the sanitization has, since neither of us has to relearn a previous version of ourselves' particular styling choices when picking up an older project.

Where we're keeping it simple

We're not using every feature the Settings API offers, there's more flexibility in there around custom rendering and conditional fields than most of our theme options pages actually need. We stick to the same handful of field types, text, checkbox, a simple select dropdown, across nearly every project, resisting the urge to build something more elaborate just because the API technically supports it. A theme options page for a small business client rarely needs more than a logo upload, a phone number, and a couple of social links, and building anything more flexible than that would be effort spent on a problem we don't actually have yet.

We're standardizing on this pattern for every new theme from here forward, and slowly retrofitting the older homegrown options pages whenever we're already back in a project for an unrelated change, rather than dedicating standalone time to migrating theme by theme just for the sake of consistency.

← 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