# Designing classes for the WordPress options API

Much like the [plugin API](https://carlalexander.ca/wordpress-adventurous-plugin-api/), it's almost impossible to build a plugin without using the [options API](https://carlalexander.ca/wordpress-adventurous-options-api/). This can be a problem if you're trying to [learn object-oriented programming with WordPress](https://carlalexander.ca/learn-object-oriented-programming-using-wordpress/). You need a way to build a class around it. Lucky for us, this is a lot less complicated to do than with [the plugin API](https://carlalexander.ca/designing-system-wordpress-event-management/). The options API is really nothing more than an API around a [data store](https://en.wikipedia.org/wiki/Data_store). Our job as designers is simple. We need to design a class that mirrors this API. That said, we don't have to limit ourselves to just copying the options API as is. We can also push things further by adding some extra functionality around it. This is what makes designing a class around the options API so interesting.

# Review options API

But first, let's do a quick review of the options API. As we mentioned earlier, the options API is an API designed to interact with a data store. This data store is the [`wp_options`](https://codex.wordpress.org/Database_Description#Table:_wp_options) table. The options API has functions for [adding](https://codex.wordpress.org/Function_Reference/add_option), [deleting](https://codex.wordpress.org/Function_Reference/delete_option), [getting](https://codex.wordpress.org/Function_Reference/get_option) and [updating](https://codex.wordpress.org/Function_Reference/update_option) these options. That said, in practice, there's no reason to use the adding function. (Updating an option that doesn't exist will create the option for us.) So we're not going to use the adding function with our class. # Building our basic Options class

We're going to start by building an Options class that mirrors the options API. This means that, at first, our class will only be a wrapper around the API. But don't worry! After that, we'll look at adding some extra features to it. ```
/**
 * Manages options using the WordPress options API.
 */
class MyPlugin_Options
{
    /**
     * Gets the option for the given name. Returns the default value if the value does not exist.
     *
     * @param string $name
     * @param mixed  $default
     *
     * @return mixed
     */
    public function get($name, $default = null)
    {
        return get_option($name, $default);
    }

    /**
     * Removes the option with the given name.
     *
     * @param string $name
     */
    public function remove($name)
    {
        delete_option($name);
    }

    /**
     * Sets an option. Overwrites the existing option if the name is already in use.
     *
     * @param string $name
     * @param mixed  $value
     */
    public function set($name, $value)
    {
        update_option($name, $value);
    }
}
```

Here's our basic `MyPlugin_Options` class. It has three methods: `get`, `remove` and `set`. As we just mentioned, each method is a simple wrapper for an options API function. You might wonder why we picked these names for our class method. The `get` method makes sense with the `get_option` function. But using `update` doesn't make sense when it's both adding and updating an option. `set` makes more sense in that context since we're setting an option in our data store. As for the choice of `remove` as a method name, this is more of a personal choice. Removing an option from a data store makes more sense than deleting an option. But feel free to use whichever names you prefer! (There's no right answer!) # Adding new functionality

Right now, our `MyPlugin_Options` class is pretty underwhelming. It's only a wrapper around options API functions. But this was just the beginning! Now, we get to the fun part! Let's look at adding some new functionality to our `MyPlugin_Options` class. There are quite a few things that we can do now that we have our foundation in place. ## Checking if an option exists

The first thing that we can do is create a method that checks if an option exists or not. This is a good helper method to have since checking if an option exists is a pretty common thing to do! We'll call this method the `has` method. ```
/**
 * Manages options using the WordPress options API.
 */
class MyPlugin_Options
{
    // ...

    /**
     * Checks if the option with the given name exists or not.
     *
     * @param string $name
     *
     * @return bool
     */
    public function has($name)
    {
        return null !== $this->get($name);
    }

    // ...
}
```

As you can see above, there's nothing too complicated about our `has` method. We leverage our existing `get` method to fetch an option with the `name` argument. Since we didn't pass a default value to the `get` method, it'll return `null` if it doesn't find our option. We use this fact to check if the option exists or not. We do this by using the `!==` [comparison operator](https://secure.php.net/manual/en/language.operators.comparison.php). It'll only return `true` if `get` returns `null` and nothing else. (If we used `!=`, PHP would return `true` for empty strings, empty arrays, `0` and `false`.) ## Better handling of arrays

One issue that's a bit annoying with the options API is how it handles arrays in certain situations. What do we mean by that? Let's imagine for a moment that you save an empty array as an option like this: ```
update_option('myplugin_option', array());
```

We just used the `update_option` to save an empty array as the `myplugin_option` option. Now, you might think that the options API would save an empty array in the database in that situation. But it didn't, it saved an empty string. This becomes a problem when you use the `get_option` function. ```
$maybe_array = get_option('myplugin_option', array());

foreach ($maybe_array as $item) {
    // ...
}
```

The above code will generate a PHP error even if we saved an empty array beforehand. That's because the `get_option` function will return an empty string. And that's even if we said that the default value was an array. ```
$maybe_array = (array) get_option('myplugin_option', array());

foreach ($maybe_array as $item) {
    // ...
}
```

Now, we can fix that by using [type casting](https://en.wikipedia.org/wiki/Type_conversion) like we did above. But it's easy to forget about it and have bugs in your code because of it. That said, it's something that we can fix with our `MyPlugin_Options` class! ```
/**
 * Manages options using the WordPress options API.
 */
class MyPlugin_Options
{
    // ...

    /**
     * Gets the option for the given name. Returns the default value if the value does not exist.
     *
     * @param string $name
     * @param mixed  $default
     *
     * @return mixed
     */
    public function get($name, $default = null)
    {
        $option = get_option($name, $default);

        if (is_array($default) && !is_array($option)) {
            $option = (array) $option;
        }

        return $option;
    }

    // ...
}
```

As you can see, we modified the `get` method inside our `MyPlugin_Options` class. We added a guard clause that does two checks to see if it should cast the option retrieved by the `get_option` function as an array. First, it checks if the default value that we got is an array using [`is_array`](https://secure.php.net/manual/en/function.is-array.php). If it is, it checks if the option retrieved by the `get_option` function is also an array. Only if it isn't does it cast the option as an array. ## Prefixing our options

A good habit to have when building a plugin is to prefix our plugin options. This can be annoying to do all the time when you're building your plugin. But with our `MyPlugin_Options` class, it's easy to implement! ```
/**
 * Manages options using the WordPress options API.
 */
class MyPlugin_Options
{
    /**
     * The prefix used by all option names.
     *
     * @var string
     */
    private $prefix;

    /**
     * Constructor.
     *
     * @param string $prefix
     */
    public function __construct($prefix = '')
    {
        $this->prefix = $prefix;
    }

    // ...
}
```

First, we want to add a constructor to our `MyPlugin_Options` class. This constructor has a single parameter called `prefix`. That's the prefix that we want to use with all our options. We store the value of the `prefix` in the `prefix` internal variable. By default, `prefix` is an empty string. This means that our updated `MyPlugin_Options` class will behave as it did earlier by default. ```
/**
 * Manages options using the WordPress options API.
 */
class MyPlugin_Options
{
    // ...

    /**
     * Gets the option for the given name. Returns the default value if the value does not exist.
     *
     * @param string $name
     * @param mixed  $default
     *
     * @return mixed
     */
    public function get($name, $default = null)
    {
        $option = get_option($this->prefix . $name, $default);

        if (is_array($default) && !is_array($option)) {
            $option = (array) $option;
        }

        return $option;
    }

    /**
     * Checks if the option with the given name exists or not.
     *
     * @param string $name
     *
     * @return bool
     */
    public function has($name)
    {
        return null !== $this->get($name);
    }

    /**
     * Removes the option with the given name.
     *
     * @param string $name
     */
    public function remove($name)
    {
        delete_option($this->prefix . $name);
    }

    /**
     * Sets an option. Overwrites the existing option if the name is already in use.
     *
     * @param string $name
     * @param mixed  $value
     */
    public function set($name, $value)
    {
        update_option($this->prefix . $name, $value);
    }
}
```

Above is the rest of our updated `MyPlugin_Options` class. All that we did is concatenate our `prefix` internal variable to every `name` variable. Everything else stayed the same. ### Prefixing using inheritance

Now, you don't have to rework the `MyPlugin_Options` class to add the prefix functionality. We can also do it by using [inheritance](https://carlalexander.ca/using-inheritance-wordpress/). This would let us keep our original `MyPlugin_Options` as is. ```
/**
 * Manages options using the WordPress options API using a prefix.
 */
class MyPlugin_PrefixedOptions extends MyPlugin_Options
{
    /**
     * The prefix used by all option names.
     *
     * @var string
     */
    private $prefix;

    /**
     * Constructor.
     *
     * @param string $prefix
     */
    public function __construct($prefix)
    {
        $this->prefix = $prefix;
    }

    /**
     * Gets the option for the given name. Returns the default value if the value does not exist.
     *
     * @param string $name
     * @param mixed  $default
     *
     * @return mixed
     */
    public function get($name, $default = null)
    {
        return parent::get($this->prefix.$name, $default);
    }

    /**
     * Checks if the option with the given name exists or not.
     *
     * @param string $name
     *
     * @return bool
     */
    public function has($name)
    {
        return parent::has($name);
    }

    /**
     * Removes the option with the given name.
     *
     * @param string $name
     */
    public function remove($name)
    {
        parent::remove($this->prefix.$name);
    }

    /**
     * Sets an option. Overwrites the existing option if the name is already in use.
     *
     * @param string $name
     * @param mixed  $value
     */
    public function set($name, $value)
    {
        parent::set($this->prefix.$name, $value);
    }
}
```

Here's our `MyPlugin_PrefixedOptions` class which extends our original `MyPlugin_Options` class. The constructor is pretty much the same as the previous one that we did for the `MyPlugin_Options` class. The only difference is that we didn't make the `prefix` parameter optional. We want people who use our `MyPlugin_PrefixedOptions` class to supply a prefix to the class. ### Getting the name of the prefixed option

Using a prefixed options class like the ones we just saw isn't without issues. The most common one you might run into is you might need to know the full name of an option. For example, it's necessary to know the name of an option if you want to register it with the [settings API](https://codex.wordpress.org/Settings_API). ```
/**
 * Manages options using the WordPress options API.
 */
class MyPlugin_Options
{
    /**
     * The prefix used by all option names.
     *
     * @var string
     */
    private $prefix;

    /**
     * Constructor.
     *
     * @param string $prefix
     */
    public function __construct($prefix = '')
    {
        $this->prefix = $prefix;
    }

    /**
     * Get the option name used to store the option in the WordPress database.
     *
     * @param string $name
     *
     * @return string
     */
    public function get_option_name($name)
    {
        return $this->prefix . $name;
    }

    // ...
}
```

Above, we reworked the `MyPlugin_Options` class that we saw earlier. We added a new method called `get_option_name`. It returns the option name concatenated with the `prefix` inside our class. We also made the method `public` so that you can use it outside the class. ```
/**
 * Manages options using the WordPress options API.
 */
class MyPlugin_Options
{
    // ...

    /**
     * Gets the option for the given name. Returns the default value if the value does not exist.
     *
     * @param string $name
     * @param mixed  $default
     *
     * @return mixed
     */
    public function get($name, $default = null)
    {
        $option = get_option($this->get_option_name($name), $default);

        if (is_array($default) && !is_array($option)) {
            $option = (array) $option;
        }

        return $option;
    }

    /**
     * Checks if the option with the given name exists or not.
     *
     * @param string $name
     *
     * @return bool
     */
    public function has($name)
    {
        return null !== $this->get($name);
    }

    /**
     * Removes the option with the given name.
     *
     * @param string $name
     */
    public function remove($name)
    {
        delete_option($this->get_option_name($name));
    }

    /**
     * Sets an option. Overwrites the existing option if the name is already in use.
     *
     * @param string $name
     * @param mixed  $value
     */
    public function set($name, $value)
    {
        update_option($this->get_option_name($name), $value);
    }
}
```

Next, we reworked the rest of the class to use our new `get_option_name` method. And now that you have the `get_option_name` method, you can register options using the settings API. Here's a small code sample to show you how: ```
register_setting('myplugin_admin', $options->get_option_name('option_name'));
```

# Creating option classes for site options

You can also use similar classes to check for site options. Site options are options that are only used when you use the WordPress [multisite feature](https://codex.wordpress.org/Multisite). WordPress stores these options in a [different table](https://codex.wordpress.org/Database_Description#Table:_wp_sitemeta) as well. Creating a class to use site options isn't complicated. Instead of using the options API functions for regular options, we just need to use the ones for site options. This results in a class that looks like this: ```
/**
 * Manages site options using the WordPress options API.
 */
class MyPlugin_SiteOptions
{
    /**
     * Gets the site option for the given name. Returns the default value if the value does not exist.
     *
     * @param string $name
     * @param mixed  $default
     *
     * @return mixed
     */
    public function get($name, $default = null)
    {
        $option = get_site_option($name, $default);

        if (is_array($default) && !is_array($option)) {
            $option = (array) $option;
        }

        return $option;
    }

    /**
     * Checks if the site option with the given name exists or not.
     *
     * @param string $name
     *
     * @return bool
     */
    public function has($name)
    {
        return null !== $this->get($name);
    }

    /**
     * Removes the site option with the given name.
     *
     * @param string $name
     */
    public function remove($name)
    {
        delete_site_option($name);
    }

    /**
     * Sets a site option. Overwrites the existing site option if the name is already in use.
     *
     * @param string $name
     * @param mixed  $value
     */
    public function set($name, $value)
    {
        update_site_option($name, $value);
    }
}
```

As you can see, the `MyPlugin_SiteOptions` class really is almost the same as the `MyPlugin_Options` class. We changed the options API functions that the class used, but that's it. Nothing else changed. ## Using an abstract class

Since both the `MyPlugin_Options` and `MyPlugin_SiteOptions` classes are almost the same, why don't we look into reusing code between the two? This is something that's easy to do using an [abstract class](https://carlalexander.ca/polymorphism-wordpress-abstract-classes/). So let's create one for our options classes. ```
abstract class MyPlugin_AbstractOptions
{
    /**
     * Checks if the option with the given name exists or not.
     *
     * @param string $name
     *
     * @return bool
     */
    public function has($name)
    {
        return null !== $this->get($name);
    }

    /**
     * Gets the option for the given name. Returns the default value if the value does not exist.
     *
     * @param string $name
     * @param mixed  $default
     *
     * @return mixed
     */
    abstract public function get($name, $default = null);

    /**
     * Removes the option with the given name.
     *
     * @param string $name
     */
    abstract public function remove($name);

    /**
     * Sets an option. Overwrites the existing option if the name is already in use.
     *
     * @param string $name
     * @param mixed  $value
     */
    abstract public function set($name, $value);
}
```

Here's our `MyPlugin_AbstractOptions` class. It looks a lot like the classes that we've built so far. The `has` method is the only defined method in the class. The other three methods are abstract methods. If you're not familiar with abstract methods, they're placeholder methods that a child class must implement. (If you don't, PHP will throw an error.) But it's because of those placeholders that we can have the `has` method inside our `MyPlugin_AbstractOptions` class. All that we have to do now is update both our `MyPlugin_Options` and `MyPlugin_SiteOptions` classes. We need them to extend our new `MyPlugin_AbstractOptions` class. And we also need to remove the `has` method in both of them. You can find the result below: ```
/**
 * Manages options using the WordPress options API.
 */
class MyPlugin_Options extends MyPlugin_AbstractOptions
{
    /**
     * Gets the option for the given name. Returns the default value if the value does not exist.
     *
     * @param string $name
     * @param mixed  $default
     *
     * @return mixed
     */
    public function get($name, $default = null)
    {
        $option = get_option($name, $default);

        if (is_array($default) && !is_array($option)) {
            $option = (array) $option;
        }

        return $option;
    }

    /**
     * Removes the option with the given name.
     *
     * @param string $name
     */
    public function remove($name)
    {
        delete_option($name);
    }

    /**
     * Sets an option. Overwrites the existing option if the name is already in use.
     *
     * @param string $name
     * @param mixed  $value
     */
    public function set($name, $value)
    {
        update_option($name, $value);
    }
}

/**
 * Manages site options using the WordPress options API.
 */
class MyPlugin_SiteOptions extends MyPlugin_AbstractOptions
{
    /**
     * Gets the site option for the given name. Returns the default value if the value does not exist.
     *
     * @param string $name
     * @param mixed  $default
     *
     * @return mixed
     */
    public function get($name, $default = null)
    {
        $option = get_site_option($name, $default);

        if (is_array($default) && !is_array($option)) {
            $option = (array) $option;
        }

        return $option;
    }

    /**
     * Removes the site option with the given name.
     *
     * @param string $name
     */
    public function remove($name)
    {
        delete_site_option($name);
    }

    /**
     * Sets a site option. Overwrites the existing site option if the name is already in use.
     *
     * @param string $name
     * @param mixed  $value
     */
    public function set($name, $value)
    {
        update_site_option($name, $value);
    }
}
```

# Wrapping things up

This is a good place to finish this article! At this point, you have everything you need to build one or more classes to manage WordPress options. While these classes are pretty small, they have a lot of reuse potential. This makes them very useful inside an object-oriented plugin. (And the ultimate goal of this site is to help you do that!) So go ahead and give them a try!