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:

Or:

So in this tutorial we’re going to create a simple WordPress settings page with a couple of tabs in two different ways:
- 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.
- 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:

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:
- If you don’t know where to insert it, please check this guide.
- One more time – there is a complete tutorial about options pages in WordPress on my site.
- The long story short, we’re just using different option groups for different tabs and displaying the options related to a currently active tab.
- Just in case, PHP function
array_key_first()
is only available since PHP 7.3.0.
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:


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