Can’t get plugin settings page to save data

have a simple plugin that inserts text (a Google ad) partway through the content of a single post. I’m trying to create a settings page that will let users change the ad code, and change after which paragraph the ad appears.

I have spent all day reading tutorials and code, and I have a lovely settings page, but I can’t figure out how to get it to actually save the data. I’m mostly following the example in Professional WordPress Plugin Development.

Read More

Here’s what I have:

<?php
// add plugin options
add_option( 'wpa_ad_insert_paragraph', '2' );
add_option( 'wpa_ad_insert_adcode', 'ad code goes here');

// update options
update_option( 'wpa_ad_insert_paragraph', $_POST['wpa_ad_insert_paragraph'] );
update_option( 'wpa_ad_insert_adcode', $_POST['wpa_ad_insert_adcode'] );

// Add a menu for our option page
add_action('admin_menu', 'wpa_ad_insert_add_page');
function wpa_ad_insert_add_page() {
    add_options_page( 'Ad Insertion', 'Ad Insertion', 'manage_options', 'wpa_ad_insert', 'wpa_ad_insert_option_page' );
}

// Draw the option page
function wpa_ad_insert_option_page() {
    ?>
    <div class="wrap">
        <?php screen_icon(); ?>
        <h2>Ad Insertion</h2>
        <form action="options.php" method="post">
            <?php settings_fields('wpa_ad_insert_options'); ?>
            <?php do_settings_sections('wpa_ad_insert'); ?>
            <input name="Submit" type="submit" value="Save Changes" />
        </form>
    </div>
    <?php
}

// Register and define the settings
add_action('admin_init', 'wpa_ad_insert_admin_init');
function wpa_ad_insert_admin_init(){
    register_setting(
        'wpa_ad_insert_options',
        'wpa_ad_insert_options',
        'wpa_ad_insert_validate_options'
    );
    add_settings_section(
        'wpa_ad_insert_main',
        'Ad Insertion Settings',
        'wpa_ad_insert_section_text',
        'wpa_ad_insert'
    );
    add_settings_field(
        'wpa_ad_insert_paragraph',
        'Ad will appear after paragraph number:',
        'wpa_ad_insert_paragraph_setting',
        'wpa_ad_insert',
        'wpa_ad_insert_main'
    );
    add_settings_field(
        'wpa_ad_insert_adcode',
        'Ad code:',
        'wpa_ad_insert_adcode_setting',
        'wpa_ad_insert',
        'wpa_ad_insert_main'
    );
}

function wpa_ad_insert_paragraph_setting() {
    $options = get_option('wpa_ad_insert_paragraph');
    $items = array("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20");
    echo "<select id='wpa_ad_insert_paragraph' name='plugin_options[wpa_ad_insert_paragraph]'>";
    foreach($items as $item) {
        $selected = ($options['wpa_ad_insert_paragraph']==$item) ? 'selected="selected"' : '';
        echo "<option value='$item' $selected>$item</option>";
    }
    echo "</select>";
}

function wpa_ad_insert_adcode_setting() {
    $options = get_option('wpa_ad_insert_adcode');
    echo "<textarea id='wpa_ad_insert_adcode' name='plugin_options[wpa_ad_insert_adcode]' rows='7' cols='50' type='textarea'>{$options['wpa_ad_insert_adcode']}</textarea>";
}


function wpa_insert_ad($content) {
    $paragraphAfter = get_option('wpa_ad_insert_paragraph');
    $ad = get_option('wpa_ad_insert_adcode');
    if( is_single() && is_main_query() ) {
        $content = explode("</p>", $content);
        for ($i = 0; $i <count($content); $i++ ) {
            if ($i == $paragraphAfter)   
            echo $content[$i] . "</p>";
        }
    }   
    return $content;
}
add_filter('the_content', 'wpa_insert_ad');
?>

