Network Options Pages

This tutorial is how to add settings pages to Network Admin with WordPress Multisite installed. I have a couple amazing tutorial on my blog where you can learn how to create options pages with Settings API or how to add site-specific settings in Network Admin > All Sites.

That’s how the settings page we are going to create here looks like:

network options page

1. Network Admin Menu

This step is very similar to what we did when created regular options pages. The only change here is that we are going to use network_admin_menu hook instead of admin_menu.

And we are going to use add_menu_page() and add_submenu_page() functions in order to add new network admin settings pages. Let’s begin with a simple code like below:

add_action( 'network_admin_menu', 'rudr_network_settings_pages' );
function rudr_network_settings_pages() {

	add_menu_page( 'Schedule', 'Schedule', 'manage_network_options', 'schedule-page', 'schedule_cb', 'dashicons-airplane' );

	add_submenu_page( 'themes.php', 'More settings', 'More settings', 'manage_network_options', 'more-settings', 'more_settings_cb' );


function schedule_cb() {


function more_settings_cb() {


How both add_menu_page() and add_submenu_page() functions are working is described pretty near in here. But please keep in mind that the best place where you can insert this code is a network-wide activated custom plugin.

Here is the pages:

network admin settings pages
Both pages are completely empty, it is because callback functions schedule_cb() and more_settings_cb() are completely empty. But we are going to add fields in just a little bit, in a next step.

Also when using add_submenu_page() in Network Dashboard you can use one of the slugs below:

SlugParent page

2. Network Settings Page (without Settings API)

Let’s begin with the moment that in order to save network settings we are going to use network_admin_edit_{ACTION} action hook. If you look through any of the available network options pages tutorials, you will see that this hook is used in every of them. The thing is that when we create regular options pages in WordPress we do not have to do anything to save them into the database – Settings API is going to care about it. But now… we are using an action hook… so what is the point of combining register_setting() function with it?

What do you think guys, is there a Multisite equivalent of register_setting()? Please let me know in comments.

Add fields

function schedule_cb() {

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


Save field values

Please keep in mind, that network_admin_edit_ hook contains an action parameter which is a part of our form action HTML attribute, in our example it will be <form action="edit.php?action=mishaaction">.

// add_action( 'network_admin_edit_{ACTION}', 'rudr_save_settings' );
add_action( 'network_admin_edit_mishaaction', 'rudr_save_settings' );

function rudr_save_settings(){

	check_admin_referer( 'misha-validate' ); // Nonce security check

	update_site_option( 'some_field', sanitize_text_field( $_POST[ 'some_field' ] ) );

	$checkbox = isset( $_POST[ 'some_checkbox' ] ) && 'yes' === $_POST[ 'some_checkbox' ] ? 'yes' : 'no';
	update_site_option( 'some_checkbox', $checkbox );

				'page' => 'schedule-page',
				'updated' => true
			network_admin_url( 'admin.php' )


Functions get_option() and update_option() should be familiar to you, they work with the current blog settings in database. There are also similar functions get_blog_option() and update_blog_option() that allow to work with options of a specific blog of a network, example is here. But in the current tutorial we work with get_site_option() and update_site_option() because these functions allow to work with the settings of the whole network.

When saving options do not forget about sanitization.


For regular option pages notices we used admin_notices hook, for network options pages all is the same, but just use a different hook – network_admin_notices.

add_action( 'network_admin_notices', 'rudr_notice' );

function rudr_notice(){

	if( isset( $_GET[ 'page' ] ) && 'schedule-page' === $_GET[ 'page' ] && isset( $_GET[ 'updated' ] )  ) {
		?><div id="message" class="updated notice"><p>Settings updated. You're the best!</p></div><?php


The result:

network options page
Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.

Need some developer help? Contact me

Follow me on X