The WordPress settings API makes it easy to add shared content to a site for administrators to edit. But it would be nice to let other roles edit some settings too.
When we register a setting in the WordPress settings API, that setting can be edited and saved only by administrators by default. This is a good thing, because often settings allow major changes to the behaviour and configuration of a website.
But sometimes we want to use the settings API to let clients easily change some common site content, like:
- contact details — email address, phone number, Google Maps link
- site-wide disclaimer text
- site-wide notices
Clients often like to delegate editing content like that to staff with limited access to the website. We can allow them to edit selected settings through a WordPress filter hook:
option_page_capability_{$option_page}
If our setting is named “example_disclaimer”, we can add a filter hook to option_page_capability_example_disclaimer
and change the capability required for editing that setting. The default capability is manage_options
, and we can change it to edit_pages
so that anyone with an Editor or Administrator role can edit that setting.
Here’s a working example for contact details in settings, without the form HTML:
const OPT_SETTINGS = 'example_settings'; const SETTING_PHONE = 'phone'; const SETTING_EMAIL = 'email'; const SETTING_OFFICE_HOURS = 'office_hours'; /** * register settings */ add_action('admin_init', function() { add_settings_section(OPT_SETTINGS, false, false, OPT_SETTINGS); register_setting(OPT_SETTINGS, OPT_SETTINGS, __NAMESPACE__ . '\\settings_validate'); }); /** * register admin menu items */ add_action('admin_menu', function() { add_options_page('Contact details', 'Contact details', 'edit_pages', 'example', __NAMESPACE__ . '\\settings_page'); }, 5); /** * allow Editor role to save settings * @param string $capability * @return string */ add_filter('option_page_capability_' . OPT_SETTINGS, function($capability) { return 'edit_pages'; }); /** * show settings page */ function settings_page() { $settings = get_option(OPT_SETTINGS); require __DIR__ . '/views/admin-settings.php'; } /** * validate settings on save * @param array $input * @return array */ function settings_validate($input) { $output = []; $output[SETTING_PHONE] = trim(sanitize_text_field($input[SETTING_PHONE] ?? '')); $output[SETTING_EMAIL] = trim(sanitize_text_field($input[SETTING_EMAIL] ?? '')); $output[SETTING_OFFICE_HOURS] = trim(sanitize_text_field($input[SETTING_OFFICE_HOURS] ?? '')); return $output; }
Of course, we don’t have to add our settings page under the Settings menu; we can attach it to whichever admin menu item we’d like to. For example, I like to add the disclaimer text to the Pages menu:
/** * register admin menu items */ add_action('admin_menu', function() { add_pages_page('Disclaimer', 'Disclaimer', 'edit_pages', 'example-disclaimer', __NAMESPACE__ . '\\disclaimer_page'); });
So job can be done using the simple available tools (settings API) without requiring everyone to be an administrator.