Intro to the WordPress Settings API

API Documentation is always going to be a hell that I do my best to avoid. I learned early on when working with SourceSDK that documentation for much of anything worth a damn would be hard to find and the new WordPress Settings API (SAPI) is in the same ballpark. This was actually added to the 2.7 release of the trusty blogging / CMS software, but it was (was? is!) not well documented and has some really dope capabilities and features that you should all take advantage of.

So what are you waiting for? Time to rewrite a plug-in and learn the new API!

This walkthrough is going to do more than just talk about SAPI. I will use this soap box to share some suggestions to future plug-in developers to help ensure that you work is able to be self contained, avoiding function collisions and improve your ability to debug things. Proper programming standards (naming conventions, use of white space and the like) are all still quite applicable, even in light of your development of a plugin. The following are a few that I have picked up over the years.

  • Any plug-in should only have one variable added to the options. Use an array to be able to save more than that one variable.
  • All plug-in functions should be wrapped in a class.
  • If you need to create An Administration Menu item, don’t go overboard. Only insert what is entirely necessary and where it is appropriate.
  • Do not rely upon side effects.
  • Include proper Install, Upgrade/Update, Uninstall functionality

That said, know that there is a lot more to be uncovered. I will likely expand upon these with a later post, but i am a bit excited and I’d like to get into the meat of the discussion. For the purposes of this discussion i will be creating an array variable, something that is quite important to avoid bloating up the options table with settings that aren’t necessary in case of a bad update or uninstall.

Overview of the Settings API

The new API is actually pretty complicated, but only in its usage. The API only comes down to a handful of functions and concepts, but they are pretty powerful. SAPI wraps up a number of tasks to allow us to focus on dealing with the actual plug-in internals.

  • making sure an admin submitted our value
  • provides a hook to allow us to control validation of our plug-in values
  • allows us to embed our controls, the form elements you are used to finding on a website, in pages as we see fit.
    • This includes the built in pages within WordPress
    • but can also include making our own
  • Abstracts away the process of saving the verified values
  • Standardize formatting to WordPress default
  • White-listing variables, to simplify processing.
  • Error Catching & Display

The first function we are going to introduce is used to alert WordPress to our intention to work with the SAPI as well as let it know that we would like to keep an eye out for a particular variable.

register_setting(
    'Demo_Vars_Group',
    'Demo_Vars',
    array('DemoPlugin', 'Validate'));

This snippet creates a Demo_Vars_Group containing the Demo_Vars input and passes the callback to a function DemoPlugin::Validate(). This function call assumes a variable name of Demo_Vars which will be passed to the Validate function. As a quick side note, this function is necessarily static. If you don’t know what that means, please leave a comment and ill be sure to expand on what is going on here. There is a second function unregister_setting which is useful for situations where you are modifying another plug-in or wish to remove options from the default WordPress. I can’t really wrap my mind around where else you would use it so since this is a basic plug-in ill go ahead and ignore it. (We will also cover validation in a minute.)

The next key function is going to let SAPI know we want to create a section, which is used to wrap up our controls.

add_settings_section(
    'Demo_Vars_ID',
    'Demo Vars Title',
    array('DemoPlugin', 'Overview'),
    'Demo_Page_Title');

Demo_Vars_ID is the identifier for the section, used to bind the controls so WordPress knows which ones to render. Demo Vars Title goes into an H3 tag above the controls. Immediately below the title the contents of DemoPlugin::Overview() is dropped. You don’t have to return the contents, it is executed and should just render the content as though it were inline code. Lastly, ‘Demo_Page_Title’ is a unique identifier for the section, used when rendering the form.

Next we need to add a settings field to our section. This is one of the more complicated functions (lots of parameters, none of which are too complicated but can be difficult to figure out.).

add_settings_field(
    'Control_ID',
    'Demo Control Name',
    array('DemoPlugin', 'Demo_Control'),
    'Demo_Page_Title',
    'Demo_Vars_ID');

As you can see this has many similar fields to the previous function, but their order is different. ControlID is the expected ID or Name for the field that you are creating. As with other IDs within WordPress development, you should ensure that this is Unique.The third is another link to a function call, this one to DemoPlugin::Demo_Control(), which should also just return the content as though it were inline code. The last two are expected to be identical to the entries in the section. Using these two you can, however, do some hoop jumping and use the same section on two different pages with different controls inside of it, but i don’t recommend complicating life in such a way.

Now we need to do some ground work and setup our plug-in to execute these functions. All of these functions should be included when the admin sections are initialized. Our menu, on the other hand is rendered at a different time.

class DemoPlugin
{
    function Init()
    {
        register_setting(
            'Demo_Vars_Group',
            'Demo_Vars',
            array('DemoPlugin', 'Validate'));
 
        add_settings_section(
            'Demo_Vars_ID',
            'Demo Vars Title',
            array('DemoPlugin', 'Overview'),
            'Demo_Page_Title');
 
        add_settings_field(
            'Control_ID',
            'Demo Control Name',
            array('DemoPlugin', 'Demo_Control'),
            'Demo_Page_Title',
            'Demo_Vars_ID');
    }
 
    function Admin_Menus()
    {
        if (!function_exists('current_user_can')
            ||
            !current_user_can('manage_options'))
                return;
 
        if (function_exists('add_options_page'))
            add_options_page(
                'Settings_API_Sample',
                'Settings API Sample',
                'manage_options',
                'settings_api_sample',
                array('DemoPlugin', 'SampleForm'));
    }
}
 
add_action('admin_init',
    array('DemoPlugin', 'Init'));
