'Wordpress save multiple setting sections at the same time

I've created a settings page for for WordPress plugin.

I then created two setting sections for the same page:

add_plugins_page(
    __('API Settings', 'api'),
    __('API Settings', 'api'),
    'administrator',
    'api',
    array('API', 'settings_display')
);

// add general settings section
add_settings_section(
    'api_general',
    __('General Settings', 'api'),
    array('API', 'section_callback'),
    'api'
);

// add page section
add_settings_section(
    'api_pages',
    __('Set API pages', 'api'),
    array('API', 'section_callback'),
    'apis'
);

Various fields were then added to the different sections with add_settings_field().

The function that handled the rendering of the page looks as follows:

<!-- Create a header in the default WordPress 'wrap' container -->
<div class="wrap">
    <!-- Add the icon to the page -->
    <?php screen_icon(); ?>
    <h2><?php _e('API Settings', 'api'); ?></h2>
    <!-- Make a call to the WordPress function for rendering errors when settings are saved. -->
    <?php settings_errors(); ?>
    <!-- Create the form that will be used to render our options -->
    <form method="post" action="options.php">
        <?php settings_fields('api_pages'); ?>
        <?php settings_fields('api_general'); ?>
        <?php do_settings_sections('api'); ?>
        <?php submit_button(); ?>
    </form>
</div><!-- /.wrap -->

When I then try to save the page settings it will only save the api_general settings.

I've found that the settings_fields() is actually meant only to output nonce, action, and option_page fields for a specific section. So when I called it for the two different sections one section output basically renders the previous section ignored.

I've done some research and looked at tutorials but I haven't found one that shows have to save multiple sections at the same time. But since the do_settings_sections() output all the sections for a page there must be a way to save all the sections at the same time.

My only other recourse would be to combine all the fields to the same section or to create separate pages which I would like to avoid if possible.



Solution 1:[1]

Maybe this will help.... according to this codex: settings_fields

The first parameter to the settings_fields function is supposed to be a settings group as declared in register_setting.

But it looks like you are using the name for a settings section, so I'm not even sure how that works at all they way you have it.

You can have two or more sections on a page, but the all the settings (ie options), regardless of what section they are in, have to be part of the same settings group within a form. The hidden fields for the group (singular) are inserted at the top of the form by the magic "settings_field" function.

However you can also have more than one form on a page, each with their own submit button and settings_fields('optiongroup'), but I personally think multiple submit buttons on a page are very confusing to the user.

As I understand it, the limiting factor is there is a 1 to 1 to 1 correspondence between:

  • a form on a page
  • the submit button in that form
  • the settings_fields in that form

The settings_fields() determines what will be saved behind the scenes. And it is more efficient to use an array of options rather than individual options. I have not tried this yet, but to logically break apart sections on a form, it would make sense to have one array of options associated with each settings section. Then each section (n) would then have its own get_options('section-(n)') to get the array of values for all of its fields. But still (at the risk of over-repetition), each of the options arrays containing all of the field values in each of the sections get saved at once when the one submit button is pressed for the one form on each page.

Whew! :-)

Solution 2:[2]

To my understanding it is not possible to have multiple setting section on one page and save the data of all of the sections them. A solution would be to use tabs, http://wp.smashingmagazine.com/2011/10/20/create-tabs-wordpress-settings-pages/ should get you started on tabs.

Solution 3:[3]

I was actually able to get this to work. The key for me was to make sure the register_setting() used the same slug for the group even though sections were different. essentially I used the first section's slug for the first parameter instead of the each section's slug. In my setup, this was using what I called a "page" variable since I used it to also define the options page.

My sections and fields were defined like this:

$sections=>array(
...

    'page_vars'=>array(
      'slug'=>'page_vars',
      'label'=>'Page Layout Variables',
    ),
    'display_defaults'=>array(
      'slug'=>'display_defaults',
      'label'=>'Display Defaults',
      'page' =>'page_vars',
    ),
    'blog_defaults'=>array(
      'slug'=>'blog_defaults',
      'label'=>'Blog Display Defaults',
      'page' =>'page_vars',
    ),


...
);

with corresponding fields:

