I took over a legacy WooCommerce plugin for a new client last month, and it was a mess. The previous developer had sprinkled get_option() and update_option() calls everywhere. Some option names had the plugin’s prefix, some didn’t, and one clashed with an entirely different plugin, which made settings reset at random. The client was frustrated that their “save settings” button was basically a roll of the dice, and so was I.
My first thought was a global find-and-replace: hunt down every instance of get_option and slap the proper prefix on it. Quick and dirty, and yeah, it would have fixed the immediate bug. But it was a patch over the real problem, not a fix for the architecture. The next developer, or me at 2 AM on a deadline, would make the same mistake again. The fix had to go deeper.
A wrapper class for the WordPress Options API
Stop calling the WordPress Options API functions directly. For any plugin of real size, doing so is asking for trouble. Instead, create a simple “gatekeeper” class that handles all the interactions for you. It’s the only part of your plugin that should be allowed to talk to the options table.
The good news is that it’s not much work. You’re creating a simple wrapper that enforces your rules automatically, such as making sure every option key is prefixed correctly. This is a stripped-down version of a fuller design pattern for the options API, an idea I first saw laid out at carlalexander.ca.
<?php
/**
* Manages plugin options with a consistent prefix.
*/
class MyPlugin_Options
{
private $prefix = 'my_plugin_';
/**
* Gets a prefixed option from the database.
*
* @param string $name The option name, without prefix.
* @param mixed $default The default value.
* @return mixed
*/
public function get($name, $default = null)
{
return get_option($this->prefix . $name, $default);
}
/**
* Sets a prefixed option in the database.
*
* @param string $name The option name, without prefix.
* @param mixed $value The value to set.
*/
public function set($name, $value)
{
update_option($this->prefix . $name, $value);
}
/**
* Removes a prefixed option from the database.
*
* @param string $name The option name, without prefix.
*/
public function remove($name)
{
delete_option($this->prefix . $name);
}
}
// Now, instead of this scattered everywhere:
// update_option('my_plugin_api_key', 'some_value');
// You do this through your gatekeeper:
// $options = new MyPlugin_Options();
// $options->set('api_key', 'some_value');Why this works
By routing every call through this class, you fix the problem at its source. You can’t “forget” the prefix because the class adds it. You can’t get a typo in the option name across 15 different files, because you define it once. You’re building guardrails that make the right thing easy and the wrong thing hard.
- Stop scattering raw
get_optionandupdate_optioncalls through your plugin. That’s what causes this kind of mess. - A wrapper class keeps the logic in one place. It’s about ten minutes of work that saves hours of debugging later.
- The prefix gets enforced automatically, so there’s no more guesswork or naming conflicts.
- The codebase gets cleaner and more predictable to work in.
This stuff gets complicated fast. If you’re tired of debugging someone else’s mess and just want your site to work, drop my team a line. We’ve probably seen it before.