Create a Custom Settings Page in WordPress
I can’t count how many custom settings pages I created in WordPress over the years, not only for clients but for my own projects as well.
Still, this morning, I struggled, because my options just wouldn’t save. So I decided to write down all the parts, that make a working settings page.
It is not a complete example/guide, just a very basic reference for my future self.
Step 1: Register your setting(s)
Define the option group and give your option a name and also add a callback for validation.1
function my_register_settings() {
register_setting( 'my_settings_group', 'my_settings', [ 'sanitize_callback' => 'my_settings_validate' ] );
}
add_action( 'admin_init', 'my_register_settings' );
Step 2: Validate your setting(s)
function my_settings_validate( $args ) {
// Validate & sanitize input
return $args;
}
Make sure all input is valid – also sanitize everything before passing it along, as it gets saved to the database after that.
Step 3: Set capability (optional)
Define the capability that is needed to change/save your option. By default this is set to manage_options
.
function my_settings_capability( $capability ) {
return 'edit_pages';
}
add_filter( 'option_page_capability_my_settings_group', 'my_settings_capability' );
Step 4: The form
Here’s where I made a mistake: I didn’t point the form’s action attribute to options.php
– which is required if you want sanitize and save your input automatically.
So my (now working) form looked something like this:
<form action="options.php">
<?php
settings_errors();
$default_options = [
// Default option values
];
$options = wp_parse_args( get_option( 'my_settings' ), $default_options );
?>
<!-- Input fields, select boxes, submit, etc. -->
</form>
→ Settings Errors Function
→ Parse Arguments Function
I hope this is somewhat helpful. I know it will be for me, the next time I create a settings page.
- I realized for the first time that the third parameter is not meant as a function callback to validate your setting, but rather has multiple arguments. I still think it is perfectly fine to use the “sanitize_callback” to also do validation at this point. (Please correct my if I am wrong.) ↩︎