register_setting()WP 2.7.0

Registers a new option and a callback function to handle the option value when it is saved to the database.

The function can also be used to register a new option to be added to the base WordPress settings page (General, Media Files, Read...) and REST API. The option is added to an existing section with add_settings_field() or you can create a new section with add_settings_section() and add the option there.

The function should be called on the hook:

  • admin_init - to be used through the admin interface.
  • rest_api_init - for using in REST API. You need to specify the show_in_rest=true parameter. See examples below.

The first time an option is added to the database, the sanitize callback is triggered twice.

For example, the following function will return a string with two exclamation points:

function append_exclamation( $input ){ return $input .'!'; }

In this case, the option most likely does not exist yet in the wp_options table, so update_option(), having "seen" that the option does not exist, calls add_option() to add the new option. This is because the hook sanitize_option is called before add_option() is called and is triggered a second time, inside add_option().

ERROR: options page not found - explanation and solution:

This error occurs when the whitelist_options filter knows nothing about your new option.

The register_settings() adds data to the global variable $new_allowed_options. This variable is then combined with the $whitelist_options variable in option_update_filter(), which in turn adds new data to $new_allowed_options, where $option_group is used as the index of the new data. When you get the error "ERROR: options page not found", it means that WP could not find options by key.

The confusion occurs because the first argument $options_group is used as a key, and the actual comparison in the options.php file is with the $options_page parameter, which is $hook_suffix, which is obtained from the result of the add_submenu_page() function.

A simple solution to this problem is to specify the same names for the $option_group and $option_name parameters.

Another reason for this error is when the $page parameter is incorrectly specified when calling the function:

add_settings_section( $id, $title, $callback, $page )

OR

add_settings_field( $id, $title, $callback, $page, $section, $args )

Note: $page must be equal to $menu_slug from the function:

add_theme_page( $page_title, $menu_title, $capability, $menu_slug, $function );

Used in conjunction with other API settings functions:

Hooks from the function

Return

null. Nothing (null).

Usage

register_setting( $option_group, $option_name, $args );
$option_group(string) (required)
Name of the group to which the option will belong. This name must match the name of the group in settings_fields().
$option_name(string) (required)
Name of the option that will be stored in the database.
$args(string|array)

Registered option data.

Before version 4.7, the callback function sanitize_callback was specified here, i.e. you had to specify a string - the name of the function, and now this string is specified in the array element of the same name. The previous version is supported, i.e. there is backward compatibility.

If the option is not planned to be used in REST API, only two array elements sanitize_callback and default can be specified.

