Plugin settings pages allow users to configure your plugin without touching code. The WordPress Settings API provides a standardized, secure way to create settings pages that follow WordPress UI conventions and handle data properly.
Why Use the Settings API
The Settings API offers significant advantages over custom form handling:
Automatic security – Nonces and capability checks are built-in Consistent UI – Pages match WordPress admin styling automatically Data handling – WordPress manages saving, sanitization, and validation Best practices – Follows WordPress standards automatically
Avoid building custom form handlers. The Settings API is tested, secure, and maintained by WordPress core.
Creating the Admin Menu
First, add a menu page to WordPress admin:
function dprt_add_settings_page() {
add_options_page(
'My Plugin Settings', // Page title
'My Plugin', // Menu title
'manage_options', // Capability
'my-plugin-settings', // Menu slug
'dprt_render_settings_page' // Callback function
);
}
add_action( 'admin_menu', 'dprt_add_settings_page' );This adds a submenu under Settings. For a top-level menu, use add_menu_page() instead.
Registering Settings
Register each setting WordPress should manage:
function dprt_register_settings() {
register_setting(
'dprt_settings_group', // Option group
'dprt_api_key', // Option name
array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'default' => ''
)
);
register_setting(
'dprt_settings_group',
'dprt_enable_feature',
array(
'type' => 'boolean',
'default' => false
)
);
}
add_action( 'admin_init', 'dprt_register_settings' );Each setting gets a name (stored in wp_options), type, sanitization callback, and default value.
Creating Settings Sections
Organize settings into logical sections:
function dprt_register_settings_sections() {
add_settings_section(
'dprt_api_section', // Section ID
'API Configuration', // Section title
'dprt_api_section_callback', // Section callback
'my-plugin-settings' // Page slug
);
add_settings_section(
'dprt_display_section',
'Display Options',
'dprt_display_section_callback',
'my-plugin-settings'
);
}
add_action( 'admin_init', 'dprt_register_settings_sections' );
function dprt_api_section_callback() {
echo '<p>Configure API settings for third-party integrations.</p>';
}
function dprt_display_section_callback() {
echo '<p>Control how content displays on your site.</p>';
}Sections group related settings with descriptive headers and instructions.
Adding Settings Fields
Add individual fields to sections:
function dprt_register_settings_fields() {
// Text field
add_settings_field(
'dprt_api_key', // Field ID
'API Key', // Field title
'dprt_api_key_callback', // Field callback
'my-plugin-settings', // Page slug
'dprt_api_section' // Section ID
);
// Checkbox field
add_settings_field(
'dprt_enable_feature',
'Enable Feature',
'dprt_enable_feature_callback',
'my-plugin-settings',
'dprt_display_section'
);
}
add_action( 'admin_init', 'dprt_register_settings_fields' );Field Callback Functions
Field callbacks render the HTML inputs:
// Text input
function dprt_api_key_callback() {
$value = get_option( 'dprt_api_key', '' );
echo '<input type="text" name="dprt_api_key" value="' . esc_attr( $value ) . '" class="regular-text">';
echo '<p class="description">Enter your API key from the provider.</p>';
}
// Checkbox
function dprt_enable_feature_callback() {
$value = get_option( 'dprt_enable_feature', false );
echo '<input type="checkbox" name="dprt_enable_feature" value="1" ' . checked( 1, $value, false ) . '>';
echo '<label>Enable this experimental feature</label>';
}
// Select dropdown
function dprt_display_style_callback() {
$value = get_option( 'dprt_display_style', 'default' );
$options = array(
'default' => 'Default Style',
'minimal' => 'Minimal Style',
'fancy' => 'Fancy Style'
);
echo '<select name="dprt_display_style">';
foreach ( $options as $key => $label ) {
echo '<option value="' . esc_attr( $key ) . '" ' . selected( $value, $key, false ) . '>' . esc_html( $label ) . '</option>';
}
echo '</select>';
}Always escape output and use WordPress helper functions like checked() and selected().
Rendering the Settings Page
The settings page displays all registered sections and fields:
function dprt_render_settings_page() {
// Check user capabilities
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
// Show error/update messages
settings_errors( 'dprt_messages' );
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<form action="options.php" method="post">
<?php
// Output security fields
settings_fields( 'dprt_settings_group' );
// Output settings sections
do_settings_sections( 'my-plugin-settings' );
// Output submit button
submit_button( 'Save Settings' );
?>
</form>
</div>
<?php
}settings_fields() outputs hidden nonce fields. do_settings_sections() renders all registered sections and fields. submit_button() creates the submit button.
Custom Sanitization
Implement custom sanitization for complex data:
function dprt_sanitize_email_list( $input ) {
$emails = explode( ',', $input );
$sanitized = array();
foreach ( $emails as $email ) {
$email = trim( $email );
if ( is_email( $email ) ) {
$sanitized[] = sanitize_email( $email );
}
}
return implode( ', ', $sanitized );
}
register_setting(
'dprt_settings_group',
'dprt_email_list',
array(
'sanitize_callback' => 'dprt_sanitize_email_list'
)
);Sanitization callbacks clean data before saving to the database.
Validation and Error Messages
Add validation with admin notices:
function dprt_validate_api_key( $value ) {
if ( strlen( $value ) < 32 ) {
add_settings_error(
'dprt_messages',
'dprt_message',
'API key must be at least 32 characters long.',
'error'
);
// Return old value to prevent invalid save
return get_option( 'dprt_api_key' );
}
return $value;
}Tabbed Settings Interface
For complex plugins, organize settings into tabs:
function dprt_render_tabbed_settings_page() {
$active_tab = isset( $_GET['tab'] ) ? $_GET['tab'] : 'general';
?>
<div class="wrap">
<h1>My Plugin Settings</h1>
<h2 class="nav-tab-wrapper">
<a href="?page=my-plugin-settings&tab=general" class="nav-tab <?php echo $active_tab === 'general' ? 'nav-tab-active' : ''; ?>">General</a>
<a href="?page=my-plugin-settings&tab=advanced" class="nav-tab <?php echo $active_tab === 'advanced' ? 'nav-tab-active' : ''; ?>">Advanced</a>
</h2>
<form action="options.php" method="post">
<?php
if ( $active_tab === 'general' ) {
settings_fields( 'dprt_general_settings' );
do_settings_sections( 'dprt-general-settings' );
} else {
settings_fields( 'dprt_advanced_settings' );
do_settings_sections( 'dprt-advanced-settings' );
}
submit_button();
?>
</form>
</div>
<?php
}Retrieving Saved Options
Access saved settings anywhere in your plugin:
// Single option
$api_key = get_option( 'dprt_api_key', '' );
// Multiple options
$options = array(
'api_key' => get_option( 'dprt_api_key', '' ),
'enable_feature' => get_option( 'dprt_enable_feature', false ),
'display_style' => get_option( 'dprt_display_style', 'default' )
);Always provide default values as the second parameter.
Conclusion
The WordPress Settings API streamlines plugin configuration. Register settings, create sections and fields, render the page with built-in functions, and WordPress handles security, validation, and data storage. This approach creates professional, secure settings pages that integrate seamlessly with WordPress admin.
- Real-world settings page examples
Includes complete code examples, form templates, and best practices for creating user-friendly plugin settings interfaces.
External Links
Call to Action
Supercharge your development! ACF Copilot Pro generates ACF field groups with AI, exports to PHP, and accelerates custom field workflows—try it free!

