Devlog

WordPress settings API

WordPress advises to use the Settings API when programming a settings page. But as you start using it, you quickly get overwhelmed with all the arguments you have to give to functions like register_setting, add_settings_section, add_settings_field, settings_fields, do_settings_sections, add_menu_page and add_submenu_page…

This is an explanation what every argument means and how it fits into the big picture. This is also work in progress.

Add a new admin page and a sub page to it. This should be called from the admin_init hook:

add_menu_page(
  'Page title', // HTML title tag
  'Menu title',
  'manage_options', // capability
  'my-settings-page', // page slug
  'my_settings_page_html' // callback
);

add_submenu_page(
  'my-settings-page', // parent page slug
  'Page title', // HTML title tag
  'Menu title',
  'manage_options', // capability
  'my-sub-settings-page', // page slug
  'my_sub_settings_page_html'
);

function my_settings_page_html() {
  // TODO
}

function my_sub_settings_page_html() {
  // TODO
}

If you want to show something on this subpage, you have to echo something from the my_sub_settings_page_html function. This can be anything, but if you want to use the settings API, you have to do this:

function my_sub_settings_page_html() {
  ?>
  <div class="wrap">
    <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
    <form action="options.php" method="post">
    <?php
      settings_fields('my-sub-settings-page'); // page slug
      do_settings_sections('my-sub-settings-page'); // page slug
      submit_button();
    ?>
    </form>
  </div>
  <?php
}

Both the settings_fields and do_settings_sections get the page slug as argument.

Right now you will only see the title because we haven’t add any sections and fields to this page and we haven’t registered any settings yet. This should all be one from the admin_init hook:

register_setting(
  'my-sub-settings-page', // page slug
  'my-options', // key in options table
  [
    // Optional arguments
    // The sanitize callback receives one argument and you have
    // to return it.
    'sanitize_callback' => 'my_options_sanitize_callback'
  ]
);

add_settings_section(
  'my_section_id', // you use this to add fields to this section
  'Section title',
  'my_section_html', // callback
  'my-sub-settings-page' // page slug
);

add_settings_field(
  'my_field_id', // don't know what this is for...
  'Field title',
  'my_field_html', // callback
  'my-sub-settings-page', // page slug
  'my_section_id', // section this field is in
  [
    // Optional arguments
    // The label_for arguments makes that we have a clickable label.
    // Most of the time just juse the same value as the first argument
    // (my_field_id). This is not required but makes it clear.
    'label_for' => 'my_field_id',
    // You can add as many arguments here - this makes it possible
    // to call add_settings_field dynamically
  ]
);

function my_section_html() {

}

function my_field_html($args) {
  // See for $args the last argument of add_settings_field
  $option = get_option('my-options');
  // This can be a scalar value or something serialized that is
  // automatically deserialized by WordPress.
  ?>
  <input type="text"
    id="<?php echo esc_attr($args['label_for']); ?>"
    name="<?php echo esc_attr($args['label_for']); ?>"
    value="<?php echo esc_attr($option); ?>" />
  <?php
}

Because we did register this option, saving is done automatically for us.