Create Settings Pages with Tabs

In many different WordPress plugins settings are organized by tabs, we can consider it like a default functionality, because when creating tabs you don’t even need to write any CSS for them, it is already provided by WordPress code, just use the appropriate classes.

For example:

Tabs in WooCommerce plugin settings page
WooCommerce plugin settings page.

Or:

crossposting plugin settings tabs
The tabs in the settings page of my Simple WP Crossposting plugin.

So in this tutorial we’re going to create a simple WordPress settings page with a couple of tabs in two different ways:

  1. In the first method we’re going to create options pages from scratch using WordPress Settings API. If you’ve never had a chance to work with it, then either consider using the second way or read a tutorial about Settings API.
  2. The second method is much simpler, all you need to do is to copy and paste the ready code into your plugin or theme, but in this case you have to have my Simple Fields plugin installed on your website.

That’s what we are going to have by the end of this tutorial:

Tabs in WordPress settings pages
We added two text fields into the first tab and one field into the second one.

Below is the code which allows to create two tabs like on the screenshot above:

<?php
// add options page first
add_action( 'admin_menu', function(){
	add_options_page( 'Settings Page Test', 'Settings Test', 'manage_options', 'misha_test_page', 'misha_test_page_callback' );
} );

// displaying page HTML and print settings
function misha_test_page_callback(){
	?>
	<div class="wrap">
		<h1><?php echo get_admin_page_title() ?></h1>
		<?php
		$tabs = array(
			'tab1' => 'Tab 1',
			'tab2' => 'Tab 2',
		); 
		$current_tab = isset( $_GET[ 'tab' ] ) && isset( $tabs[ $_GET[ 'tab' ] ] ) ? $_GET[ 'tab' ] : array_key_first( $tabs );
		?>
		<form method="post" action="options.php">
			<nav class="nav-tab-wrapper">
				<?php
				foreach( $tabs as $tab => $name ){
					// CSS class for a current tab
					$current = $tab === $current_tab ? ' nav-tab-active' : '';
					// URL
					$url = add_query_arg( array( 'page' => 'misha_test_page', 'tab' => $tab ), '' );
					// printing the tab link
					echo "<a class=\"nav-tab{$current}\" href=\"{$url}\">{$name}</a>";
				}
				?>
			</nav>
			<?php
				settings_fields( "misha_test_page_{$current_tab}_settings" );
				do_settings_sections( "misha_test_page_{$current_tab}" );
				submit_button();
			?>
		</form>
	</div>
	<?php
}

// registering fields
add_action( 'admin_init', function(){

	// for the first tab
	$page_slug = 'misha_test_page_tab1';
	$option_group = 'misha_test_page_tab1_settings';

	// add section
	add_settings_section( 'misha_section_1', '', '', $page_slug );

	// register fields
	register_setting( $option_group, 'field1', 'sanitize_text_field' );
	register_setting( $option_group, 'field2', 'sanitize_text_field' );

	// add fields
	add_settings_field( 'field1', 'Field 1', 'misha_text_field', $page_slug, 'misha_section_1', array( 'name' => 'field1' ) );
	add_settings_field( 'field2', 'Field 2', 'misha_text_field', $page_slug, 'misha_section_1', array( 'name' => 'field2' ) );

	// for the second tab
	$page_slug = 'misha_test_page_tab2';
	$option_group = 'misha_test_page_tab2_settings';

	// add section
	add_settings_section( 'misha_section_2', '', '', $page_slug );

	// register fields
	register_setting( $option_group, 'field3', 'sanitize_text_field' );

	// add fields
	add_settings_field( 'field3', 'Field 3', 'misha_text_field', $page_slug, 'misha_section_2', array( 'name' => 'field3' ) );

} );

// custom callback function to print field HTML
function misha_text_field( $args ){
	printf(
		'<input type="text" id="%s" name="%s" value="%s" class="regular-text" />',
		$args[ 'name' ],
		$args[ 'name' ],
		get_option( $args[ 'name' ] )
	);
}

A little bit of code explanation:

My Simple Fields plugin since version 3.0 allows to create tabs in WordPress settings pages in a much more easier way.

add_filter( 'simple_register_option_pages', function( $option_pages ) {

	$option_pages[] = array(
		'id' => 'misha_test_page',
		'title' => 'Settings Page Test',
		'menu_name' => 'Settings Test',
		'parent_slug' => 'options-general.php',
		'tabs' => array(
			// Tab 1
			array(
				'name' => 'Tab 1',
				'fields' => array(
					array( 
						'id' => 'field1', 
						'label' => 'Field 1', 
						'type' => 'text',
					),
					array( 
						'id' => 'field2', 
						'label' => 'Field 2', 
						'type' => 'text',
					),
				),
			),
			// Tab 2
			array(
				'name' => 'Tab 2',
				'fields' => array(
					array( 
						'id' => 'field3', 
						'label' => 'Field 3', 
						'type' => 'text',
					),
			 	),
			)
		)
	);

	return $option_pages;

} );

And we have exactly the same result:

Tabs in WordPress settings pages
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