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:

// 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?

Solutions Collecting From Web of "Settings API erases itself?"

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.