This website uses cookies to ensure you get the best possible experience. See our Cookies Policy.

PMG Digital Made for Humans

How to Use the WordPress Settings API

12 MINUTE READ | August 3, 2012

How to Use the WordPress Settings API

The WordPress settings api is a collection of functions that allows you to extend existing admin pages with your own fields or create new pages.  In this tutorial, we’ll cover how to do both.

The settings api is comprised of several functions.  The most important of which are:

  • register_setting – Registers our setting with WordPress, which lets us take advantage of using options.php to handle saving the data.

  • add_settings_section – Adds a section (meaning a collection of fields) to a page.

  • add_settings_field – Adds a field to a section on a given page.

All of this is very abstract.  So we’re going to start small.

The simplest possible example is adding a field to an already existing page and already existing section.  Let’s add a field to the general options page.

Registering the Setting

First up, we need to hook into admin_init and call register_setting.  register_setting takes two required arguments: the page on which the setting will live (“general” in this case) and the settings name.  The third argument is optional, but extremely useful – we’ll cover it later.

<?php

add_action(‘admin_init’, ‘pmgtut_simple_settings_register’);

/**

* Hooked into ‘admin_init’ this is the central function that takes care of

* registering the setting, addint sections and adding fields

*

* @since   1.0

* @uses    register_setting

* @uses    add_settings_section

* @uses    add_settings_field

*/

function pmgtut_simple_settings_register()

{

// our setting name

$name = ‘pmgtut_setting_simple’;

// our settings page, we’re going to add options to the “general” page

$page = ‘general’;

// The section to which we’ll add things

$section = ‘default’;

// ‘register_setting is the central call.  This Let’s WP know about your

// setting.  You **MUST** call this first

register_setting($page, $name, ‘pmgtut_simple_validator’);

}

Adding a Settings Field

The next step is example our function a bit to include a call to add_settings_field.  As the name implies, this function tells WP to add an additional input field.

<?php

function pmgtut_simple_settings_register()

{

// our setting name

$name = ‘pmgtut_setting_simple’;

// our settings page, we’re going to add options to the “general” page

$page = ‘general’;

// The section to which we’ll add things

$section = ‘default’;

// ‘register_setting is the central call. This Let’s WP know about your

// setting. You **MUST** call this first

register_setting($page, $name, ‘pmgtut_simple_validator’);

// at this point WP knows about your setting.

// Lets add a new field field to the default section

add_settings_field(

‘pmg-example-simple’, // field ID not used for much

__(‘Simple Field’, ‘pmg’), // the label for our field

‘pmgtut_simple_field_cb’, // this is the callback function

$page, // page to place our field on

$section // section to place our field in

);

}

The crucial argument of add_settings_field is the third.  This is the callback function. As the page where that setting was registered loads, WordPress will call your callback function.  This function is responsible for spitting out a form field.  Here’s the simple example:

<?php

function pmgtut_simple_field_cb()

{

echo ‘works’;

}

As exciting as that is, let’s make our field callback actually do something.  Most important thing here: the name attribute of our field MUST match up with the name of our registered setting.  This will become clear a bit later.

<?php

