I write a wordpress plugin. My plugin has options. All options are in one group, ‘pluginname-settings’. All option names are uniform and look like “pluginname-settings[‘option-name’]”. Some code to illustrate my case:

register_setting( 'pluginname_options', 'pluginname-settings', 'pluginname_validate' );
add_settings_section( 'section-one', 'Name of Section One', 'section_one_callback', 'pluginname_options-sectionname' );
add_settings_field( 'optionname', 'First Option', 'my_text_input', 'pluginname_options-sectionname', 'section-button', array(
    'name' => 'pluginname[optionname]',
    'value' => '42')
    )

For blog admins to tweak them, I created a settings page and grouped options in tabs. Each tab shows a subset of options (one section) and an “Update button”, as follows:

echo "<form action=\"options.php\" method=\"POST\">";
settings_fields( 'pluginname_options' );
do_settings_sections( 'pluginname_options-sectionname' ); 
submit_button('Update', 'primary',  'submit-form', false);
echo "</form>";

The problem is that when I press “Update” on one tab, the options from other tabs get cleared.

To my understanding, this is because all options represent an array of one setting.

Question: is it possible to save one section without clearing others under this setup? What is a good practice in such cases — register separate settings, use validation function to fill in the blanks or something else? Or is it just me doing it all wrong?

Thank you in advance.

P.S.: Per request in comments, here is a minimal working example:

<?php
/*
Plugin Name: Plugin Name
Plugin URI:
Description: Description
Version: 0.0.1
Author: Author Name
Author URI:
License: GPL3+
*/

add_action( 'admin_menu', 'pluginname_menu' );

function pluginname_menu()
    {
    add_options_page( 'PluginName Options', 'pluginname', 'manage_options', 'pluginname_options_page', 'pluginname_options_page' );
    }

add_action( 'admin_init', 'pluginname_admin_init' );

function pluginname_admin_init()
    {
    register_setting( 'pluginname_options', 'pluginname-settings' );
    add_settings_section( 'section-one', 'Section One', 'pluginname_section_callback', 'pluginname_options-section-one' );
    $options_array = get_option('pluginname-settings');
    add_settings_field( 'optionname-one', 'First Option', 'pluginname_field_callback', 'pluginname_options-section-one', 'section-one', array(
    'name' => 'pluginname-settings[optionname-one]',
    'value' => isset($options_array['optionname-one']) ? $options_array['optionname-one'] : '42')
    );
    add_settings_field( 'optionname-two', 'Second Option', 'pluginname_field_callback', 'pluginname_options-section-one', 'section-one', array(
    'name' => 'pluginname-settings[optionname-two]',
    'value' => isset($options_array['optionname-two']) ? $options_array['optionname-two'] : '42')
    );
    add_settings_section( 'section-two', 'Section Two', 'pluginname_section_callback', 'pluginname_options-section-two' );
    add_settings_field( 'optionname-three', 'Third Option', 'pluginname_field_callback', 'pluginname_options-section-two', 'section-two', array(
    'name' => 'pluginname-settings[optionname-three]',
    'value' => isset($options_array['optionname-three']) ? $options_array['optionname-three'] : '42')
    );
    add_settings_field( 'optionname-four', 'Fourth Option', 'pluginname_field_callback', 'pluginname_options-section-two', 'section-two', array(
    'name' => 'pluginname-settings[optionname-four]',
    'value' => isset($options_array['optionname-four']) ? $options_array['optionname-four'] : '42')
    );
    }

function pluginname_validate($input)
    {
    return $input;
    }

function pluginname_section_callback()
    {
    echo 'Feel free to change parameters below.';
    }

function pluginname_field_callback( $args )
    {
    $name = esc_attr( $args['name'] );
    $value = esc_attr( $args['value'] );
    echo "<input type="text" name="$name" value="$value" /> ";
    }

function pluginname_tab1()
    {
    echo "<form action=\"options.php\" method=\"POST\">";
    settings_fields( 'pluginname_options' );
    do_settings_sections( 'pluginname_options-section-one' ); 
    submit_button('Update', 'primary',  'submit-form', false);
    echo "</form>";
    }

function pluginname_tab2()
    {
    echo "<form action=\"options.php\" method=\"POST\">";
    settings_fields( 'pluginname_options' );
    do_settings_sections( 'pluginname_options-section-two' ); 
    submit_button('Update', 'primary',  'submit-form', false);
    echo "</form>";
    }

function pluginname_options_page()
    {
    ?>
    <div class="wrap">
        <h2>Options</h2>
        <h2 class="nav-tab-wrapper">
        <a href="https://wordpress.stackexchange.com/questions/119289/?page=pluginname_options_page&tab=1" class="nav-tab <? if ( @( $_GET['tab'] == '1' ) || !isset($_GET['tab'])) echo "nav-tab-active"; ?>">Section One Options</a>
        <a href="?page=pluginname_options_page&tab=2" class="nav-tab <? if ( $_GET['tab'] == '2' ) echo "nav-tab-active"; ?>">Section Two Options</a>
        </h2>
        <?php $current_tab = $_GET['tab'];
        switch ($current_tab)
            {
            case '2' : pluginname_tab2(); break;
            default: pluginname_tab1();
            } ?>
    </div>
    <?php
}
?>

minimal working example.

3 Answers
3

First kick in your validation callback by changing the register_setting() to

register_setting( 'pluginname_options', 'pluginname-settings', 'pluginname_validate' );

And then update your validation function to actually do something. Below it gets the current state of the options, and then only updates the pieces of the array that are submitted. When you are on a tab and click “Update” only the info in the tab is posted. Therefore the array (as written) only has 2 keys, and the info from the other tab is purged.

function pluginname_validate($input)
    {
    $options_array = get_option('pluginname-settings');

    if( isset( $input['optionname-one'] ) )
         $options_array['optionname-one'] = sanitize_text_field( $input['optionname-one'] );

    if( isset( $input['optionname-two'] ) )
         $options_array['optionname-two'] = sanitize_text_field( $input['optionname-two'] );

    if( isset( $input['optionname-three'] ) )
         $options_array['optionname-three'] = sanitize_text_field( $input['optionname-three'] );

    if( isset( $input['optionname-four'] ) )
         $options_array['optionname-four'] = sanitize_text_field( $input['optionname-four'] );

    return $options_array;
    }

I threw in a little sanitization for fun, the type of data santization depends on what your real options are, but you should always do some kind of sanitization.

Leave a Reply

Your email address will not be published. Required fields are marked *