$defaults = array(
	'sanitize_callback' => null,
	'default'           => null,
	'type'              => 'string',
	'group'             => $option_group,
	'description'       => '',
	'show_in_rest'      => false,
);
  • sanitize_callback(string|array)
    Name of the callback function that will handle the option value before saving.

    Important: The function will get one parameter - the option value. The value that the function returns will be written to the DB .

  • default(mixed)
    Default value when get_option() is called.

    Affects both the Options API (such as get_option()) and the REST API.

  • type(string) (REST API)
    The data type with which the option is associated. Possible values are 'string', 'boolean', 'integer', 'number', 'array', 'object'.

    Only used in the REST API to define a schema and apply appropriate sanitization.

    Only makes sense if show_in_rest=true. So when show_in_rest=false or when show_in_rest parameter is not set, this parameter may not be specified.

    It does not affect how the admin pages work or how the setting is handled in the options API. (I.e., for example, you can set type=boolean and pass string in form when saving this option - through admin panel. Specified string will be saved in database. But there will be an error in REST API with such situation.

  • description(string) (REST API)
    Description of data to be stored in this option.

    Only used in REST API, so it makes sense only if show_in_rest=true.

  • show_in_rest(true|false|array) (REST API)
    Is it necessary to add this option data to the REST API.

    When registering complex settings, this argument can be an array in which the schema key can be used. See examples bellow.

Default: array()

Examples

0

#1 Use the function via hook

An example showing how to connect the function via hook admin_init:

add_action( 'admin_init', 'register_my_setting' );

function register_my_setting() {
	register_setting( 'my_options_group', 'my_option_name', 'intval' ); 
} 
0

#2 Other examples

For more examples, see Options API.

0

#3 Register textual Option also for REST API

If registration is done for both site and REST API, then function call should be put on both rest_api_init and admin_init hooks. If you use only admin_init hook, the option will not work in REST.

In this case the option will also be visible when accessing the wp-json/wp/v2/settings endpoint.

add_action( 'admin_init', 'register_my_setting' );
add_action( 'rest_api_init', 'register_my_setting' );

function register_my_setting() {

	$args = array(
		'sanitize_callback' => 'sanitize_text_field',
		'default'      => '',
		'type'         => 'string',
		'show_in_rest' => true,
	);

	register_setting( 'my_options_group', 'my_option_name', $args ); 
} 
0

#4 Registration option for REST API only

add_action( 'rest_api_init', 'register_block_core_site_logo_setting', 10 );

/**
 * Register a core site setting for a site logo
 */
function register_block_core_site_logo_setting() {

	register_setting( 'general', 'site_logo', [
		'show_in_rest' => array(
			'name' => 'site_logo',
		),
		'type'         => 'integer',
		'description'  => __( 'Site logo.' ),
	] );
}
0

#5 Array type option in REST API

If you want to save the array in settings and also show this array in the wp-json/wp/v2/settings endpoint, you must specify the array scheme in the show_in_rest parameter.

add_action( 'admin_init',    'wpdocs_foo_register_settings' );
add_action( 'rest_api_init', 'wpdocs_foo_register_settings' );

function wpdocs_foo_register_settings() {

	register_setting( 'general_setting', 'id' );
	register_setting( 'general_setting', 'order' );
	register_setting(
		'general_setting',
		'slider-data',
		array(
			'show_in_rest' => array(
				'name' => 'images_slide',
				'schema' => array(
					'type'  => 'array',
					'items' => array(
						'id'    => 'string',
						'order' => 'string',
					),
				),
			),
			'type' => 'array',
			'sanitize_callback' => array( $this, 'wpdocs_admin_post_save_data' ),
		)
	);
}
0

#6 Example for object and array types:

register_setting(
	'dp_example_settings_group',
	'dp_example_array_settings',
	array(
		'type'         => 'object',
		'default'      => array(
			'A',
			'B',
			'C',
		),
		'show_in_rest' => array(
			'schema' => array(
				'type'  => 'object',
				'items' => array(
					'type' => 'string',
				),
			),
		),
	)
);

register_setting(
	'dp_example_settings_group',
	'dp_example_object_settings',
	array(
		'type'         => 'object',
		'default'      => array(
			'some_str' => 'A',
			'some_int' => 3,
		),
		'show_in_rest' => array(
			'schema' => array(
				'type'       => 'object',
				'properties' => array(
					'some_str' => array(
						'type' => 'string',
					),
					'some_int' => array(
						'type' => 'integer',
					),
				),
			),
		),
	)
);
-2

#7 Processing when sanitize is triggered twice

As mentioned in the note above, sanitize can work twice when the option is first added to the database. Therefore, if there are any performance-critical points or other points that need to be taken into account in this case, they need to be handled separately in the sanitize function.

add_action( 'admin_init', 'on_admin_init' );

/*
 *  Add custom options to whitelist, allowing valiated settings to be saved by form.
 */
function on_admin_init(): void 
{
	register_setting( PLUGIN_SLUG, PLUGIN_SLUG, [ 'sanitize_callback' => 'my_sanitize_settings' ] ); 
}

/*
 *  Sanitize the form input.
 */
function my_sanitize_settings( $input = NULL ):  
{
	// Detect multiple sanitizing passes.
	// Accomodates bug: https://core.trac.wordpress.org/ticket/21989
	static $pass_count = 0; $pass_count++;

	if ( $pass_count <= 1 ) {
		// Handle any single-time / performane sensitive actions.

	}

	// Insert regular santizing code here.
}

The function only fires twice the first time a setting is saved and added to a DB table. Subsequent updates to the setting perform the sanitize_callback function only once. So unless you are doing some very, very, very heavy sanitize operation, there is no need to worry about it.

Notes

  • Global. Array. $new_allowed_options
  • Global. Array. $wp_registered_settings

Changelog

Since 2.7.0 Introduced.
Since 3.0.0 The misc option group was deprecated.
Since 3.5.0 The privacy option group was deprecated.
Since 4.7.0 $args can be passed to set flags on the setting, similar to register_meta().
Since 5.5.0 $new_whitelist_options was renamed to $new_allowed_options. Please consider writing more inclusive code.

register_setting() code WP 6.5.2

function register_setting( $option_group, $option_name, $args = array() ) {
	global $new_allowed_options, $wp_registered_settings;

	/*
	 * In 5.5.0, the `$new_whitelist_options` global variable was renamed to `$new_allowed_options`.
	 * Please consider writing more inclusive code.
	 */
	$GLOBALS['new_whitelist_options'] = &$new_allowed_options;

	$defaults = array(
		'type'              => 'string',
		'group'             => $option_group,
		'description'       => '',
		'sanitize_callback' => null,
		'show_in_rest'      => false,
	);

	// Back-compat: old sanitize callback is added.
	if ( is_callable( $args ) ) {
		$args = array(
			'sanitize_callback' => $args,
		);
	}

	/**
	 * Filters the registration arguments when registering a setting.
	 *
	 * @since 4.7.0
	 *
	 * @param array  $args         Array of setting registration arguments.
	 * @param array  $defaults     Array of default arguments.
	 * @param string $option_group Setting group.
	 * @param string $option_name  Setting name.
	 */
	$args = apply_filters( 'register_setting_args', $args, $defaults, $option_group, $option_name );

	$args = wp_parse_args( $args, $defaults );

	// Require an item schema when registering settings with an array type.
	if ( false !== $args['show_in_rest'] && 'array' === $args['type'] && ( ! is_array( $args['show_in_rest'] ) || ! isset( $args['show_in_rest']['schema']['items'] ) ) ) {
		_doing_it_wrong( __FUNCTION__, __( 'When registering an "array" setting to show in the REST API, you must specify the schema for each array item in "show_in_rest.schema.items".' ), '5.4.0' );
	}

	if ( ! is_array( $wp_registered_settings ) ) {
		$wp_registered_settings = array();
	}

	if ( 'misc' === $option_group ) {
		_deprecated_argument(
			__FUNCTION__,
			'3.0.0',
			sprintf(
				/* translators: %s: misc */
				__( 'The "%s" options group has been removed. Use another settings group.' ),
				'misc'
			)
		);
		$option_group = 'general';
	}

	if ( 'privacy' === $option_group ) {
		_deprecated_argument(
			__FUNCTION__,
			'3.5.0',
			sprintf(
				/* translators: %s: privacy */
				__( 'The "%s" options group has been removed. Use another settings group.' ),
				'privacy'
			)
		);
		$option_group = 'reading';
	}

	$new_allowed_options[ $option_group ][] = $option_name;

	if ( ! empty( $args['sanitize_callback'] ) ) {
		add_filter( "sanitize_option_{$option_name}", $args['sanitize_callback'] );
	}
	if ( array_key_exists( 'default', $args ) ) {
		add_filter( "default_option_{$option_name}", 'filter_default_option', 10, 3 );
	}

	/**
	 * Fires immediately before the setting is registered but after its filters are in place.
	 *
	 * @since 5.5.0
	 *
	 * @param string $option_group Setting group.
	 * @param string $option_name  Setting name.
	 * @param array  $args         Array of setting registration arguments.
	 */
	do_action( 'register_setting', $option_group, $option_name, $args );

	$wp_registered_settings[ $option_name ] = $args;
}