The other day I was googling up information about coding options pages in the network administration dashboard of a WordPress multisite installation and I noticed that some people think they cannot use the Settings API with those pages. I also noticed there was no article showing how to do it, so here it is.
Following is the documented code you need to create a network options page using the WordPress Settings API. You can also go to GitHub and download a fully functional plugin that demonstrates that code, I added a normal options page in the plugin so that you can compare the code.
If you have any remark or question just use the comment section.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
/** * First let's hook up to the 'network_admin_menu' action and create an options * page. * * Then we use the Settings API to create a section and register an option. * * You will notice the only difference with coding a normal page is the parent * slug of our option page (must be 'settings.php') and the capability required * for this page to be displayed (here 'manage_network_options'). */ add_action('network_admin_menu', 'post3872_network_admin_menu'); function post3872_network_admin_menu() { // Create our options page. add_submenu_page('settings.php', __('My Network Options', 'post3872'), __('My Plugin', 'post3872'), 'manage_network_options', 'post3872_network_options_page', 'post3872_network_options_page_callback'); // Create a section (we won't need a section header). add_settings_section('default', __('Default Network Options'), false, 'post3872_network_options_page'); // Create and register our option (we make the option id very explicit because // this is the key that will be used to store the options. register_setting('post3872_network_options_page', 'post3872_network_option_1'); add_settings_field('post3872_network_option_1', __('Network option one', 'post3872'), 'post3872_network_option_1_callback', 'post3872_network_options_page', 'default'); } /** * Displays our only option. Nothing special here. */ function post3872_network_option_1_callback() { ?> <label><input type="checkbox" name="post3872_network_option_1" value="1" <?php checked(get_site_option('post3872_network_option_1')); ?> /> <?php _e('Check this box if you want to activate network option one.', 'post3872') ?></label><?php } /** * Displays the options page. The big difference here is where you post the data * because, unlike for normal option pages, there is nowhere to process it by * default so we have to create our own hook to process the saving of our options. */ function post3872_network_options_page_callback() { if (isset($_GET['updated'])): ?> <div id="message" class="updated notice is-dismissible"><p><?php _e('Options saved.') ?></p></div> <?php endif; ?> <div class="wrap"> <h1><?php _e('My Network Options', 'post3872'); ?></h1> <form method="POST" action="edit.php?action=post3872_update_network_options"><?php settings_fields('post3872_network_options_page'); do_settings_sections('post3872_network_options_page'); submit_button(); ?> </form> </div> <?php } /** * This function here is hooked up to a special action and necessary to process * the saving of the options. This is the big difference with a normal options * page. */ add_action('network_admin_edit_post3872_update_network_options', 'post3872_update_network_options'); function post3872_update_network_options() { // Make sure we are posting from our options page. There's a little surprise // here, on the options page we used the 'post3872_network_options_page' // slug when calling 'settings_fields' but we must add the '-options' postfix // when we check the referer. check_admin_referer('post3872_network_options_page-options'); // This is the list of registered options. global $new_whitelist_options; $options = $new_whitelist_options['post3872_network_options_page']; // Go through the posted data and save only our options. This is a generic // way to do this, but you may want to address the saving of each option // individually. foreach ($options as $option) { if (isset($_POST[$option])) { // Save our option with the site's options. // If we registered a callback function to sanitizes the option's // value it will be called here (see register_setting). update_site_option($option, $_POST[$option]); } else { // If the option is not here then delete it. It depends on how you // want to manage your defaults however. delete_site_option($option); } } // At last we redirect back to our options page. wp_redirect(add_query_arg(array('page' => 'post3872_network_options_page', 'updated' => 'true'), network_admin_url('settings.php'))); exit; } |
Image Credits: Antonio Ruiz GarcÃa
Thank you! You saved my life.
Very nice explanation.
You’re welcome :)
BTW, you don’t need to call
apply_filters('sanitize_option_' . $option_name, $_POST[$option]);
, because when callingupdate_site_option()
, this filter will also be called.you’re right, thanks :)
Thank you so much, your code worked perfectly!
I just want to say for the benefit of anyone else reading this that I am using WordPress 4.8 and I had to change the redirect target from settings.php to admin.php.
Thanks for the info Alex, I will update the code when I have 5mn :)
Pingback: The wacky world of network activated WordPress plugins in multisite
Hi Claude,
thanks for the really helpful post! :)
Regarding the redirect target: For me it works great with
settings.php
also in 4.8.Cheers,
Florian
Thanks Florian,
I think anything works, it just depends where you want to send people after they submitted the form :)
Your
add_filter('network_admin_menu', 'post3872_network_admin_menu');
line should probably beadd_action('network_admin_menu', 'post3872_network_admin_menu');
(since you’re not filtering anything).correct, thanks :)
Still working through trying to get this working. So far, it doesn’t seem that the options are saving.
Side note: As part of working through this, I noticed that core changed
$new_whitelist_options
to$new_allowed_options
here: https://core.trac.wordpress.org/changeset/48477Anyway, is this code working for others? I’ve hit a bit of a wall.
EDIT: Correction. This is working as-is. When trying to change the checkbox field to a text field, it doesn’t save.