Settings API erases itself?

I have two forms created using Settings API, and when I save one of them the other one gets erased and vice versa.

Here’s the whole code so you could paste it into your functions.php file and see for yourself:

Read More
// Register settings
function registerSettings() {

register_setting('XX_theme_settings', 'XX_theme_settings' );

add_settings_section('theme_options', 'Theme Options', 'theme_options_generate', 'page1' ); 
add_settings_field( 'XX_Option1', 'Option 1', 'text_input', 'page1', 'theme_options', 'XX_Option1' );
add_settings_field( 'XX_Option2', 'Option 2', 'text_input', 'page1', 'theme_options', 'XX_Option2' ); 
add_settings_field( 'XX_Option3', 'Option 3', 'textarea', 'page1', 'theme_options', 'XX_Option3');  
add_settings_field( 'XX_Option4', 'Option 4', 'textarea', 'page1', 'theme_options', 'XX_Option4');  

add_settings_section('theme_options2', 'Theme Options2', 'theme_options_generate2', 'page2' ); 
add_settings_field( 'XX_Option5', 'Option 5', 'text_input', 'page2', 'theme_options2', 'XX_Option5' );
add_settings_field( 'XX_Option6', 'Option 6', 'text_input', 'page2', 'theme_options2', 'XX_Option6' ); 
add_settings_field( 'XX_Option7', 'Option 7', 'textarea', 'page2', 'theme_options2', 'XX_Option7');  
add_settings_field( 'XX_Option8', 'Option 8', 'textarea', 'page2', 'theme_options2', 'XX_Option8');     

};

add_action('admin_init', 'registerSettings');

//Generate section 1    
function theme_options_generate() {
     echo 'This is a Settings Section 1';
 }
//Generate section 2
function theme_options_generate2() {
     echo 'This is a Settings Section 2';
 }

//Generate text input callback    
function text_input($args) {
    $options = get_option('XX_theme_settings');
    echo "<input id=". $args ." name='XX_theme_settings[". $args ."]' size='40' type='text' value='{$options[$args]}' />";   
 }

//Generate textarea callback    
 function textarea($args) {
    $options = get_option('XX_theme_settings');
    echo "<textarea id=". $args ." name='XX_theme_settings[". $args ."]' rows='7' cols='50' type='textarea'>{$options[$args]}</textarea>";
 }

//Add admin pages
function registerMenus() {

add_menu_page('Theme Options', 'Theme Options', 'edit_theme_options', 'theme_menu_slug', 'theme_options_page'); 
add_menu_page('Theme Options2', 'Theme Options2', 'edit_theme_options', 'theme_menu_slug2', 'theme_options_page2'); 

};

add_action('admin_menu', 'RegisterMenus'); 

//Generate Page1 form
function theme_options_page() { ?>
   <form action="options.php" method="post">
   <?php settings_fields('XX_theme_settings'); do_settings_sections('page1'); ?>
   <p class="submit">  <input name="Submit" type="submit" class="button-primary" value="<?php _e('Save Changes'); ?>" /></p> 
   </form>

   <pre><?php echo var_dump(get_option('XX_theme_settings')); ?></pre>

<?php }

//Generate Page2 form
function theme_options_page2() { ?> 
   <form action="options.php" method="post">
   <?php settings_fields('XX_theme_settings'); do_settings_sections('page2'); ?>
   <p class="submit">  <input name="Submit" type="submit" class="button-primary" value="<?php _e('Save Changes'); ?>" /></p> 
   </form>

   <pre><?php echo var_dump(get_option('XX_theme_settings')); ?></pre>

<?php } ?>

I know I’m not validating data (yet), but I guess it should just work (and not earse the whole array every time) out of the box, right? What went wrong?

Related posts

Leave a Reply

1 comment

  1. The reason is that if you are on page 1, the data that is posted to be saved is an array of the form:

    XX_theme_settings=array('XX_Option1' =>'input1','XX_Option2'=>'input2',...)
    

    and contains no data from page 2.

    This is because the input from page 2 is not posted with it (since it wasn’t in the same <form> – it’s not on the page). Thus when the XX_theme_settings array is saved to the database it does not contain any data from page 2.

    Likewise, saving on page 2 means no data from page 1 is in the array, and since this array replaces complete the array in the database (i.e. they are not merged), you loose all data from page 1.

    Note: only one ‘form’ is ever sent, (and so recieved) – so you should ensure you have all your sections within one form. (They can appear to be different forms, and have a submit button after each section – but each submit button will save all the settings).

    Putting the fields inside one <form> will solve the issue. If you insist on having them in separate pages, one simple solution to this would be to have a different record in the database for each page.

    Alternatively, in your validation callback of the XX_theme_settings array, you could merge that array with the existing array in the database, so that any ‘missing’ data is added with it’s current value in the database. (See array_merge)

    Note: if a checkbox is unchecked, it does not send anything, and so will be considered ‘missing’. This makes the second option a bit tricky (i.e. is the data missing because it wasn’t posted (wrong page) or because its a checkbox and wasn’t checked). To get round this you would need to determine which page’s data has been sent, and if data from a checkbox onthat page is missing set its value to 0 prior to merging. You could do this by having separate validation callbacks for each page (there could be another/better way).

    As @ChipBennett states in the comments, determining the page could be achieved by giving the submit button a name which indicates the page.