Options Pages in Multisite

Ok, you can find a lot of guides about options pages and settings API but I didn’t find any good ones about creating options pages in WordPress Multisite.

#WordPress Multisite  /    /   4

Step 1. Where in Menu you would like to Display your Settings Page? #

You can place the link to your settings page anywhere in Network Dashboard menu, to create a parent menu link, we will use add_menu_page() function, to create a child one – add_submenu_page().

Example:

Custom settings pages in Network Dashboard menu
I added one settings page under Themes menu item and another settings page just at the very end of the menu.

Let’s add both of these links:

add_action("network_admin_menu", "misha_new_menu_items");
function misha_new_menu_items() {
 
	add_submenu_page(
		'themes.php', // Parent element
		'Settings Page 1', // Text in browser title bar
		'Settings Page 1', // Text to be displayed in the menu.
		'manage_options', // Capability
		'settings-page-1', // Page slug, will be displayed in URL
		'misha_settings_page_1' // Callback function which displays the page
	);
 
	add_menu_page(
		'Settings Page 2',
		'Settings Page 2',
		'manage_options',
		'settings-page-2',
		'misha_settings_page_2',
 		'', // Icon
		100 // Position of the menu item in the menu.
	);
 
}

A couple words where to insert the code – the best way is to create your custom plugin and activate it for the Network.

Line 5 – for submenu elements you can specify the Parent item:

  • index.php – Dashboard,
  • sites.php – Sites,
  • users.php – Users,
  • themes.php – Themes,
  • plugins.php – Plugins,
  • settings.php – Settings

Line 21 – for Parent elements play with the position parameter (in the example it is equal to 100), the less the number, the higher your menu item will be displayed in menu.

Custom Icon #

Ok, but what if I don’t want the default cog icon to be displayed for my custom settings pages?

There are two ways to change the icon, the first and the simplest one is to use the build-in Dashicons icons set. If you want to use it follow these steps:

  • Go to Dashicons website,
  • Select an icon you like and copy its code, example: dashicons-admin-tools,
  • Use this code as the 6th parameter of add_menu_page() function, example:
    add_menu_page(
    	'Settings Page 2',
    	'Settings Page 2',
    	'manage_options',
    	'settings-page-2',
    	'misha_settings_page_2',
    	'dashicons-admin-tools', // here it is
    	100 
    );

Example:

Custom menu icon in network dashboard.

The second way may be helpful if there is no icon in Dashicons set which you need, maybe it is your custom plugin logo. In this method you have to include your own icon set in admin and add some custom CSS, example:

add_action( 'admin_head', 'misha_custom_admin_icons' );
function misha_custom_admin_icons(){
	echo '<style>
 
	/* 
 
	 you can include your custom icon sets with @font-face here
 
	*/
 
	#toplevel_page_settings-page-2 .wp-menu-image:before {
		font-family: "your custom icon font name";
		content: "\e909";
	}
	</style>';
}

As you can see on line 11, part of the element ID attribute is our page slug, #toplevel_page_{SLUG}.

Step 2. Settings Fields #

As you remember from Step 1, there should be callback functions misha_settings_page_1() and misha_settings_page_2() to print the page content and option fields.

I’m not going to create both of these options pages, one of them will be enough to show you how it works.

function misha_settings_page_1() {
 
	echo '<div class="wrap">
		<h1>Theme Options</h1>
		<form method="post" action="edit.php?action=mishaaction">';
			wp_nonce_field( 'misha-validate' );
			echo '
			<h2>Section 1</h2>
			<table class="form-table">
				<tr>
					<th scope="row"><label for="some_field">Some option</label></th>
					<td>
						<input name="some_field" class="regular-text" type="text" id="some_field" value="' . esc_attr( get_site_option( 'some_field') ) . '" />
						<p class="description">Field description can be added here.</p>
					</td>
				</tr>
			</table>
			<h2>Section 2</h2>
			<table class="form-table">
				<tr>
					<th scope="row">Some checkbox</th>
					<td><label><input name="some_checkbox" type="checkbox" value="yes" ' . checked('yes', get_site_option( 'some_checkbox'), false ) . '> Yes, check this checkbox</label></td>
				</tr>
			</table>';
			submit_button();
		echo '</form></div>';
 
}

A couple words about functions:

  • get_option( 'option_name' ) and update_option( 'option_name', $value ) functions should be familiar to you. These functions work with the current blog settings in database.
  • There are similar functions get_blog_option( $blog_id, 'option_name' ) and update_blog_option( $blog_id, 'option_name', $value ) that works with the certain blog which blog ID is passed to the first function argument. If you need an example, you can check it in this tutorial I published before.
  • But in the current tutorial we work with get_site_option( 'option_name' ) and update_site_option( 'option_name', $value ) because these functions allows to work with the settings of the whole network.

Why we do not use Settings API here #

I saw some examples of using Settings API for Multisite Options Pages and I couldn’t understand what was the reason of using it, because in those examples there was another hook for saving the option fields.

The reason why we usually use Settings API is because we do not have to save option values ourselves! Settings API do it instead. Isn’t it right?

Step 3. Save Fields #

Here is how I do it:

  • Form action attribute in Step 2 must contain the value in the following format edit.php?action={ACTION},
  • In this step we will use network_admin_edit_{ACTION} to process the settings.

So, let’s go 🚀

add_action( 'network_admin_edit_mishaaction', 'misha_save_settings' );
 
function misha_save_settings(){
 
	check_admin_referer( 'misha-validate' ); // Nonce security check
 
	update_site_option( 'some_field', $_POST['some_field'] );
	update_site_option( 'some_checkbox', $_POST['some_checkbox'] );
 
	wp_redirect( add_query_arg( array(
		'page' => 'settings-page-1',
		'updated' => true ), network_admin_url('themes.php')
	));
 
	exit;
 
}

Some significant things you have to keep in mind:

  1. Nonce field parameter misha-validate on line 5 and in Step 2, line 6 must match.
  2. And it is obvious, that field names must be appropriated too, but you can use different input field names and option settings names – it is OK.
  3. Set the redirect correctly, the new URL should be like this: {YOU SETTINGS PAGE}&updated=true. In the example I added my page under Themes menu item, so, on line 12 I have network_admin_url('themes.php'), but if you added it under Users menu, this value will be changed to network_admin_url('users.php') etc. And do not forget to make sure that page parameter on line 11 matches the slug of your settings page! 😁

Step 4. Notices #

And welcome to the most simple step now! Your settings page should work perfectly by this moment. But we have to display some notices for better user experience, haven’t we?

add_action( 'network_admin_notices', 'misha_custom_notices' );
 
function misha_custom_notices(){
 
	if( isset($_GET['page']) && $_GET['page'] == 'settings-page-1' && isset( $_GET['updated'] )  ) {
		echo '<div id="message" class="updated notice is-dismissible"><p>Settings updated. You\'re the best!</p><button type="button" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span></button></div>';
	}
 
}

The only thing you should care about here is that page slug settings-page-1 on line 5 matches the actual page slug.

And finally, that’s how my page looks like:

Creating custom options pages in WordPress Network Dashboard
Misha Rudrastyh
About the author Misha Rudrastyh

Passionate about WordPress and snowboarding, creating websites for over 9 years! Let's work together — just contact me.

If you are a developer too, subscribe to my facebook page.

Comments 4

Leave your question or feedback

phpjsHTMLCSSSQLCode
Please, enter a comment
Please, enter a name
Incorrect email