WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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> 

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

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

share|improve this question
It could actually be related to not defining a callback, try defining one and just return the data for testing. – t31os Feb 10 '12 at 11:29
@t31os, what kind of callback do you mean? There are callbacks for each settings field and section. – Wordpressor Feb 10 '12 at 11:33
up vote 4 down vote accepted

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.

share|improve this answer
Stephen Harris, having these two on one page doesn't fix anything, they still erase each other. I'll try array_merge but I'm surprised it doesn't work this way out of the box. – Wordpressor Feb 10 '12 at 12:30
Out of interest, how did you put them on the same page (did you have them in different sections on the same page) or did you just call do_settings_sections twice? – Stephen Harris Feb 10 '12 at 12:35
Try putting them in the same form - just because they are on the same page, doesn't mean both sets of data are posted, it is only sent if its in the same form. If you really don't want to put them in the same form you'll have to do the array_merge or save as separate fields. – Stephen Harris Feb 10 '12 at 12:42
By the way, you can put multiple sections in side one form... It's just that only one form is ever posted, (and that's true everywhere). As for the link - that can all be one big form, but just break it up into sections, and add identical submit button after each section - any of the buttons will submit the entire form. :D – Stephen Harris Feb 10 '12 at 12:44
To get around the checkbox issue, append the name of the [submit] input with the name of the settings page, then inside the validation callback, determine which page has been submitted, by looking at the value of [submit]. I do the same thing, except using the tabname. Example here. – Chip Bennett Feb 10 '12 at 13:10

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.