What are the advantages to the Settings API?

Let me preface this by saying that I hardly ever work with WordPress – in fact, the last time I did a site in WordPress was back during 2.2. Yesterday I made quite a mess of everything and asked several questions here trying to get a basic menu plugin working.

I now have the plugin fully functional and behaving exactly as I expect, so I decided to make minor changes here and there to add functionality and compatibility – including using the Settings API. However a very short moment into reading tutorials on this API and I became quite confused, then this confusion only deepened as I read on and tried to implement the examples – which was made even more difficult by the fact that my plugin is implemented as a class.

Unless I’m doing something wrong, from what I understand to use the Settings API requires the creation of a new function PER SETTING. This means 3-5 functions for the average plugin, and up to hundreds for more advanced plugins. It just seems ludicrous to write this many functions (and develop a naming system to keep from confusing them) when you could just as easily import all applicable $_POST variables into an array and forego the entire mess.

Perhaps I’m old-fashioned, but unless there’s something to gain from it I don’t see the reason to triple or quadruple how much code I’m writing. Here’s how I managed options before attempting to add the Settings API:

    function __construct() {
        /* constructor stuff */
        $this->options = $this->db_options = get_option( 'de-menu-options' );
        if( $this->options === false ){
            $this->options = $this->defaults;
        }
        if (is_admin()) {
            add_action('admin_menu', array(&$this, 'admin_menu'));
        }   
        /* more stuff */

        // When WordPress shuts down we store changes to options
        add_action('shutdown', array(&$this, 'update'));
    }

    public function admin_menu() {
        add_options_page('DE Menu Options', 'DE Menu', 'manage_options', 'de-menu-options', array(&$this, 'options'));
        add_option('de-menu-options', $this->options);
    }

    public function options() {
        if (!current_user_can('manage_options')) {
            wp_die( __('You do not have sufficient permissions to access this page.') );
        }
        if ( !empty($_POST) && check_admin_referer('de-menu-options') ) {
            // These options are saved to the database at shutdown
            $this->options = array(
                "columns" => $_POST["de-menu-columns"],
                "maintenance" => $_POST["de-menu-maintenance"]
            );
            echo 'DE Menu options saved';
        }
?>

<div class="wrap">
    <h2>DE Menu Plugin</h2>
    <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
        <?php settings_fields('de-menu-options'); ?>
        <input type="checkbox" name="de-menu-maintenance" />
        <label for="de-menu-columns">Columns:</label>
        <input type="text" name="de-menu-columns" value="<?php echo $this->options['columns']; ?>" />
        <p class="submit">
        <input type="submit" name="de-menu-submit" value="Update Options »" />
        </p>
    </form>
</div>
<?php
    }

    function update() {
        // By storing all changes at the end we avoid multiple database calls
        $diff = array_diff( $this->options, $this->db_options );
        if( !empty( $diff )  ){
            update_option('de-menu-options', $this->options);
        }
    }

Now with the settings API I have something more like the following:

    function __construct() {
        /* constructor stuff */
        // Do I load options? Will they be loaded for me? Who knows?
        if (is_admin()) {
            add_action('admin_menu', array(&$this, 'admin_menu'));
            add_action('admin_init', array(&$this, 'admin_init'));
        }   
        /* more stuff */
        // Settings API should update options for me... I think
    }

    public function admin_menu() {
        add_options_page('DE Menu Options', 'DE Menu', 'manage_options', 'de-menu-options', array(&$this, 'options'));
        add_option('de-menu-options', $this->options);
    }

    public function admin_init() {
        register_setting('de-menu-options','de-menu-options',array(&$this,'validate'));
        add_settings_section('de-menu-main-options', 'Main Settings', 'options_section', 'de-menu-options');
        add_settings_field('de-menu-maintenance', 'Maintenance Mode', array(&$this,'options_maintenance'), 'de-menu-options', 'de-menu-main-options');
        add_settings_field('de-menu-columns', 'Columns', array(&$this,'options_columns'), 'de-menu-options', 'de-menu-main-options');
    }

    public function options() {
        if (!current_user_can('manage_options')) {
            wp_die( __('You do not have sufficient permissions to access this page.') );
        }
        if ( !empty($_POST) && check_admin_referer('de-menu-options') ) {
            // These options are saved to the database at shutdown
            $this->options = array(
                "columns" => $_POST["de-menu-columns"],
                "maintenance" => $_POST["de-menu-maintenance"]
            );
            echo 'DE Menu options saved';
        }
?>

<div class="wrap">
    <h2>DE Menu Plugin</h2>
    <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
        <?php settings_fields('de-menu-options'); ?>
        <?php do_settings_sections('de-menu-options'); ?>
        <p class="submit">
        <input type="submit" name="de-menu-submit" value="Update Options »" />
        </p>
    </form>
</div>
<?php
    }

    public function options_section() {
        echo '<p>' . __('Main description of this section here.','de-menu-lang') . '</p>';
    }

    public function options_maintenance() {
        echo "<input id='de-menu-maintenance' name="options[maintenance]" type="checkbox" />";
    }

    public function options_columns() {
        echo "<input id='de-menu-columns' name="options[columns]" type="checkbox" value=".$this->options['columns']."/>";
    }

    function validate($options) {
        return $options; // I guess?
    }

It’s probably painfully obvious from the scrollbars that the code is already longer with just two options. It’s like-wise obvious from the comments that I don’t entirely understand what I’m doing. Then there’s the matter of having 5 new functions (and removing only 1) in order to accomplish all of this.

So just what advantage am I gaining from all of this extra work?

3

My point of view is that main purpose and benefit of Settings API is structure.

It helps to keep complex settings setups:

  • orderly (logic of registration and sections);
  • secure (nonces, validation callbacks);
  • extensible (hooking into another page or allowing to be hooked into).

As with any such structural overhead it benefits more complex use cases and benefits less simple ones.

So you do can implement anything Settings API does without using it. The question is if you can accomplish that in as reliable, secure and extensible way.

Leave a Comment