/** * the settings callback function. This spits out the form field * * @since 1.0 * @uses get_option */ function pmgtut_simple_field_cb() { // Name of our setting, same as we registered $setting = ‘pmgtut_setting_simple’; // step one: get the value in our option with get_option $val = get_option($setting, ”); // spit out the form field printf( ‘<input type=”text” class=”regular-text” name=”%1$s” id=”%1$s” value=”%2$s” />’, esc_attr($setting), esc_attr($val) ); }

Using the Validation Callback

Remember that third argument of register_setting?  That is a settings validation callback.

When you hit save on a given admin options page, WordPress submits a POST request to wp-admin/options.php.  From here, WordPress validates nonces and referrers for you.  Assuming everything is okay, WP will then look for fields named after all the registered settings assigned to each page.  If the third argument of register setting is present, WP will call that function name, passing in the values of all the fields with that settings name.  In this example, there’s only one field.

Let’s pretend we want to make sure that an email is entered in that field.  We can use the built in is_email function to check.  If it is a valid email, we’ll simply return the value from our callback function.  Otherwise, we’ll add a settings error to give our user feedback.

<?php

/**

* Validation callback function. Makes sure we have an email address or adds

* a settings error to give the user feedback.

*

* @since   1.0

* @uses    add_settings_error

* @uses    is_email

* @return  string The email or an empty string

*/

function pmgtut_simple_validator($value)

{

if(is_email($value))

{

// we have a valid email, return it

return $value;

}

// not a valid email. Add a settings error.

add_settings_error(

‘pmgtut_setting_simple’, // setting name

‘pmgtut-no-email’, // Code, used int he ID att of the error

__(‘Please enter a valid email’, ‘pmg’), // error message

‘error’ // type of error: updated?  error, in this case

);

// return an empty string

return ”;

}

Instead of just adding a field, let’s add an entire section and add several fields to that section.  We start off the same way: hook into admin_init and register the setting.  At that point, we also need to add a section with add_settings_section.

add_settings_section takes four arguments: a section id (we’ll use this later to add fields), The section title, a callback to spit out something like help text, and the page (options group) on which the section will reside.

<?php

add_action(‘admin_init’, ‘pmgtut_settings_register’);

/**

* Hooked into ‘admin_init’ this is the central function that takes care of

* registering the setting, adding sections, and adding fields

*

* @since   1.0

* @uses    register_setting

* @uses    add_settings_section

* @uses    add_settings_field

*/

function pmgtut_settings_register()

{

// our setting name

$name = ‘pmgtut_setting’;

// our settings page, we’re going to add options to the “general” page

$page = ‘general’;

// The name of our section

$section = ‘example-section’;

// ‘register_setting is the central call. This Let’s WP know about your

// setting.  You **MUST** call this first

register_setting($page, $name, ‘pmgtut_validator’);

// at this point WP knows about your setting.

// Lets add a new section

add_settings_section(

$section, // our section id

__(‘Example Section’, ‘pmg’), // the title.  Gets put in an in the admin area

‘pmgtut_section_cb’, // name of our callback function.

$page // what page the section lives on

);

}

Of particular note is the callback function for add_settings_section. This can be used to spit out help text.  Our example is simple:

<?php

/**

* Section callback function.  Can be used to spit out some help text or

* whatever you like.

*

* @since   1.0

* @uses    esc_html__

* @return  null

*/

function pmgtut_section_cb()

{

echo ‘’ . esc_html__(‘Help text here’, ‘pmg’) . ‘’;

}

If you don’t want to mess with a callback, you can pass in __return_false — a built in WordPress function that as, the name implies returns false — to add_settings_section.  In this case __return_false will do nothing.

<?php

add_settings_section(

$section, // our section id

__(‘Example Section’, ‘pmg’), // the title.  Gets put in an in the admin area

‘__return_false’, // name of our callback function.

$page // what page the section lives on

);

Adding Fields

Just like our simple example above, we can add fields with add_settings_field. Let’s add two fields in this case: one for an email and one for a string.

<?php

/**

* Hooked into ‘admin_init’ this is the central function that takes care of

* registering the setting, adding sections, and adding fields

*

* @since   1.0

* @uses    register_setting

* @uses    add_settings_section

* @uses    add_settings_field

*/

function pmgtut_settings_register()

{

// our setting name

$name = ‘pmgtut_setting’;

// our settings page, we’re going to add options to the “general” page

$page = ‘general’;

// The name of our section

$section = ‘example-section’;

// ‘register_setting is the central call.  This Let’s WP know about your

// setting.  You **MUST** call this first

register_setting($page, $name, ‘pmgtut_validator’);

// at this point WP knows about your setting.

// Lets add a new section

add_settings_section(

$section, // our section id

__(‘Example Section’, ‘pmg’), // the title.  Gets put in an in the admin area

‘pmgtut_section_cb’, // name of our callback function.

$page // what page the section lives on

);

// We’ve now registered our setting and section.  Add the fields!

add_settings_field(

’email-field’, // field id

__(‘Your Email’, ‘pmg’), // field label

‘pmgtut_email_field_cb’, // field callback

$page, // option page/group

$section // settings section

);

add_settings_field(

‘normal-text-field’,

__(‘Some Text’, ‘pmg’),

‘pmgtut_normal_field_cb’,

$page,

$section

);

}

And our simple settings callbacks to test things:

<?php

/**

* Callback function for our email field

*

* @since   1.0

* @uses    get_option

*/

function pmgtut_email_field_cb()

{

echo ‘works’;

}

/**

* Callback function for our normal text field

*

* @since   1.0

* @uses    get_option

*/

function pmgtut_normal_field_cb()

{

echo ‘also works’;

}

Filling Out the Fields

Rather than clutter our database up with options, we’re going to save both those fields under the same option name as an array.  To do this, we need to make sure the name attribute of each of the fields follows this formula: settings_name[field_key] or name="pmgtut_setting[the_field]".  Our new settings fields callbacks follow.  You’ll notice a lot of repeated code, which sucks.  We’ll talk about how to get around that later.

<?php

/**

* Callback function for our email field

*

* @since   1.0

* @uses    get_option

*/

function pmgtut_email_field_cb()

{

// variable to use later

$setting = ‘pmgtut_setting’;

$field = ’email’;

// get our options

$opts = get_option($setting, array());

// Set up the value with a ternary statment

$val = isset($opts[$field]) ? $opts[$field] : ”;

// actually print the field

printf(

‘<input type=”text” class=”regular-text” id=”%1$s[%2$s]” name=”%1$s[%2$s]” value=”%3$s” />’,

esc_attr($setting),

esc_attr($field),

esc_attr($val)

);

}

/**

* Callback function for our normal text field

*

* @since   1.0

* @uses    get_option

*/

function pmgtut_normal_field_cb()

{

$setting = ‘pmgtut_setting’;

$field = ‘normal’;

// get our options

$opts = get_option($setting, array());

// Set up the value with a ternary statment

$val = isset($opts[$field]) ? $opts[$field] : ”;

// actually print the field

printf(

‘<input type=”text” class=”regular-text” id=”%1$s[%2$s]” name=”%1$s[%2$s]” value=”%3$s” />’,

esc_attr($setting),

esc_attr($field),

esc_attr($val)

);

}

Validating Options

When you save more than one value per option, your validation callback function will receive an associative array as its argument rather than a string.  You simply look for each of your fields, validate each, and return the array.

<?php

/**

* settings validation callback

*

* @since   1.0

* @uses    add_settings_error

* @uses    esc_attr

* @uses    is_email

* @return  array The cleaned options

*/

function pmgtut_validator($dirty)

{

$clean = array();

if(isset($dirty[’email’]) && is_email($dirty[’email’]))

{

// hooray email!

$clean[’email’] = $dirty[’email’];

}

else

{

add_settings_error(

‘pmgtut_setting’,

‘pmg-invalid-email’,

__(‘Please enter a valid email’, ‘pmg’),

‘error’

);

}

$clean[‘normal’] = isset($dirty[‘normal’]) ? esc_attr($dirty[‘normal’]) : ”;

return $clean;

}

The settings API is amazing because it makes it easy for other developers to extend your work.  That’s why the WordPress core itself uses it.  The downside, of course, is that you end up with a lot of code to just do some simple stuff like printing out a form field. Having multiple fields means using multiple callback functions in most cases.  If you have two of the same field type, however, you can get around that.

add_settings_field takes an option sixth argument: an array of args.  This array is then passed into your callback function.  You can use this to pass in different options keys like the code below does.  First we have to modify our call to add_settings_field to include the final argument as well as a call to a unified callback.

<?php

/**

* Hooked into ‘admin_init’ this is the central function that takes care of

* registering the setting, adding sections, and adding fields

*

* @since   1.0

* @uses    register_setting

* @uses    add_settings_section

* @uses    add_settings_field

*/

function pmgtut_settings_register()

{

// our setting name

$name = ‘pmgtut_setting’;

// our settings page, we’re going to add options to the “general” page

$page = ‘general’;

// The name of our section

$section = ‘example-section’;

// snip snipp

// unified callback

$fields = array(

’email’  => __(‘Your Email’, ‘pmg’),

‘normal’ => __(‘Some Text’, ‘pmg’)

);

foreach($fields as $key => $label)

{

add_settings_field(

$key,

$label,

‘pmgtut_field_cb’,

$page,

$section,

array(‘key’ => $key) // option args

);

}

}

The unified field callback will just look in the args for a key and use that as the field name.  Otherwise it’s the same as our previous field callbacks.

<?php

/**

* Example of a unified callback

*

* @since   1.0

* @uses    get_option

*/

function pmgtut_field_cb($args)

{

// settings name

$setting = ‘pmgtut_setting’;

// get our options

$opts = get_option($setting, array());

// Set up the value with a ternary statment

$val = isset($opts[$args[‘key’]]) ? $opts[$args[‘key’]] : ”;

// actually print the field

printf(

‘’,

esc_attr($setting),

esc_attr($args[‘key’]),

esc_attr($val)

);

}

get_option fetchs values from the wp_options table in the database.  It’s goes without saying that hitting the database every time you need an option might get expensive and slow things down.

Fortunately, WordPress caches options from the start.  Calling get_option multiple times is no more expensive than calling any other function.

Wrapping all your settings api functionality inside a class is a great way to go.  It allows you to set up some class constants and other convenient things to make your life easier.  Our examples don’t benefit a ton from being wrapped in a class, but you can view an example on github.

This is also super easy.  AFter registering your page with add_options_page, you need to do a few specialized things inside the page callback.

settings_fields will take care of outputting a nonce and referrer field for you and do_settings_sections will make WordPress output all the fields.

Your page callback function might look something like this:

<?php

/**

* Menu page callback function

*

* @since   1.0

* @access  public

* @uses    settings_field

* @uses    do_settings_section

* @uses    screen_icon

*/

public static function menu_page_cb()

{

?>

<div class=”wrap”>

<?php screen_icon(); ?>

<h2><?php esc_html_e(‘Sample Options Page’, ‘pmg’); ?></h2>

<form action=”<?php echo admin_url(‘options.php’); ?>” method=”post”>

<?php

settings_fields(‘option_group_or_page’);

do_settings_sections(‘option_group_or_page’);

submit_button(__(‘Save Settings’, ‘pmg’));

?>

</form>

</div>

<?php

}

Insights meet inbox

Sign up for weekly articles & resources.

You can see a complete example on Github along with the rest of the code.


Posted by Christopher Davis

Related Content

thumbnail image

Get Informed

PMG Innovation Challenge Inspires New Alli Technology Solutions

4 MINUTES READ | November 2, 2021

Get Informed

Applying Function Options to Domain Entities in Go

11 MINUTES READ | October 21, 2019

thumbnail image

Get Informed

My Experience Teaching Through Jupyter Notebooks

4 MINUTES READ | September 21, 2019

Get Informed

Trading Symfony’s Form Component for Data Transfer Objects

8 MINUTES READ | September 3, 2019

Get Inspired

Working with an Automation Mindset

5 MINUTES READ | August 22, 2019

Get Informed

Parsing Redshift Logs to Understand Data Usage

7 MINUTES READ | May 6, 2019

Get Inspired

3 Tips for Showing Value in the Tech You Build

5 MINUTES READ | April 24, 2019

thumbnail image

Get Informed

Testing React

13 MINUTES READ | March 12, 2019

Get Inspired

Tips for Designing & Testing Software Without a UX Specialist

4 MINUTES READ | March 6, 2019

Get Informed

A Beginner’s Experience with Terraform

4 MINUTES READ | December 20, 2018

All POST