Advertisement

Using the Settings API - Part 2: Create A Top Level Admin Menu

by

This is Part Two of "Create Theme Settings Pages that use the Settings API" tutorial. In this part, we will be looking into how we can create a top level admin menu with more than one settings pages as well as how we can add tabs when we need them. If you have not yet had the chance to read Part One, you may want to do that first before you continue. This tutorial builds on the code shown in the first part of this tutorial.


A look at what we will be creating

Just like we did in Part One lets take a look at how the finished result looks like. We will be using the twentyeleven WordPress 3.2 default theme again however feel free to use your own theme if you prefer.

  1. Download the Source files and unzip
  2. Find the Part Two/source_files/lib folder and upload it inside the twentyeleven theme folder so that it is on the same level as the twentyeleven/js folder you see.
  3. Then, open the Part Two/source_files/functions.php in a code editor and copy the require_once code line.
  4. Next, open the twentyeleven/functions.php in your code editor.
    Find the twentyeleven_setup() function around line 74 and paste the line you copied earlier (point 3) inside the function as you see shown below.
    This will replace the previous require_once() line of code you added in Part One.
function twentyeleven_setup() {

	//require only in admin!
	if(is_admin()){	
		require_once('lib/wptuts-theme-settings-advanced.php');
	}

Upon completing this step you should be able to see the Wptuts Settings top-level menu in your Admin area. You will notice the two menu links: Options Page One and Options Page Two. Options Page One is exactly the same settings page you created in Part One so go directly to Options Page Two Following the Wptuts Settings Page Two title you see four tabs with their individual settings fields. To keep things simple and help you concentrate on the code required to create multiple pages and tabs you will notice that the settings are the same as those you see on Options Page One.

Now that you see what the finished result looks like, let's learn how we can re-create it step by step.


"The final code described in this step is found in the Part Two/source_ files/step1 folder"

Step 1 Registering the administration pages

This step is about creating a top level admin menu and registering two settings pages.

We will be using the same my-theme-settings.php document you were working with previously in Part One so go ahead and open that file in your code editor.

Register the top level menu

We will edit the existing wptuts_add_menu() function by adding a call to the add_menu_page(). We will add this right after we collect our contextual help like you see done below.


/*
 * The admin menu pages
 */
function wptuts_add_menu(){
	
	$settings_output 		= wptuts_get_settings();
	// collect our contextual help text
	$wptuts_contextual_help = $settings_output['wptuts_contextual_help'];
	
	// As a "top level" menu
	// add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position );
	add_menu_page( __('Wptuts Settings'), __('Wptuts Settings','wptuts_textdomain'), 'manage_options', WPTUTS_PAGE_BASENAME, 'wptuts_settings_page_fn');
	
	// old code follows below
}

Understand the add_menu_page() parameters

Take note of the add_menu_page() function parameters so you can later on customize the function call to your needs. The information is taken from the Codex page:

  • $page_title - The text to be displayed in the title tag of the page when the menu is selected
  • $menu_title - The text to be used for the menu
  • $capability - The capability required for this menu to be displayed to the user.
  • $menu_slug - The slug name to refer to this menu by (should be unique for this menu). (Note the use of our WPTUTS_PAGE_BASENAME constant!)
  • $function - The callback function to output the content for this page.
  • $icon_url - The url to the icon to be used for this menu. This parameter is optional. (We did not include this paramenter)
  • $position - The position in the menu order this menu should appear. (We did not include this paramenter)

Register the pages

Next, we will replace the existing add_theme_page() call with the add_submenu_page() function to register our first settings page. Then, we will register a second page as you see shown below.

/*
 * The admin menu pages
 */
function wptuts_add_menu(){
	
	$settings_output 		= wptuts_get_settings();
	// collect our contextual help text
	$wptuts_contextual_help = $settings_output['wptuts_contextual_help'];
	
	// As a "top level" menu
	// add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position );
	add_menu_page( __('Wptuts Settings'), __('Wptuts Settings','wptuts_textdomain'), 'manage_options', WPTUTS_PAGE_BASENAME, 'wptuts_settings_page_fn');
	
	// page one
	// add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function );
	$wptuts_settings_page = add_submenu_page(WPTUTS_PAGE_BASENAME, __('Wptuts Settings | Options'), __('Options Page One','wptuts_textdomain'), 'manage_options', WPTUTS_PAGE_BASENAME, 'wptuts_settings_page_fn');
		// contextual help
		if ($wptuts_settings_page) {
			add_contextual_help( $wptuts_settings_page, $wptuts_contextual_help );
		}
		// css & js
		add_action( 'load-'. $wptuts_settings_page, 'wptuts_settings_scripts' );
		
	// page two
	$wptuts_settings_page_two = add_submenu_page(WPTUTS_PAGE_BASENAME, __('Wptuts Settings | Options Page Two', 'wptuts_textdomain'), __('Options Page Two','wptuts_textdomain'), 'manage_options', WPTUTS_PAGE_BASENAME . '-page-two', 'wptuts_settings_page_fn');
		// contextual help
		if ($wptuts_settings_page_two) {
			add_contextual_help( $wptuts_settings_page_two, $wptuts_contextual_help );
		}
		// css & js
		add_action( 'load-'. $wptuts_settings_page_two, 'wptuts_settings_scripts' );
}

Note the variable names used for page two. When you customize this later you may want to use names that are more descriptive of the theme settings they contain. You can repeat the code we used for registering page two as many times as the number of settings pages you want to create. Take care to edit the page titles and variables accordingly. To help you in this, compare the code block for registering page one to the code block used for registering page two. Note which parameters change and which remain constant. Imitate this for any other pages you may want to create.

Understand the add_submenu_page() parameters

Take note of the add_submenu_page() function parameters so you can later on customize the function call to your needs. The information is taken from the Codex page:

  • $page_title - The text to be displayed in the title tag of the page when the menu is selected
  • $menu_title - The text to be used for the menu
  • $capability - The capability required for this menu to be displayed to the user.
  • $menu_slug - The slug name to refer to this menu by (should be unique for this menu). (Note the use of our WPTUTS_PAGE_BASENAME constant!)
  • $function - The callback function to output the content for this page.

Check the result

Do you still have a copy of my-theme-options.php file from Part One in your twentyeleven/lib folder? If you don't, upload the one (my-theme-options.php) you were working with during the first part of this tutorial or the one you find in Part One/source_files/step7 folder, before you open your WordPress admin in your browser.

If you have followed the above successfully, this is how your settings page should look like at this point.
Note that the page content will be the same for both pages. This is to be expected as we have not yet defined or registered the settings for the second page. This we will do in Steps 2 and 3.


Step 2 Defining the settings for each settings page

"The final code described in this step is found in the Part Two/source_ files/step2 folder"

Now that we have our settings pages in place we need to tell WordPress the settings, sections and fields we want to register and whitelist i.e. sanitize for each individual settings page. You may recall that the wptuts_register_settings() function (located in my-theme-settings.php) does exactly that for one settings page but how do we handle multiple pages?
And what if we want to display a page's settings in tabs?

The approach we will take is this:
Let WordPress know which page - and when using tabs, which tab - we are currently viewing and based on that register, display and save the settings needed for the current settings page.
Note that when saving the settings, we will save the settings only displayed on the page or tab we currently have open.

Especially those of you familiar with the excellent Incorporating the Settings API in WordPress Themes tutorial by Chip Bennett take extra note of this: The action of saving the settings will require that each page and tab saves it's settings under it's own unique option name (as used in a get_option() function call)! This need not necessarily be taken as a negative thing. It is simply a different approach; one that is required because we register, display and save only those settings under the current page or tab. Whether this is the best approach for you to take in a specific project can only be determined by the project at hand and the number of pages/tabs you need to create. So please, do keep an open mind as you read on.

The first thing we need is a couple of new helper functions. One function should be able to return the current settings page and another function the current tab. I've decided to keep these in a separate document so let's create that first.

Prepare a new Document with some helper functions

Create a new document in your code editor and call it wptuts-helper-functions.php. Copy and paste in it the three functions given below then, upload it inside the twentyeleven/lib folder. Each function is explained before the next is given.

The code given below should be written in the wptuts-helper-functions.php file.

/**
 * Helper function: Check for pages and return the current page name
 * 
 * @return string
 */
function wptuts_get_admin_page() {
	global $pagenow;
	
	// read the current page
	$current_page = trim($_GET['page']);
	
	// use a different way to read the current page name when the form submits
	if ($pagenow == 'options.php') {
		// get the page name
		$parts 	= explode('page=', $_POST['_wp_http_referer']); // http://codex.wordpress.org/Function_Reference/wp_referer_field
		$page  	= $parts[1]; 

		// account for the use of tabs (we do not want the tab name to be part of our return value!)
		$t 		= strpos($page,"&");
		
		if($t !== FALSE) {			 
			$page  = substr($parts[1],0,$t); 
		}
		
		$current_page = trim($page);
	}
	
return $current_page;

The first helper function will return the current page name. We depend on the $_GET superglobal.
The variable will return the page name we are currently viewing - e.g. wptuts-settings as shown in the ?page=wptuts-settings part of the page URL.

However, when we save the settings our $_GET variable will not be able to return the settings page name we expect (it will actually return a NULL value).

Why? Well, when we save our settings WordPress will send a POST request to options.php and at that moment we no longer have ?page=wptuts-settings as part of our page URL.
What now? WordPress includes the page name in the $_POST['_wp_http_referer'] variable.
Using the $pagenow WordPress global we can check when options.php is called and return the value stored in $_POST['_wp_http_referer']

/**
 * Helper function: Set default tab
 * 
 * @return string
 */
function wptuts_default_tab() {
	// find current page
	$current_page = wptuts_get_admin_page();
	
	// There may be times when the first tab has a different slug from page to page. Here is where you can override the $default_tab = 'general'; Gives you more control :)
	// if our current page is the 'wptuts-settings-page-two' page then set the default tab to 'text-inputs'
	if ($current_page == 'wptuts-settings-page-two') {
		$default_tab = 'text-inputs';
		
	// if you have more settings pages with a first tab slug other than "general" continue with an 
	//}elseif($current_page == 'your-page-slug'){ 
	//conditional here.
		
	// else fallback to the "general" tab.
	} else {
		$default_tab = 'general';
	}
return $default_tab;
}

This second helper function returns the default tab name. It it useful when your default tab slug is not always called general. To customize the function to your needs later, please take a moment to read through the comments left in the code.

/**
 * Helper function: Check for tabs and return the current tab name
 * 
 * @return string
 */
function wptuts_get_the_tab() {
	global $pagenow;
	
	// set default tab
	$default_tab 	= wptuts_default_tab();
	
	// read the current tab when on our settings page
	$current_tab 	= (isset($_GET['tab']) ? $_GET['tab'] : $default_tab);
	
	//use a different way to read the tab when the form submits
	if ($pagenow == 'options.php') {
		// need to read the tab name so we explode()!
		$parts 	= explode('&tab=', $_POST['_wp_http_referer']); // http://codex.wordpress.org/Function_Reference/wp_referer_field
		// count the "exploded" parts
		$partsNum = count($parts);
		
		// account for "&settings-updated=true" (we do not want that to be part of our return value!)
			// is it "&settings-updated=true" there? - check for the "&"
			$settings_updated = strpos($parts[1],"&");
			
			// filter it out and get the tab name
			$tab_name = ($settings_updated !== FALSE ? substr($parts[1],0,$settings_updated) : $parts[1]);
		
		// use if found, otherwise pass the default tab name
		$current_tab = ($partsNum == 2 ? trim($tab_name) : $default_tab);
	}
	
return $current_tab
}

The third helper function returns the current tab name.
Similar to what we did in the wptuts_get_admin_page() function we use the $_GET superglobal for reading the current tab name when the settings display and the $_POST['_wp_http_referer'] variable for reading the tab name when the settings save.

Remember to save the three functions shown above in the wptuts-helper-functions.php and upload it inside the twentyeleven/lib folder.

Define those settings

Time to define page tabs, settings sections and fields and contextual help for each settings page. We actually have the settings needed for "Options Page One" already from Part One of this tutorial. The sections, fields and contextual help fuctions are defined in my-theme-options.php and we will leave those as they are.
What we will do now is define settings for "Options Page Two".

The "Options Page Two" settings page will devide it's settings into tabs. Create a new document called my-theme-options-two.php then copy and paste in it the functions given below. Each function is explained after the code is given.

Define the page tabs

/**
 * Define page tabs
 * $tabs['tab-slug'] 	= __('Tab Name', 'wpShop');
 */
function wptuts_options_two_page_tabs() {
	
	$tabs = array();
	
	$tabs['text-inputs'] 	= __('Text Inputs', 'wpShop');	
	$tabs['textareas'] 		= __('Textareas', 'wpShop');	
	$tabs['select'] 		= __('Select', 'wpShop');	
	$tabs['checkboxes'] 	= __('Checkboxes', 'wpShop');
	
	return $tabs;
}

The tab array should have as value, the tab name as it will appear on each tab and as key, the tab slug as it will appear as part of the page URL as in &tab=tab-name

Define settings sections for each tab

/**
 * Define our settings sections
 *
 * array key=$id, array value=$title in: add_settings_section( $id, $title, $callback, $page );
 * @return array
 */
function wptuts_options_two_page_sections() {
	// we change the output based on open tab
	
	// get the current tab
	$tab = wptuts_get_the_tab();

	// switch sections array according to tab
	switch ($tab) {
		// Text Inputs
		case 'text-inputs':
			$sections = array();
			$sections['txt_section'] 		= __('Text Form Fields', 'wptuts_textdomain');
		break;
		
		// Textareas
        case 'textareas':
			$sections = array();
			$sections['txtarea_section'] 	= __('Textarea Form Fields', 'wptuts_textdomain');
		break;
		
		// Select
        case 'select':
			$sections = array();
			$sections['select_section'] 	= __('Select Form Fields', 'wptuts_textdomain');
		break;
		
		// Checkboxes
        case 'checkboxes':
			$sections = array();
			$sections['checkbox_section'] 	= __('Checkbox Form Fields', 'wptuts_textdomain');
		break;
	}
	
return $sections;	
}

The sections array is much the same as we defined it for "Options Page One" - my-theme-options.php - in that it returns an associative array where the value, is the section title and the key, the section id. However, the sections array output changes according to the current open tab. Note the tab switch.

// get the current tab
$tab = wptuts_get_the_tab();

// switch sections array according to tab
	switch ($tab) {
	// Text Inputs
	case 'text-inputs':
		
	break;
	
	// Textareas
	case 'textareas':
	
	break;
	
	// Select
	case 'select':
	
	break;
	
	// Checkboxes
	case 'checkboxes':
	
	break;
}

Each case is the tab slug - the array key from our wptuts_options_two_page_tabs() function. When you customize this function later you will need to create a new case for each tab you define.

The wptuts_get_the_tab() function you see called before the switch was defined in our wptuts-helper-functions.php. It helps us "read" the current tab name - the &tab=tab-name part of the page URL and passes that on to the $tab variable.

// get the current tab
$tab = wptuts_get_the_tab();

Define settings fields for each tab

/**
 * Define our form fields (options) 
 *
 * @return array
 */
function wptuts_options_two_page_fields() {
	
	// get the tab using wptuts_get_the_tab() for we need options.php to be able to process the form submission!
	$tab = wptuts_get_the_tab();
	
	// setting fields according to tab
	switch ($tab) {
		// Text Inputs
		case 'text-inputs':
			$options[] = array(
				"section" => "txt_section",
				"id"      => WPTUTS_SHORTNAME . "_txt_input_2",
				"title"   => __( 'Text Input - Some HTML OK!', 'wptuts_textdomain' ),
				"desc"    => __( 'A regular text input field. Some inline HTML (<a>, <b>, <em>, <i>, <strong>) is allowed.', 'wptuts_textdomain' ),
				"type"    => "text",
				"std"     => __('Some default value','wptuts_textdomain')
			);
			
			$options[] = array(
				"section" => "txt_section",
				"id"      => WPTUTS_SHORTNAME . "_nohtml_txt_input_2",
				"title"   => __( 'No HTML!', 'wptuts_textdomain' ),
				"desc"    => __( 'A text input field where no html input is allowed.', 'wptuts_textdomain' ),
				"type"    => "text",
				"std"     => __('Some default value','wptuts_textdomain'),
				"class"   => "nohtml"
			);
			
			$options[] = array(
				"section" => "txt_section",
				"id"      => WPTUTS_SHORTNAME . "_numeric_txt_input_2",
				"title"   => __( 'Numeric Input', 'wptuts_textdomain' ),
				"desc"    => __( 'A text input field where only numeric input is allowed.', 'wptuts_textdomain' ),
				"type"    => "text",
				"std"     => "123",
				"class"   => "numeric"
			);
			
			$options[] = array(
				"section" => "txt_section",
				"id"      => WPTUTS_SHORTNAME . "_multinumeric_txt_input_2",
				"title"   => __( 'Multinumeric Input', 'wptuts_textdomain' ),
				"desc"    => __( 'A text input field where only multible numeric input (i.e. comma separated numeric values) is allowed.', 'wptuts_textdomain' ),
				"type"    => "text",
				"std"     => "123,234,345",
				"class"   => "multinumeric"
			);
			
			$options[] = array(
				"section" => "txt_section",
				"id"      => WPTUTS_SHORTNAME . "_url_txt_input_2",
				"title"   => __( 'URL Input', 'wptuts_textdomain' ),
				"desc"    => __( 'A text input field which can be used for urls.', 'wptuts_textdomain' ),
				"type"    => "text",
				"std"     => "http://wp.tutsplus.com",
				"class"   => "url"
			);
			
			$options[] = array(
				"section" => "txt_section",
				"id"      => WPTUTS_SHORTNAME . "_email_txt_input_2",
				"title"   => __( 'Email Input', 'wptuts_textdomain' ),
				"desc"    => __( 'A text input field which can be used for email input.', 'wptuts_textdomain' ),
				"type"    => "text",
				"std"     => "email@email.com",
				"class"   => "email"
			);
			
			$options[] = array(
				"section" => "txt_section",
				"id"      => WPTUTS_SHORTNAME . "_multi_txt_input_2",
				"title"   => __( 'Multi-Text Inputs', 'wptuts_textdomain' ),
				"desc"    => __( 'A group of text input fields', 'wptuts_textdomain' ),
				"type"    => "multi-text",
				"choices" => array( __('Text input 1','wptuts_textdomain') . "|txt_input1", __('Text input 2','wptuts_textdomain') . "|txt_input2", __('Text input 3','wptuts_textdomain') . "|txt_input3", __('Text input 4','wptuts_textdomain') . "|txt_input4"),
				"std"     => ""
			);
		break;
		
		// Textareas
		case 'textareas':
			$options[] = array(
				"section" => "txtarea_section",
				"id"      => WPTUTS_SHORTNAME . "_txtarea_input_2",
				"title"   => __( 'Textarea - HTML OK!', 'wptuts_textdomain' ),
				"desc"    => __( 'A textarea for a block of text. HTML tags allowed!', 'wptuts_textdomain' ),
				"type"    => "textarea",
				"std"     => __('Some default value','wptuts_textdomain')
			);

			$options[] = array(
				"section" => "txtarea_section",
				"id"      => WPTUTS_SHORTNAME . "_nohtml_txtarea_input_2",
				"title"   => __( 'No HTML!', 'wptuts_textdomain' ),
				"desc"    => __( 'A textarea for a block of text. No HTML!', 'wptuts_textdomain' ),
				"type"    => "textarea",
				"std"     => __('Some default value','wptuts_textdomain'),
				"class"   => "nohtml"
			);
			
			$options[] = array(
				"section" => "txtarea_section",
				"id"      => WPTUTS_SHORTNAME . "_allowlinebreaks_txtarea_input_2",
				"title"   => __( 'No HTML! Line breaks OK!', 'wptuts_textdomain' ),
				"desc"    => __( 'No HTML! Line breaks allowed!', 'wptuts_textdomain' ),
				"type"    => "textarea",
				"std"     => __('Some default value','wptuts_textdomain'),
				"class"   => "allowlinebreaks"
			);

			$options[] = array(
				"section" => "txtarea_section",
				"id"      => WPTUTS_SHORTNAME . "_inlinehtml_txtarea_input_2",
				"title"   => __( 'Some inline HTML ONLY!', 'wptuts_textdomain' ),
				"desc"    => __( 'A textarea for a block of text. 
							Only some inline HTML 
							(<a>, <b>, <em>, <strong>, <abbr>, <acronym>, <blockquote>, <cite>, <code>, <del>, <q>, <strike>)  
							is allowed!', 'wptuts_textdomain' ),
				"type"    => "textarea",
				"std"     => __('Some default value','wptuts_textdomain'),
				"class"   => "inlinehtml"
			);
		break;
		
		// Select
		case 'select':
			$options[] = array(
				"section" => "select_section",
				"id"      => WPTUTS_SHORTNAME . "_select_input_2",
				"title"   => __( 'Select (type one)', 'wptuts_textdomain' ),
				"desc"    => __( 'A regular select form field', 'wptuts_textdomain' ),
				"type"    => "select",
				"std"    => "3",
				"choices" => array( "1", "2", "3")
			);
			
			$options[] = array(
				"section" => "select_section",
				"id"      => WPTUTS_SHORTNAME . "_select2_input_2",
				"title"   => __( 'Select (type two)', 'wptuts_textdomain' ),
				"desc"    => __( 'A select field with a label for the option and a corresponding value.', 'wptuts_textdomain' ),
				"type"    => "select2",
				"std"    => "",
				"choices" => array( __('Option 1','wptuts_textdomain') . "|opt1", __('Option 2','wptuts_textdomain') . "|opt2", __('Option 3','wptuts_textdomain') . "|opt3", __('Option 4','wptuts_textdomain') . "|opt4")
			);
		break;
		
		// Checkboxes
		case 'checkboxes':
			$options[] = array(
				"section" => "checkbox_section",
				"id"      => WPTUTS_SHORTNAME . "_checkbox_input_2",
				"title"   => __( 'Checkbox', 'wptuts_textdomain' ),
				"desc"    => __( 'Some Description', 'wptuts_textdomain' ),
				"type"    => "checkbox",
				"std"     => 1 // 0 for off
			);
			
			$options[] = array(
				"section" => "checkbox_section",
				"id"      => WPTUTS_SHORTNAME . "_multicheckbox_inputs_2",
				"title"   => __( 'Multi-Checkbox', 'wptuts_textdomain' ),
				"desc"    => __( 'Some Description', 'wptuts_textdomain' ),
				"type"    => "multi-checkbox",
				"std"     => 0,
				"choices" => array( __('Checkbox 1','wptuts_textdomain') . "|chckbx1", __('Checkbox 2','wptuts_textdomain') . "|chckbx2", __('Checkbox 3','wptuts_textdomain') . "|chckbx3", __('Checkbox 4','wptuts_textdomain') . "|chckbx4")	
			);
		break;
	}
	
	return $options;	
}

The fields array is much same as we defined it for "Options Page One". You will notice that I even left the $options[] = array() arguments the same with the option id the only exception (I simply added a _2) The important point to take home here is that the fields array output changes according to the current open tab like we did in our wptuts_options_two_page_sections() function. Note the tab switch.

// get the current tab
$tab = wptuts_get_the_tab();

// setting fields according to tab
	switch ($tab) {
	// Text Inputs
	case 'text-inputs':
		
	break;
	
	// Textareas
	case 'textareas':
	
	break;
	
	// Select
	case 'select':
	
	break;
	
	// Checkboxes
	case 'checkboxes':
	
	break;
}

Each case is the tab slug - the array keys from our wptuts_options_two_page_tabs() function. When you customize this function later you will need to create a new case for each tab you define.

Again, you see the wptuts_get_the_tab() function called before the switch. It helps us "read" the current tab name - the &tab=tab-name part of the page URL and passes that on to the $tab variable.

// get the current tab
$tab = wptuts_get_the_tab();

Define contextual help for each tab

Following the same pattern of switching the array output according to the current open tab, we define each tab's contextual help.

/**
 * Contextual Help
 */
function wptuts_options_two_page_contextual_help() {
	// get the current tab
	$tab = wptuts_get_the_tab();
	
	$text 	= "<h3>" . __('Wptuts Settings Page Two - Contextual Help','wptuts_textdomain') . "</h3>";
	
	// contextual help according to tab
	switch ($tab) {
		// Text Inputs
		case 'text-inputs':
			$text 	.= "<p>" . __('Contextual help for the "Text Input" settings fields goes here.','wptuts_textdomain') . "</p>";
		break;
		
		// Textareas
		case 'textareas':
			$text 	.= "<p>" . __('Contextual help for the "Textarea" settings fields goes here.','wptuts_textdomain') . "</p>";
		break;
		
		// Select
		case 'select':
			$text 	.= "<p>" . __('Contextual help for the "Select" settings fields goes here.','wptuts_textdomain') . "</p>";
		break;
		
		// Checkboxes
		case 'checkboxes':
			$text 	.= "<p>" . __('Contextual help for the "Checkboxes" settings fields goes here.','wptuts_textdomain') . "</p>";
		break;
	}
	
	// must return text! NOT echo
	return $text;
}

All the settings code given above should be now written in your my-theme-options-two.php file. Save it and upload it inside the twentyeleven/lib folder


Step 3 Registering the tabs and settings for each settings page

"The final code described in this step is found in the Part Two/source_ files/step3 folder"

Now that our page settings are all nicely defined, let's tell WordPress to display them.

Include the new Documents we created in Step 2

We want to use our new helper functions and settings in our my-theme-settings.php file so let's include the new wptuts-helper-functions.php and my-theme-options-two.php files. Find the existing require_once('my-theme-options.php'); code line and adjust as you see below.

The code given below should be written in the my-theme-settings.php file.

/**
 * Include the required files
 */
// helper functions
require_once('wptuts-helper-functions.php');
// page settings sections & fields as well as the contextual help text.
require_once('wptuts-theme-options.php');
require_once('wptuts-theme-options-two.php');

Adjust the wptuts_get_settings() function

Time to adjust the existing wptuts_get_settings() helper function to retrieve our settings based on the page or tab we currently have open.

/**
 * Helper function for defining variables for the current page
 *
 * @return array
 */
function wptuts_get_settings() {
	
	$output = array();
	
	/*PAGES*/
	// get current page
	$page = wptuts_get_admin_page();
	
	/*TABS*/
	// get current tab
	$tab = wptuts_get_the_tab();
	
	/*DEFINE VARS*/
	// define variables according to registered admin menu page
	switch ($page) {
		case WPTUTS_PAGE_BASENAME:
			$wptuts_option_name 		= 'wptuts_options';
			$wptuts_settings_page_title = __( 'Wptuts Settings Page','wptuts_textdomain');	
			$wptuts_page_sections 		= wptuts_options_page_sections();
			$wptuts_page_fields 		= wptuts_options_page_fields();
			$wptuts_contextual_help 	= wptuts_options_page_contextual_help();
			$wptuts_page_tabs			= '';
		break;
	
		case WPTUTS_PAGE_BASENAME . '-page-two':
			$wptuts_option_name 		= 'wptuts_options_two';
			$wptuts_settings_page_title = __( 'Wptuts Settings Page Two','wptuts_textdomain');
			$wptuts_page_sections 		= wptuts_options_two_page_sections();
			$wptuts_page_fields 		= wptuts_options_two_page_fields();
			$wptuts_contextual_help 	= wptuts_options_two_page_contextual_help();
			$wptuts_page_tabs 			= wptuts_options_two_page_tabs();
			
			// define a new option name according to tab
			switch ($tab) {
				// Text Inputs
				case 'text-inputs':
					$wptuts_option_name = $wptuts_option_name . '_text_inputs';
				break;
				
				// Textareas
				case 'textareas':
					$wptuts_option_name = $wptuts_option_name . '_textareas';
				break;
				
				// Select
				case 'select':
					$wptuts_option_name = $wptuts_option_name . '_select';
				break;
				
				// Checkboxes
				case 'checkboxes':
					$wptuts_option_name = $wptuts_option_name . '_checkboxes';
				break;
			}
		break;
	}
	
	// put together the output array 
	$output['wptuts_option_name'] 		= $wptuts_option_name;
	$output['wptuts_page_title'] 		= $wptuts_settings_page_title;
	$output['wptuts_page_tabs']			= $wptuts_page_tabs;
	$output['wptuts_page_sections'] 	= $wptuts_page_sections;
	$output['wptuts_page_fields'] 		= $wptuts_page_fields;
	$output['wptuts_contextual_help'] 	= $wptuts_contextual_help;
	
	
return $output;
}

Breaking-down the code

We fill our $output array with the option name, page title, page tabs, settings sections, settings fields and contextual help. The values of the six array keys change based on the settings page or tab we currently have open.

First we have a page switch

switch ($page) {
	case WPTUTS_PAGE_BASENAME:
		
	break;

	case WPTUTS_PAGE_BASENAME . '-page-two':
		
	break;
}

You will need to create a new case for each settings page you register in the wptuts_add_menu() function. (Note that the case must match the $menu_slug parameter in the add_submenu_page() function call.)

Each case defines the option name and page title with the appropriate string value. The page tabs, settings sections, settings fields and contextual help variables are defined by calling the appropriate functions that give the corresponding output. (You recall that the functions are defined in a separate document - my-theme-options.php for "Options Page One" and my-theme-options-two.php for "Options Page Two".)

Should a particular settings page not need any tabs then the $wptuts_page_tabs variable is left empty. This is done for example for "Options Page One"

case WPTUTS_PAGE_BASENAME:
	$wptuts_option_name 		= 'wptuts_options';
	$wptuts_settings_page_title = __( 'Wptuts Settings Page','wptuts_textdomain');	
	$wptuts_page_sections 		= wptuts_options_page_sections();
	$wptuts_page_fields 		= wptuts_options_page_fields();
	$wptuts_contextual_help 	= wptuts_options_page_contextual_help();
	$wptuts_page_tabs			= '';
break;

Finally we have a tab switch

// define a new option name according to tab
switch ($tab) {
	// Text Inputs
	case 'text-inputs':
		$wptuts_option_name = $wptuts_option_name . '_text_inputs';
	break;
	
	// Textareas
	case 'textareas':
		$wptuts_option_name = $wptuts_option_name . '_textareas';
	break;
	
	// Select
	case 'select':
		$wptuts_option_name = $wptuts_option_name . '_select';
	break;
	
	// Checkboxes
	case 'checkboxes':
		$wptuts_option_name = $wptuts_option_name . '_checkboxes';
	break;
}

This is only needed on settings pages that we want to use tabs. You will need to create a new case for each tab you register. (Note that the case must match the tab-slug in your tab array key.) Each case defines a new option name with the appropriate string value.

Adjust the page content output function

Finally for this step, we need to make a little adjustment to our wptuts_settings_page_fn()() function so that it displays our tabs when these are defined. Replace the existing function with the following:

/*
 * Admin Settings Page HTML
 * 
 * @return echoes output
 */
function wptuts_settings_page_fn() {
	// get the settings sections array
	$settings_output = wptuts_get_settings();
?>
	<div class="wrap">
		<?php 
		// dislays the page title and tabs (if needed)
		wptuts_settings_page_header(); 
		?>
		
		<form action="options.php" method="post">
			<?php 
			// http://codex.wordpress.org/Function_Reference/settings_fields
			settings_fields($settings_output['wptuts_option_name']); 
			// http://codex.wordpress.org/Function_Reference/do_settings_sections
			do_settings_sections(__FILE__); 
			?>
			
			<p class="submit">
				<input name="Submit" type="submit" class="button-primary" value="<?php esc_attr_e('Save Changes','wptuts_textdomain'); ?>" />
			</p>
			
		</form>
	&lt;/div><!-- wrap -->
&lt;?php }

We call a new function called wptuts_settings_page_header(). Let's go ahead and define this in our wptuts-helper-functions.php file. Copy and paste the following after the wptuts_get_the_tab() function.

/**
 * Helper function: Creates settings page title and tabs (if needed)
 *
 * @return echos output
 */
function wptuts_settings_page_header() {
	
    // get the tabs
    $settings_output 	= wptuts_get_settings();
	$tabs 				= $settings_output['wptuts_page_tabs'];
	
	// get the current tab
	$current_tab 		= wptuts_get_the_tab();
	
	// display the icon and page title
	echo '&lt;div id="icon-options-general" class="icon32">&lt;br />&lt;/div>';
	echo '&lt;h2>' . $settings_output['wptuts_page_title'] . '&lt;/h2>';
    
	// check for tabs
	if ($tabs !='') {
		// wrap each in anchor html tags
		$links = array();
		foreach( $tabs as $tab => $name ) {
			// set anchor class
			$class 		= ($tab == $current_tab ? 'nav-tab nav-tab-active' : 'nav-tab');
			$page 		= $_GET['page'];
			// the link
			$links[] 	= "&lt;a class='$class' href='?page=$page&tab=$tab'>$name&lt;/a>";
		}
		
		echo '&lt;h3 class="nav-tab-wrapper">';
			foreach ( $links as $link ) {
				echo $link;
			}
		echo '&lt;/h3>';
	}  
}

Breaking-down the code

We collect our tabs by calling the wptuts_get_settings() helper function.

// get the tabs
$settings_output 	= wptuts_get_settings();
$tabs 				= $settings_output['wptuts_page_tabs'];

Then, we get the current tab with the wptuts_get_the_tab() helper function.

// get the current tab
$current_tab 		= wptuts_get_the_tab();

We echo the icon and page title.

// display the icon and page title
echo '&lt;div id="icon-options-general" class="icon32">&lt;br />&lt;/div>';
echo '&lt;h2>' . $settings_output['wptuts_page_title'] . '&lt;/h2>';

If we have tabs defined, we display them too.

// check for tabs
if ($tabs !='') {
	// wrap each in anchor html tags
	$links = array();
	foreach( $tabs as $tab => $name ) {
		// set anchor class
		$class 		= ($tab == $current_tab ? 'nav-tab nav-tab-active' : 'nav-tab');
		$page 		= $_GET['page'];
		// the link
		$links[] 	= "&lt;a class='$class' href='?page=$page&tab=$tab'>$name&lt;/a>";
	}
	
	echo '&lt;h3 class="nav-tab-wrapper">';
		foreach ( $links as $link ) {
			echo $link;
		}
	echo '&lt;/h3>';
}

The tab code should be familiar to those of you who went through the
Incorporating the Settings API in WordPress Themes tutorial by Chip Bennett

Check the result

If you have followed the above successfully, your "Options Page Two" should display it's tabs like you see below.


Collecting the theme options together for use in our theme

The last thing we need to do before we conclude Part Two of this tutorial is to collect together the theme options we saved for each settings page and tab in our $wptuts_option variable. To do this we need to adjust the wptuts_get_global_options() function we wrote in twentyeleven/functions.php in Part One

/**
 * Collects our theme options
 *
 * @return array
 */
function wptuts_get_global_options(){
	
	$wptuts_option = array();

	// collect option names as declared in wptuts_get_settings()
	$wptuts_option_names = array (
		'wptuts_options', 
		'wptuts_options_two_text_inputs', 
		'wptuts_options_two_textareas', 
		'wptuts_options_two_select', 
		'wptuts_options_two_checkboxes'	
	);

	// loop for get_option
	foreach ($wptuts_option_names as $wptuts_option_name) {
		if (get_option($wptuts_option_name)!= FALSE) {
			$option 	= get_option($wptuts_option_name);
			
			// now merge in main $wptuts_option array!
			$wptuts_option = array_merge($wptuts_option, $option);
		}
	}	
	
return $wptuts_option;
}

Breaking-down the code

We take each option name we defined per page and tab.

.

// collect option names as declared in wptuts_get_settings()
$wptuts_option_names = array (
	'wptuts_options', 
	'wptuts_options_two_text_inputs', 
	'wptuts_options_two_textareas', 
	'wptuts_options_two_select', 
	'wptuts_options_two_checkboxes'	
);

We then call the get_option() function for each and merge them in one big array which we then output

.

// loop for get_option
	foreach ($wptuts_option_names as $wptuts_option_name) {
		if (get_option($wptuts_option_name)!= FALSE) {
			$option 	= get_option($wptuts_option_name);
			
			// now merge in main $wptuts_option array!
			$wptuts_option = array_merge($wptuts_option, $option);
		}
	}

As mentioned in Part One, echo a particular option in any of your theme templates like this: &lt;?php echo $wptuts_option['wptuts_txt_input']; ?> - the value in the brackets is the id of the option you want to display.

This concludes Part Two of our tutorial. Hope you enjoyed reading it!