WordPress Plugin Settings Page (Settings API)

Most plugins need a settings page for the site owner. The Settings API of WordPress handles the form, saving, the security nonce and the messages for you, so you only describe the page, the sections and the fields.

The idea

  1. add_options_page() adds a page under the Settings menu.
  2. register_setting() tells WordPress the name of the option and how to clean it.
  3. add_settings_section() and add_settings_field() describe the form.
  4. The page uses settings_fields() and do_settings_sections() to print the form.

The complete plugin

<?php
/**
 * Plugin Name: TC Settings Demo
 */
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// 1. Add the page under Settings.
add_action( 'admin_menu', function () {
	add_options_page( 'TC Settings', 'TC Settings', 'manage_options', 'tc-settings', 'tcs_render_page' );
} );

// 2. Register the option and the form.
add_action( 'admin_init', function () {
	register_setting( 'tcs_group', 'tcs_greeting', array(
		'type'              => 'string',
		'sanitize_callback' => 'sanitize_text_field',
		'default'           => 'Hello!',
	) );

	add_settings_section( 'tcs_main', 'Main settings', '__return_false', 'tc-settings' );

	add_settings_field( 'tcs_greeting', 'Greeting text', function () {
		printf(
			'<input type="text" name="tcs_greeting" value="%s" class="regular-text">',
			esc_attr( get_option( 'tcs_greeting', 'Hello!' ) )
		);
	}, 'tc-settings', 'tcs_main' );
} );

// 3. Print the page.
function tcs_render_page() {
	if ( ! current_user_can( 'manage_options' ) ) {
		return;
	}
	?>
	<div class="wrap">
		<h1>TC Settings</h1>
		<form action="options.php" method="post">
			<?php
			settings_fields( 'tcs_group' );
			do_settings_sections( 'tc-settings' );
			submit_button();
			?>
		</form>
	</div>
	<?php
}

Check the page in the dashboard

We log in as the admin (like in a browser), and read the new page:

Terminal output

$ curl -s -b cookies.txt "http://example.com/wp-admin/options-general.php?page=tc-settings" | grep -E -o "<h1>[^<]*</h1>|<input type=\"text\" name=\"tcs_greeting\"[^>]*>|name='(option_page|action)' value='[^']*'"
<h1>TC Settings</h1>
name='option_page' value='tcs_group'
<input type="text" name="tcs_greeting" value="Hello!" class="regular-text">

The page has our heading and the field, and settings_fields() added the hidden fields (like the option group and the nonce) for us. The form posts to options.php, which saves the data.

What the sanitize callback does

WordPress runs the sanitize callback every time the option is saved. The settings are registered on admin_init, which runs on dashboard requests, so in this test we run it by hand and then save a bad value:

do_action( 'admin_init' );
update_option( 'tcs_greeting', '<script>alert(1)</script>Welcome <b>friend</b>' );
var_dump( get_option( 'tcs_greeting' ) );
Output

string(14) "Welcome friend"

The tags were removed before the value went into the database.

Read the setting in your plugin

$greeting = get_option( 'tcs_greeting', 'Hello!' );
echo esc_html( $greeting );

Rules for a good settings page

  • Always check the capability (manage_options), both for the menu and in the page function.
  • Always sanitize on save, and escape on output.
  • Use one option which stores an array when you have many settings, to keep the wp_options table small.
  • Choose the right menu: use add_options_page() for settings, or add_menu_page() for a bigger plugin with its own menu.
Note: Prefix the option names (tcs_greeting) and delete them in uninstall.php. See Create a WordPress Plugin for the uninstall step. Next: Data Validation and Security.

Congratulations! Chapter Finished. Learn more about the similar topics:
Exercises & Assignments
No Content Found.
Interview Questions & Answers
No Content Found.