add_action('admin_menu',
    array('DemoPlugin', 'Admin_Menus'));

With that you are using the API appropriately, setting up all of the necessary ground work. The only aspects left are to hook in your functions for the controls, overview, validation and the sample form. Each of them is pretty straight forward, so i will post them in line and expand where important.

function SampleForm()
{
                        $Demo_Vars = get_option('Demo_Vars');
 
                        ?>
                                <div class="wrap">
                                        < ?php screen_icon("options-general"); ?>
                                        <h2>Settings API Sample < ?php echo $Demo_Vars['Version']; ?></h2>
                                        <form action="options.php" method="post">
                                                < ?php settings_fields('Demo_Vars_Group'); ?>
                                                < ?php do_settings_sections('Demo_Page_Title'); ?>
                                                <p class="submit">
                                                        <input name="Submit" type="submit" class="button-primary" value="<?php esc_attr_e('Save Changes'); ?/>" />
                                                </p>
                                        </form>
                                </div>
                        < ?php
                }

We have introduced two new SAPI functions, do_settings_sections() and settings_fields() as well as a couple other standards. This is really the simplest format for a settings page. The SAPI will handle rendering all of the sections and controls for us, we only have to worry about dropping the submit button, directing our form over to the options.php page and making sure it is a post form. The do_settings_sections() function takes the ID of the section that we defined earlier, likewise for the ‘Demo_Vars_Group’ parameter sent to the settings_fields() call.

function Overview()
{
    ?>This is a demo of the Settings API.< ?php
}
 
function Demo_Control()
{
    $Demo_Vars = get_option('Demo_Vars');
 
    ?>
<input id="SampleValue" class="regular-text" type="text" name="Demo_Vars[SampleValue]" value="<?php echo $Demo_Vars['SampleValue']; ?/>" />
    < ?php
}

These two function calls are executed by the SAPI. You should note that the name attribute of the input is to take advantage of the internal processing of PHP to create an array of information. Using this standard makes the whole process easy.

And all that is left is the Validation function. The white-listing mentioned earlier registers the variable Demo_Vars and will pass the contents of it into the Validation function as a parameter. We should then validate it and return. A practice that I have adopted is to grab the existing values, validate the input and if things are kosher, update our entry in our existing array, then return the existing array. There are a number of benefits to this that i wont get into here considering how long this article is already.

function Validate($input)
{
    $Demo_Vars = get_option('Demo_Vars');
 
    // Validate &amp; Replace with values from $input
    if (sprintf("%.0f", $input['SampleValue']) == $input['SampleValue'])
        $Demo_Vars['SampleValue'] = $input['SampleValue'];
    else
        add_settings_error('Demo_Vars',
            'settings_updated',
            __('Only integers are accepted.'));
 
    return $Demo_Vars;
}

And with that this plugin is complete. I added a validation check to confirm that the input value is an integer as well as a call to the add_settings_error() function, which registers an error/success message to the user. The ‘Demo_Vars’ entry

As with all other tutorials on my website, questions and comments are answered in the comments or email. Because of some formatting issues above I have attached the entire php file.

http://pastebin.com/YDBm3HHX

Enjoy!

21 thoughts on “Intro to the WordPress Settings API

  1. Pingback: Wordpress: Settings API | notes.dcgj.dk

  2. Yasen Vasilev

    Unluckily I don’t understand much of this. I have a small problem that I can’t find a solution yet on the net.
    All articles I read about Settings pages on WP, are using get_option, but what if my data is in another database and not in wp_options? Than I can’t use get_options. I tried using the global wpdb and making a query, but than my settings page crashes.

    Reply
    1. Bob Chatman Post author

      That is a kind of odd situation in and of itself. WordPress uses its own database, and if its in something else you should be turning to the database functions of PHP to grab it, but then it becomes less about wordpress settings. I would suggest either you merge your settings into the wordpress settings world, or you dont use wordpress for your plugin, or you use the database functionality.

      If you mean its in a different table, that is typically alright, but again, it wont be fun to grab. Again, i would turn to the php db interaction to grab it.

      Can you be more specific about your errors when it crashes? What actually happens?

      Reply
  3. Nigel Wilson

    Hi there – I have just started a new job and trying to get up to speed with WordPress – primarily spent past 2 1/2 years using Umbraco… This tutorial is ideal to aid my understanding of how to add functionality to a site. However i have not been able to get it to work and it would appear the code is no longer available for download. I havae activated my plugin and the option is available under “Settings” however no form appears – I must be missing something obvious. Are you able to provide the source code for me to compare against? Cheers, Nigel

    Reply
  4. andres

    Hi, hope you read this.

    I gat trouble with the add_settings_error() function, i have a lot of inputs to sanitize , but i can’t get it work

    some of mi validation code are like this
    $input['iflowid'] = ( $input['iflowid'] == ” ? ‘iflows’ : $input['iflowid'] );
    $input['iflowid'] = str_replace(” “, “_”, $input['iflowid']);
    $input['aspect_ratio'] = ( !is_numeric($input['aspect_ratio']) ? 1.964 : $input['aspect_ratio'] );
    …..

    Can you explain what happens

    Tks in advance

    Reply
    1. Bob Chatman Post author

      I have no idea what you are trying to do there, but since this is not an interview i wont waste either of our time telling you how PHP works. If you have a more direct and or interesting question i would be happy to help, otherwise i would suggest #Help on the phpfreaks irc server for further information on debugging your code.

      Reply
  5. Pingback: Settings API in 9 steps | WordPress and me