This code creates a settings page, but when I save the settings page, nothing happens (well, I get the yellow bar saying my settings have been saved, but the information is definitely not getting saved in the database.

What am I missing here?

Related posts

Leave a Reply

4 comments

  1. While you are using Settins API, that’s why you don’t need to use update_option or add_option functions. Settings API would handle that by self.

    There were few issues that’s why your code is not working.

    1.

    add_settings_section(
        'wpa_ad_insert_main',
        'Ad Insertion Settings',
        'wpa_ad_insert_section_text',
        'wpa_ad_insert'
    );
    

    3rd parameter is the callback function. Since, you don’t need this function therefore just add __return false as the callback. Then your code for this function would be like:

    add_settings_section(
        'wpa_ad_insert_main',
        'Ad Insertion Settings',
        '__return_false',
        'wpa_ad_insert'
    );
    

    2.

    register_setting(
        'wpa_ad_insert_options',
        'wpa_ad_insert_options',
        'wpa_ad_insert_validate_options'
    );
    

    Look at the above code. Since second parameter is the option name, that’s why you have to use this option name when you want to retrieve the option from database. Instead of calling that option name, you called two option names listed below:

    $options = get_option('wpa_ad_insert_paragraph');
    $options = get_option('wpa_ad_insert_adcode');
    

    Since you used another option name in the register_setting function, that’s why you were failed to retrieve the option into the database. You should have call get_option function with the option name that you registered with the register_setting function. And that would be like:

    $options = get_option('wpa_ad_insert_options');
    

    3.
    But still the data is not being saved into the database, right? Because, you used plugin_options as the name of your form input and textarea. Since you are using wordpress Settings API, that’s why you should have use the same name that you registered as option_name in the register_setting function.

    So, you need to fixed few things to make this code usable. I modified few lines of your code and that works. Replace your register_setting function with this one:

    register_setting(
        'wpa_ad_insert_options',
        'plugin_options',
        'wpa_ad_insert_validate_options'
    );
    

    Replace your add_settings_section function with this one:

    add_settings_section(
        'wpa_ad_insert_main',
        'Ad Insertion Settings',
        '__return_false',
        'wpa_ad_insert'
    );
    

    Replace all get_option function with this one:
    $options = wpa_options(‘plugin_options’);

    And finally add this new code:

    function wpa_options() {
        $default = array(
            'wpa_ad_insert_paragraph' => 1,
            'wpa_ad_insert_adcode' => ''
            );
        return get_option('plugin_options', $default);
    }
    

    Put it all together:

    // Add a menu for our option page
    add_action('admin_menu', 'wpa_ad_insert_add_page');
    function wpa_ad_insert_add_page() {
        add_options_page( 'Ad Insertion', 'Ad Insertion', 'manage_options', 'wpa_ad_insert', 'wpa_ad_insert_option_page' );
    }
    
    // Draw the option page
    function wpa_ad_insert_option_page() {
        ?>
        <div class="wrap">
            <?php screen_icon(); ?>
            <h2>Ad Insertion</h2>
            <form action="options.php" method="post">
                <?php settings_fields('wpa_ad_insert_options'); ?>
                <?php do_settings_sections('wpa_ad_insert'); ?>
                <input name="Submit" type="submit" value="Save Changes" />
            </form>
        </div>
        <?php
    }
    
    // Register and define the settings
    add_action('admin_init', 'wpa_ad_insert_admin_init');
    function wpa_ad_insert_admin_init(){
        register_setting(
            'wpa_ad_insert_options',
            'plugin_options',
            'wpa_ad_insert_validate_options'
        );
        add_settings_section(
            'wpa_ad_insert_main',
            'Ad Insertion Settings',
            // 'wpa_ad_insert_section_text',
            '__return_false',
            'wpa_ad_insert'
        );
        add_settings_field(
            'wpa_ad_insert_paragraph',
            'Ad will appear after paragraph number:',
            'wpa_ad_insert_paragraph_setting',
            'wpa_ad_insert',
            'wpa_ad_insert_main'
        );
        add_settings_field(
            'wpa_ad_insert_adcode',
            'Ad code:',
            'wpa_ad_insert_adcode_setting',
            'wpa_ad_insert',
            'wpa_ad_insert_main'
        );
    }
    
    register_setting(
        'wpa_ad_insert_options',
        'plugin_options',
        'wpa_ad_insert_validate_options'
    );
    
    function wpa_ad_insert_paragraph_setting() {
        $options = wpa_options('plugin_options');
        $items = array("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20");
        echo "<select id='wpa_ad_insert_paragraph' name='plugin_options[wpa_ad_insert_paragraph]'>";
        foreach($items as $item) {
            $selected = ($options['wpa_ad_insert_paragraph']==$item) ? 'selected="selected"' : '';
            echo "<option value='$item' $selected>$item</option>";
        }
        echo "</select>";
    }
    
    function wpa_ad_insert_adcode_setting() {
        $options = wpa_options('plugin_options');
        echo "<textarea id='wpa_ad_insert_adcode' name='plugin_options[wpa_ad_insert_adcode]' rows='7' cols='50' type='textarea'>{$options['wpa_ad_insert_adcode']}</textarea>";
    }
    
    
    function wpa_insert_ad($content) {
        $paragraphAfter = get_option('wpa_ad_insert_paragraph');
        $ad = get_option('wpa_ad_insert_adcode');
        if( is_single() && is_main_query() ) {
            $content = explode("</p>", $content);
            for ($i = 0; $i <count($content); $i++ ) {
                if ($i == $paragraphAfter)   
                echo $content[$i] . "</p>";
            }
        }   
        return $content;
    }
    add_filter('the_content', 'wpa_insert_ad');
    
    function wpa_options() {
        $default = array(
            'wpa_ad_insert_paragraph' => 1,
            'wpa_ad_insert_adcode' => ''
            );
        return get_option('plugin_options', $default);
    }
    
  2. I started all over using the Plugin Options Starter Kit plugin – http://www.presscoders.com/plugins/plugin-options-starter-kit/. This is a nice plugin. It’s actually not really a plugin at all, it’s just a plugin settings page with all the options you might want to use, so it’s easy to copy/paste/cut/configure it to do what you want. I’m still not sure why my code above doesn’t work (other than the fact that the version pasted above doesn’t have the validation function, but adding that back in didn’t fix the problem), so if anyone wants to tell me what else I needed to do to get this to work, I’d love to know.

  3. The problem is the location in the code where you are coding the update
    .

    Once you submit the form, options.php is being loaded and your plugin with it. At that point the options are updated from the post data. Then you are redirected back to your settings page, and your code get executed again, but this time there is no values in $_POST so your options are filled with some empty value.

    If you use the settings API, you should leave the updating of the options to it, and even if not your update code should have been

    if (isset($_POST['wpa_ad_insert_paragraph'] )) {
      pdate_option( 'wpa_ad_insert_paragraph', $_POST['wpa_ad_insert_paragraph'] );
      update_option( 'wpa_ad_insert_adcode', $_POST['wpa_ad_insert_adcode'] );
    }
    

    Now add_option is almost an alias to update_option, if the option exists it will behave like update_option, and if update_option is called when the option do not exist the option will be added. Therefor you need to check the non existence of the option before initializing it.

    if (!get_option('wpa_ad_insert_paragraph')) {
      add_option( 'wpa_ad_insert_paragraph', '2' );
      add_option( 'wpa_ad_insert_adcode', 'ad code goes here');
    }
    

    get_option returns false when the option do not exists (but you need to be careful if false is one of the values your option can have)

  4. You have a few issues here it seems. First issue being that you should separate the output from the logic. Basically, the admin_init action you are calling is probably not being executed correctly because it is too late in the timeline. See this similar question here and the answer: Can’t output do_settings_sections . Can’t understand why

    Second problem is that the register_setting() function does not actually create the settings options in the database. You need to do something like this:

        // Register and define the settings
        add_action('admin_init', 'wpa_ad_insert_admin_init');
    function wpa_ad_insert_admin_init(){
    
        // This will make sure your options are created in the database
        if( false === get_option( 'wpa_ad_insert_options' ) ) {
            add_option( 'wpa_ad_insert_options' );
        }
    
        register_setting(
            'wpa_ad_insert_options',
            'wpa_ad_insert_options',
            'wpa_ad_insert_validate_options'
        );
    
        ...
    

    The check at the beginning of the function will make sure you are creating the option to save the settings to. There was a similar issue here: Why won’t register_setting() create a setting?

    As @MarkKaplun said in his answer you should also remove the update_option stuff and let WordPress handle that for you.

    When you use register_setting() the second argument is the option in the database you want it to save to, that is why you need to make sure the option exists before registering the setting.

    At my first glance the issues I mentioned above look like the biggest ones, but there may be others after you get those fixed and we can work from there.