$fields=>arry(
....
  'max_page_width'=>array(
      'slug'=>'max_page_width',
      'label'=>'Maximum width for page (Including header images - include unit)',
      'section'=>'page_vars',
      'args'=>array('default'=>'100vw'),
    ),
    'xl_max_body_width'=>array(
      'slug'=>'xl_max_body_width',
      'label'=>'Default content width for XL Screens (include unit)',
      'section'=>'page_vars',
      'args'=>array('default'=>'1600px'),
    ),
    'lg_max_body_width'=>array(
      'slug'=>'lg_max_body_width',
      'label'=>'Default content width for LG Screens (include unit)',
      'section'=>'page_vars',
      'args'=>array('default'=>'95vw'),
    ),
    'md_max_body_width'=>array(
      'slug'=>'md_max_body_width',
      'label'=>'Default content width for MD Screens (include unit)',
      'section'=>'page_vars',
      'args'=>array('default'=>'95vw'),
    ),
    'sm_max_body_width'=>array(
      'slug'=>'sm_max_body_width',
      'label'=>'Default content width for SM Screens (include unit)',
      'section'=>'page_vars',
      'args'=>array('default'=>'95vw'),
    ),
    'xs_max_body_width'=>array(
      'slug'=>'xs_max_body_width',
      'label'=>'Default content width for XS Screens (include unit)',
      'section'=>'page_vars',
      'args'=>array('default'=>'95vw'),
    ),
    'display_header'=>array(
      'slug'=>'display_header',
      'label'=>'Display auto-generated page heading by default',
      'section'=>'display_defaults',
      'page' =>'page_vars',
    ),
    'display_title'=>array(
      'slug'=>'display_title',
      'label'=>'Display auto-generated page title by default',
      'section'=>'display_defaults',
      'page' =>'page_vars',
    ),
    'display_meta'=>array(
      'slug'=>'display_meta',
      'label'=>'Display auto-generated page meta by default',
      'section'=>'display_defaults',
      'page' =>'page_vars',
    ),
    'display_thumb'=>array(
      'slug'=>'display_thumb',
      'label'=>'Display thumbnail at top of post',
      'section'=>'display_defaults',
      'page' =>'page_vars',
    ),
    'display_page_comments'=>array(
      'slug'=>'display_page_comments',
      'label'=>'Display comments on pages',
      'section'=>'display_defaults',
      'page' =>'page_vars',
    ),
    'display_post_comments'=>array(
      'slug'=>'display_post_comments',
      'label'=>'Display comments on posts',
      'section'=>'display_defaults',
      'page' =>'page_vars',
    ),
    'display_sidebar'=>array(
      'slug'=>'display_sidebar',
      'label'=>'Display sidebar by default',
      'section'=>'display_defaults',
      'page' =>'page_vars',
    ),
    'mobile_sidebar'=>array(
      'slug'=>'mobile_sidebar',
      'label'=>'Display sidebar on Mobile Devices',
      'section'=>'display_defaults',
      'page' =>'page_vars',
    ),
    'display_footer'=>array(
      'slug'=>'display_footer',
      'label'=>'Display footer by default',
      'section'=>'display_defaults',
      'page' =>'page_vars',
    ),
    'blog_display_header'=>array(
      'slug'=>'blog_display_header',
      'label'=>'Display auto-generated page heading by default',
      'section'=>'blog_defaults',
      'page' =>'page_vars',
    ),
    'blog_display_title'=>array(
      'slug'=>'blog_display_title',
      'label'=>'Display auto-generated page title by default',
      'section'=>'blog_defaults',
      'page' =>'page_vars',
    ),
    'blog_display_filter'=>array(
      'slug'=>'blog_display_filter',
      'label'=>'Display post filter above content',
      'section'=>'blog_defaults',
      'page' =>'page_vars',
    ),
...
);

I then added some processing functions to do the section and field adding / registering:

    // set up options record in database

  foreach ($sections as $section=>$def){
    $page = (isset($def['page']))? $def['page'] : $def['slug'];
    add_settings_section(
      'trs_harvest_'.$def['slug'],
      __('','trs-harvest'),
      array($this,$def['slug'].'_settings_cb'),
      'trs_harvest_'.$page
    );
  }

  foreach ($fields as $field=>$def){
    $page = (isset($def['page']))? $def['page'] : $def['section'];
    $args = (isset($def['args']))? $def['args'] :null;
    register_setting('trs_harvest_'.$page,'hvst_'.$def['slug'],$args);
    add_settings_field(
      'hvst_'.$def['slug'],
      __($def['label'],'trs-harvest'),
      array($this,$def['slug'].'_cb'),
      'trs_harvest_'.$page,
      'trs_harvest_'.$def['section'],
      array('label_for'=>'hvst_'.$def['slug'])
    );
  }

Finally, when I added the option page, I made sure the settings_fields() used the first section (*Important Note is that the first section drives the nonce field here) and only created one set of settings_field() and _submit_button() output for the page.:

using this as $sections:

array('trs_harvest_page_vars','trs_harvest_display_defaults','trs_harvest_blog_defaults')

and this code to set up the options page output:

settings_fields($sections[0]);
foreach ($sections as $section){
  do_settings_sections($section);
}
echo('</div>');
submit_button('Save Settings');

This gave me a single options page with multiple sections that I could save with a single submit button.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Marc Witteveen
Solution 3 xxx