# Using The Settings API: Part 1 - Create A Theme Options Page

If you create your own themes you will, sooner or later, want to allow your theme users have some control over certain appearance and/or functional elements of your theme. When this time comes you will want to use the powerful WordPress Settings API. With it, your code becomes simpler, more efficient and more secure.

## Introduction

This tutorial is not the first to be written on using the Settings API to create a theme or plugin settings page. In fact a good number of tutorials are available in the WordPress community already. Some quality tutorials include the Extended WordPress Settings API Tutorial (in two parts) by Alison Barrett as well as the well known Incorporating the Settings API in WordPress Themes by Chip Bennett.

This tutorial builds on some excellent code techniques found in those tutorials (credit goes to both!) so if you are not familiar with them I would definitely recommend that you read those two articles too. I hope that you may find some code in this tutorial that you can use and improve on in your own work. Right then! Let's get straight to it!

## A Look at What We Will Be Creating

I think it's always nice when tutorials start by showing how the finished result looks like. So why don't we start with that, shall we? For the purpose of this tutorial we will be using the twentyeleven WordPress 3.2 default theme however feel free to use your own theme if you prefer.

2. Find the Part One/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 One/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.
 1 2 function twentyeleven_setup() {  3 4  //require only in admin!  5  if(is_admin()){  6  require_once('lib/wptuts-theme-settings-basic.php');  7  } 

Upon completing this step you should be able to see the Wptuts Options link under WordPress' Appearance top-level menu of your Admin area. Go to it and take a moment to scan through the page contents. Following the Wptuts Settings Page title are four settings sections with their individual settings fields:

• Text Form Fields
• Text Area Form Fields
• Select Form Fields
• Check Box Form Fields

Note how certain settings allow HTML tags whereas other settings do not. Some settings are dedicated to numeric input only. Try saving the default settings and see the "Settings saved." admin message appear. Try saving input with HTML tags on settings that do not allow their use and see how they are cleared away. Now go to the Email Input setting and save a wrong email format like email@email. Save the setting and see the admin error message display. See also how the setting that needs to be corrected is highlighted red so that we know exactly where to go and correct things.

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

## Step 1 Registering the Administration Page

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

This step is about creating an empty page that will eventually display our settings. As Part One of this tutorial requires only a single settings page we will simply add a submenu to the existing Appearance top level menu. (Part Two will show how to add tabs as well as more than one settings page.) We will call the add_theme_page() function within our own wptuts_add_menu()function and hook that to the admin_menu action hook.

### Prepare the Document

Create a new document in your code editor and call it my-theme-settings.php Save it and upload it inside the twentyeleven/lib folder. Open the twentyeleven/functions.php in your code editor and find the require_once code line you pasted in earlier and edit the file name to reflect the name of the new document you just created.

The code given below should be written in the twentyeleven/functions.php file.

 1 2 function twentyeleven_setup() {  3 4  //require only in admin!  5  if(is_admin()){  6  require_once('lib/my-theme-settings.php');  7  } 

### Define Our Constants

First we define some constants. This will make it a little easier when you want to customize the code to your needs later on.

All the code given below and for the remaining part of Step 1 should be written in the my-theme-settings.php file.

 1 2 /*  3  * Define Constants  4  */  5 define('WPTUTS_SHORTNAME', 'wptuts'); // used to prefix the individual setting field id see wptuts_options_page_fields()  6 define('WPTUTS_PAGE_BASENAME', 'wptuts-settings'); // the settings page slug 

### Register the Page

Next, tell WordPress that we want to register a settings page. For this, we need to write a function and hook it on the admin_menu action hook.

 1 2 /*  3  * Specify Hooks/Filters  4  */  5 add_action( 'admin_menu', 'wptuts_add_menu' );  6 7 /*  8  * The Admin menu page  9  */  10 function wptuts_add_menu(){  11   12  // Display Settings Page link under the "Appearance" Admin Menu  13  // add_theme_page( $page_title,$menu_title, $capability,$menu_slug, $function);  14 $wptuts_settings_page = add_theme_page(__('Wptuts Options'), __('Wptuts Options','wptuts_textdomain'), 'manage_options', WPTUTS_PAGE_BASENAME, 'wptuts_settings_page_fn');  15 } 

Understand the add_theme_page() parameters

Take note of the add_theme_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 tags 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. (The wptuts_settings_page_fn() described further down.) ### Define a Helper Function and the Page Content Output Function The fifth parameter in add_theme_page() - i.e. wptuts_settings_page_fn() function - is responsible for displaying our page content. However, before we write it we need to define a helper function that will help bring the final page output (page title, settings sections, settings fields and contextual help) for us together. Copy and paste the code you see below after the call to the admin_menu action hook. The helper function  1 2  /**  3  * Helper function for defining variables for the current page  4  *  5  * @return array  6  */  7 function wptuts_get_settings() {  8   9 $output = array();  10   11  // put together the output array  12  $output['wptuts_option_name'] = ''; // the option name as used in the get_option() call.  13 $output['wptuts_page_title'] = __( 'Wptuts Settings Page','wptuts_textdomain'); // the settings page title  14  $output['wptuts_page_sections'] = ''; // the setting section  15 $output['wptuts_page_fields'] = ''; // the setting fields  16  $output['wptuts_contextual_help'] = ''; // the contextual help  17   18 return$output;  19 } 

The wptuts_get_settings() helper function outputs an associative array with the following values (in the order they are written):

• The option name as we will use it in the get_option() call. (see Step 2)
• The settings page title. (see below)
• The settings sections. (see Step 3)
• The settings fields (settings). (see Step 4)
• The settings contextual help. (see Step 7)

The page content output function

Copy and paste the code you see below after the wptuts_get_settings() function.

 1 2 /*  3  * Admin Settings Page HTML  4  *  5  * @return echoes output  6  */  7 function wptuts_settings_page_fn() {  8 // get the settings sections array  9  $settings_output = wptuts_get_settings();  10 ?>  11   12   13   14   15   16   17   18   19   20   21   22  ### Check the Result If you have followed the above successfully, this is how your settings page should look like at this point. ## Step 2 Registering Page Settings "The final code described in this step is found in the Part One/source_ files/step2 folder" Now that we have our settings page in place we need to tell WordPress the settings we want to register and whitelist i.e. sanitize for it. This step is just about that. It will not change the appearance of our page so don't expect to actually "see" any changes reflected. All this vital work is done in the background. We will use the register_setting() function and it's sanitation callback within our custom wptuts_register_settings() function and then hook this on the admin_init action hook. Before we do this however, we need to adjust our helper wptuts_get_settings() function to include a value for $output['wptuts_option_name'].

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

### Check the Result

If you have followed the above successfully, your settings page should still look the same as it did at the end of Step 1!

## Step 3 Defining & Registering Settings Sections

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

This step covers the four settings sections we will need. Part of the code we'll cover will need to be written in a separate file which we will include in our my-theme-settings.php so let's start with that.

### Prepare a New Document

Create a new document in your code editor and call it my-theme-options.php Copy and paste in it the function you see below. Then save the document and upload it inside the twentyeleven/lib folder.

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

• $page - The settings page on which to show the section. ### Define the Sections Callback Function and Adjust the Page Content Output Function The settings sections callback function - i.e. wptuts_section_fn() - will echo it's contents for each section we created.  1 2 /*  3  * Section HTML, displayed before the first option  4  * @return echoes output  5  */  6 function wptuts_section_fn($desc) {  7  echo "

" . __('Settings for this section','wptuts_textdomain') . "

";  8 } 

Finally, we tell WordPress that we want the sections to display on our settings page. We do this by calling the 2 functions: settings_fields() and do_settings_sections() in our wptuts_settings_page_fn()

 1 2 /*  3  * Admin Settings Page HTML  4  *  5  * @return echoes output  6  */  7 function wptuts_settings_page_fn() {  8 // get the settings sections array  9  $settings_output = wptuts_get_settings();  10 ?>  11   12   13   14   15   16   23   24   25   26   27   28   29  ### Check the Result If you have followed the above successfully, this is how your settings page should look like at this point. ## Step 4 Defining & Registering Setting Fields "The final code described in this step is found in the Part One/source_ files/step4/ my-theme-settings.php folder" This step is all about the actual settings or as they are called in the Settings API, the settings fields. We start by defining a new helper function. ### Define a New Helper Function The function (written by Alison Barrett) is explained in her own tutorial so I would encourage you to read that at some point. Please take note of the fact that our wptuts_create_settings_field() function will pass the $class argument to our validation function so it is not there simply for stylistic use in a css file!

The code given below should be written in the my-theme-settings.php file just after the wptuts_get_settings() function.

 1 2 /**  3  * Helper function for registering our form field settings  4  *  5  * src: http://alisothegeek.com/2011/01/wordpress-settings-api-tutorial-1/  6  * @param (array) $args The array of arguments to be used in creating the field  7  * @return function call  8  */  9 function wptuts_create_settings_field($args = array() ) {  10  // default array to overwrite when calling the function  11  $defaults = array(  12  'id' => 'default_field', // the ID of the setting in our options array, and the ID of the HTML form element  13  'title' => 'Default Field', // the label for the HTML form element  14  'desc' => 'This is a default description.', // the description displayed under the HTML form element  15  'std' => '', // the default value for this setting  16  'type' => 'text', // the HTML form element to use  17  'section' => 'main_section', // the section this setting belongs to — must match the array key of a section in wptuts_options_page_sections()  18  'choices' => array(), // (optional): the values in radio buttons or a drop-down menu  19  'class' => '' // the HTML form element class. Also used for validation purposes!  20  );  21   22  // "extract" to be able to use the array keys as variables in our function output below  23  extract( wp_parse_args($args, $defaults ) );  24   25  // additional arguments for use in form field output in the function wptuts_form_field_fn!  26 $field_args = array(  27  'type' => $type,  28  'id' =>$id,  29  'desc' => $desc,  30  'std' =>$std,  31  'choices' => $choices,  32  'label_for' =>$id,  33  'class' => $class  34  );  35 36  add_settings_field($id, $title, 'wptuts_form_field_fn', __FILE__,$section, $field_args );  37 38 }  Understand the add_settings_field() parameters Take note of the add_settings_field() function parameters. The information is taken from the Codex page: • $id - String for use in the 'id' attribute of tags.
• $title - Title of the field. • $callback - The name of the callback function that will echo the form field.
• $page - The settings page on which to show the field • $section - The section of the settings page in which to show the field
• $args - Additional arguments to pass to our callback function. (These are what we mainly work with when we define our wptuts_options_page_fields() function further down) ### Define the Settings Fields The code given below should be written in the my-theme-options.php file just after the wptuts_options_page_sections() function.  1 2 /**  3  * Define our form fields (settings)  4  *  5  * @return array  6  */  7 function wptuts_options_page_fields() {  8  // Text Form Fields section  9 $options[] = array(  10  "section" => "txt_section",  11  "id" => WPTUTS_SHORTNAME . "_txt_input",  12  "title" => __( 'Text Input - Some HTML OK!', 'wptuts_textdomain' ),  13  "desc" => __( 'A regular text input field. Some inline HTML (, , , , ) is allowed.', 'wptuts_textdomain' ),  14  "type" => "text",  15  "std" => __('Some default value','wptuts_textdomain')  16  );  17   18  $options[] = array(  19  "section" => "txt_section",  20  "id" => WPTUTS_SHORTNAME . "_nohtml_txt_input",  21  "title" => __( 'No HTML!', 'wptuts_textdomain' ),  22  "desc" => __( 'A text input field where no html input is allowed.', 'wptuts_textdomain' ),  23  "type" => "text",  24  "std" => __('Some default value','wptuts_textdomain'),  25  "class" => "nohtml"  26  );  27   28 $options[] = array(  29  "section" => "txt_section",  30  "id" => WPTUTS_SHORTNAME . "_numeric_txt_input",  31  "title" => __( 'Numeric Input', 'wptuts_textdomain' ),  32  "desc" => __( 'A text input field where only numeric input is allowed.', 'wptuts_textdomain' ),  33  "type" => "text",  34  "std" => "123",  35  "class" => "numeric"  36  );  37   38  $options[] = array(  39  "section" => "txt_section",  40  "id" => WPTUTS_SHORTNAME . "_multinumeric_txt_input",  41  "title" => __( 'Multinumeric Input', 'wptuts_textdomain' ),  42  "desc" => __( 'A text input field where only multible numeric input (i.e. comma separated numeric values) is allowed.', 'wptuts_textdomain' ),  43  "type" => "text",  44  "std" => "123,234,345",  45  "class" => "multinumeric"  46  );  47   48 $options[] = array(  49  "section" => "txt_section",  50  "id" => WPTUTS_SHORTNAME . "_url_txt_input",  51  "title" => __( 'URL Input', 'wptuts_textdomain' ),  52  "desc" => __( 'A text input field which can be used for urls.', 'wptuts_textdomain' ),  53  "type" => "text",  54  "std" => "https://code.tutsplus.com",  55  "class" => "url"  56  );  57   58  $options[] = array(  59  "section" => "txt_section",  60  "id" => WPTUTS_SHORTNAME . "_email_txt_input",  61  "title" => __( 'Email Input', 'wptuts_textdomain' ),  62  "desc" => __( 'A text input field which can be used for email input.', 'wptuts_textdomain' ),  63  "type" => "text",  64  "std" => "email@email.com",  65  "class" => "email"  66  );  67   68 $options[] = array(  69  "section" => "txt_section",  70  "id" => WPTUTS_SHORTNAME . "_multi_txt_input",  71  "title" => __( 'Multi-Text Inputs', 'wptuts_textdomain' ),  72  "desc" => __( 'A group of text input fields', 'wptuts_textdomain' ),  73  "type" => "multi-text",  74  "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"),  75  "std" => ""  76  );  77   78  // Textarea Form Fields section  79  $options[] = array(  80  "section" => "txtarea_section",  81  "id" => WPTUTS_SHORTNAME . "_txtarea_input",  82  "title" => __( 'Textarea - HTML OK!', 'wptuts_textdomain' ),  83  "desc" => __( 'A textarea for a block of text. HTML tags allowed!', 'wptuts_textdomain' ),  84  "type" => "textarea",  85  "std" => __('Some default value','wptuts_textdomain')  86  );  87 88 $options[] = array(  89  "section" => "txtarea_section",  90  "id" => WPTUTS_SHORTNAME . "_nohtml_txtarea_input",  91  "title" => __( 'No HTML!', 'wptuts_textdomain' ),  92  "desc" => __( 'A textarea for a block of text. No HTML!', 'wptuts_textdomain' ),  93  "type" => "textarea",  94  "std" => __('Some default value','wptuts_textdomain'),  95  "class" => "nohtml"  96  );  97   98  $options[] = array(  99  "section" => "txtarea_section",  100  "id" => WPTUTS_SHORTNAME . "_allowlinebreaks_txtarea_input",  101  "title" => __( 'No HTML! Line breaks OK!', 'wptuts_textdomain' ),  102  "desc" => __( 'No HTML! Line breaks allowed!', 'wptuts_textdomain' ),  103  "type" => "textarea",  104  "std" => __('Some default value','wptuts_textdomain'),  105  "class" => "allowlinebreaks"  106  );  107 108 $options[] = array(  109  "section" => "txtarea_section",  110  "id" => WPTUTS_SHORTNAME . "_inlinehtml_txtarea_input",  111  "title" => __( 'Some Inline HTML ONLY!', 'wptuts_textdomain' ),  112  "desc" => __( 'A textarea for a block of text.  113  Only some inline HTML  114  (, , , , , ,
, , , , , )  115  is allowed!', 'wptuts_textdomain' ),  116  "type" => "textarea",  117  "std" => __('Some default value','wptuts_textdomain'),  118  "class" => "inlinehtml"  119  );  120   121  // Select Form Fields section  122  $options[] = array(  123  "section" => "select_section",  124  "id" => WPTUTS_SHORTNAME . "_select_input",  125  "title" => __( 'Select (type one)', 'wptuts_textdomain' ),  126  "desc" => __( 'A regular select form field', 'wptuts_textdomain' ),  127  "type" => "select",  128  "std" => "3",  129  "choices" => array( "1", "2", "3")  130  );  131   132 $options[] = array(  133  "section" => "select_section",  134  "id" => WPTUTS_SHORTNAME . "_select2_input",  135  "title" => __( 'Select (type two)', 'wptuts_textdomain' ),  136  "desc" => __( 'A select field with a label for the option and a corresponding value.', 'wptuts_textdomain' ),  137  "type" => "select2",  138  "std" => "",  139  "choices" => array( __('Option 1','wptuts_textdomain') . "|opt1", __('Option 2','wptuts_textdomain') . "|opt2", __('Option 3','wptuts_textdomain') . "|opt3", __('Option 4','wptuts_textdomain') . "|opt4")  140  );  141   142  // Checkbox Form Fields section  143  $options[] = array(  144  "section" => "checkbox_section",  145  "id" => WPTUTS_SHORTNAME . "_checkbox_input",  146  "title" => __( 'Checkbox', 'wptuts_textdomain' ),  147  "desc" => __( 'Some Description', 'wptuts_textdomain' ),  148  "type" => "checkbox",  149  "std" => 1 // 0 for off  150  );  151   152 $options[] = array(  153  "section" => "checkbox_section",  154  "id" => WPTUTS_SHORTNAME . "_multicheckbox_inputs",  155  "title" => __( 'Multi-Checkbox', 'wptuts_textdomain' ),  156  "desc" => __( 'Some Description', 'wptuts_textdomain' ),  157  "type" => "multi-checkbox",  158  "std" => '',  159  "choices" => array( __('Checkbox 1','wptuts_textdomain') . "|chckbx1", __('Checkbox 2','wptuts_textdomain') . "|chckbx2", __('Checkbox 3','wptuts_textdomain') . "|chckbx3", __('Checkbox 4','wptuts_textdomain') . "|chckbx4")  160  );  161   162  return $options;  163 }  Note how the arguments are used for each setting type whether it is a text input field, a textarea, a select drop down or a checkbox setting. Note the section argument and how it matches the $sections array key we output in our wptuts_options_page_sections() function. See that the class argument is regularly used for both our text and textarea settings types (this will be used in the wptuts_validate_options() function later.)

Next, we adjust the wptuts_get_settings() helper function to include a value for the $output['wptuts_page_fields'] variable. The code given below and for the remaining part of Step 4 should be written in the my-theme-settings.php file.  1 2  /**  3  * Helper function for defining variables for the current page  4  *  5  * @return array  6  */  7 function wptuts_get_settings() {  8   9 $output = array();  10   11  // put together the output array  12  $output['wptuts_option_name'] = 'wptuts_options';  13 $output['wptuts_page_title'] = __( 'Wptuts Settings Page','wptuts_textdomain');  14  $output['wptuts_page_sections'] = wptuts_options_page_sections();  15 $output['wptuts_page_fields'] = wptuts_options_page_fields();  16  $output['wptuts_contextual_help'] = '';  17   18 return$output;  19 } 

### Register the Settings Fields

Let's register our settings fields by calling the wptuts_create_settings_field() helper function which ultimately calls the add_settings_field() function. Remember that just like the settings sections, the settings fields we defined are stored as an array so we need to run a foreach loop.

 1 2 /*  3  * Register our setting  4  */  5 function wptuts_register_settings(){  6   7  // get the settings sections array  8  $settings_output = wptuts_get_settings();  9 $wptuts_option_name = $settings_output['wptuts_option_name'];  10   11  //setting  12  // register_setting($option_group, $option_name,$sanitize_callback );  13  register_setting($wptuts_option_name,$wptuts_option_name, 'wptuts_validate_options' );  14   15  //sections  16  // add_settings_section( $id,$title, $callback,$page );  17  if(!empty($settings_output['wptuts_page_sections'])){  18  // call the "add_settings_section" for each!  19  foreach ($settings_output['wptuts_page_sections'] as $id =>$title ) {  20  add_settings_section( $id,$title, 'wptuts_section_fn', __FILE__);  21  }  22  }  23   24  //fields  25  if(!empty($settings_output['wptuts_page_fields'])){  26  // call the "add_settings_field" for each!  27  foreach ($settings_output['wptuts_page_fields'] as $option) {  28  wptuts_create_settings_field($option);  29  }  30  }  31 } 

### Define the Setting Fields Callback Function

Finally we define the wptuts_form_field_fn() callback function that will handle the form field display. Copy and paste the following code just after the wptuts_section_fn() function.

 1 2 /*  3  * Form Fields HTML  4  * All form field types share the same function!!  5  * @return echoes output  6  */  7 function wptuts_form_field_fn($args = array()) {  8   9  extract($args );  10   11  // get the settings sections array  12  $settings_output = wptuts_get_settings();  13   14 $wptuts_option_name = $settings_output['wptuts_option_name'];  15 $options = get_option($wptuts_option_name);  16   17  // pass the standard value if the option is not yet set in the database  18  if ( !isset($options[$id] ) && 'type' != 'checkbox' ) {  19 $options[$id] =$std;  20  }  21   22  // additional field class. output only if the class is defined in the create_setting arguments  23  $field_class = ($class != '') ? ' ' . $class : '';  24   25   26  // switch html display based on the setting type.  27  switch ($type ) {  28  case 'text':  29  $options[$id] = stripslashes($options[$id]);  30  $options[$id] = esc_attr( $options[$id]);  31  echo "";  32  echo ($desc != '') ? "$desc" : "";  33  break;  34   35  case "multi-text":  36  foreach($choices as$item) {  37  $item = explode("|",$item); // cat_name|cat_slug  38  $item[0] = esc_html__($item[0], 'wptuts_textdomain');  39  if (!empty($options[$id])) {  40  foreach ($options[$id] as $option_key =>$option_val){  41  if ($item[1] ==$option_key) {  42  $value =$option_val;  43  }  44  }  45  } else {  46  $value = '';  47  }  48  echo "$item[0]:
";  49  }  50  echo ($desc != '') ? "$desc" : "";  51  break;  52   53  case 'textarea':  54  $options[$id] = stripslashes($options[$id]);  55  $options[$id] = esc_html( $options[$id]);  56  echo "";  57  echo ($desc != '') ? "$desc" : "";  58  break;  59   60  case 'select':  61  echo "";  70  echo ($desc != '') ? "$desc" : "";  71  break;  72   73  case 'select2':  74  echo "";  84  echo ($desc != '') ? "$desc" : "";  85  break;  86   87  case 'checkbox':  88  echo "";  89  echo ($desc != '') ? "$desc" : "";  90  break;  91   92  case "multi-checkbox":  93  foreach($choices as$item) {  94   95  $item = explode("|",$item);  96  $item[0] = esc_html($item[0], 'wptuts_textdomain');  97   98  $checked = '';  99   100  if ( isset($options[$id][$item[1]]) ) {  101  if ( $options[$id][$item[1]] == 'true') {  102 $checked = 'checked="checked"';  103  }  104  }  105   106  echo " $item[0] ";  107  }  108  echo ($desc != '') ? "
$desc" : "";  109  break;  110  }  111 }  Breaking-down the code We collect our settings fields in the $options variable.

 1 2 // get the settings sections array  3 $settings_output = wptuts_get_settings();  4 5 $wptuts_option_name = $settings_output['wptuts_option_name'];  6 $options = get_option($wptuts_option_name);  We pass the standard value ($std) if the setting is not yet set. We also put together a $field_class to be used as the form input field class (can be used for styling if needed.)  1 2 // pass the standard value if the option is not yet set in the database  3 if ( !isset($options[$id] ) && 'type' != 'checkbox' ) {  4 $options[$id] =$std;  5 }  6 7 // additional field class. output only if the class is defined in the create_setting arguments  8 $field_class = ($class != '') ? ' ' . $class : '';  Then, we run a foreach loop and switch based on the setting field type (text, textarea, select, checkbox etc.) When you customize this function later on, you will want to create a new case for each new setting field type (note: type) you add.  1 2 // run a foreach and switch on option type  3 foreach ($options as $option) {  4  switch ($option['type'] ) {  5  case 'text':  6  // echo code  7  break;  8   9  case "multi-text":  10  // echo code  11  break;  12   13  case 'textarea':  14  // echo code  15  break;  16   17  case 'select':  18  // echo code  19  break;  20   21  case 'select2':  22  // echo code  23  break;  24   25  case 'checkbox':  26  // echo code  27  break;  28   29  case 'multi-checkbox':  30  // echo code  31  break;  32  }  33 } 

### Check the Result

If you have followed the above successfully, this is how your settings page should look like at this point. Note that nothing will save yet so don't be surprised if nothing happens when you try!

## Step 5 Validating & Saving User Input

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

Step 5 is all about validating and sanitizing what users attempt to save when they hit the "Save Settings" button. This process, also refered to as "whitelisting" is, in my opinion, the most important part in this tutorial. If there's anything that my theme users have indelibly impressed upon me is to validate, validate, validate! So, in this tutorial we will create a project-ready validation callback function which you can use in your projects. Feel free to modify, improve and extend it according to your needs.

Oh! and one more thing before we get to the actual validation function. Should you notice that your settings don't save even when everything else looks fine, this is the place to troubleshoot!
So, we'll also cover a troubleshooting tip that may help.

### The Validation Callback Function

We have already defined this function in step 2 so go ahead and find it in your my-theme-settings.php. Then copy and paste the completed function you see below in it's place.

 1 2 /*  3  * Validate input  4  *  5  * @return array  6  */  7 function wptuts_validate_options($input) {  8   9  // for enhanced security, create a new empty array  10 $valid_input = array();  11   12  // collect only the values we expect and fill the new $valid_input array i.e. whitelist our option IDs  13   14  // get the settings sections array  15 $settings_output = wptuts_get_settings();  16   17  $options =$settings_output['wptuts_page_fields'];  18   19  // run a foreach and switch on option type  20  foreach ($options as$option) {  21   22  switch ( $option['type'] ) {  23  case 'text':  24  //switch validation based on the class!  25  switch ($option['class'] ) {  26  //for numeric  27  case 'numeric':  28  //accept the input only when numeric!  29  $input[$option['id']] = trim($input[$option['id']]); // trim whitespace  30  $valid_input[$option['id']] = (is_numeric($input[$option['id']])) ? $input[$option['id']] : 'Expecting a Numeric value!';  31   32  // register error  33  if(is_numeric($input[$option['id']]) == FALSE) {  34  add_settings_error(  35  $option['id'], // setting title  36  WPTUTS_SHORTNAME . '_txt_numeric_error', // error ID  37  __('Expecting a Numeric value! Please fix.','wptuts_textdomain'), // error message  38  'error' // type of message  39  );  40  }  41  break;  42   43  //for multi-numeric values (separated by a comma)  44  case 'multinumeric':  45  //accept the input only when the numeric values are comma separated  46 $input[$option['id']] = trim($input[$option['id']]); // trim whitespace  47   48  if($input[$option['id']] !=''){  49  // /^-?\d+(?:,\s?-?\d+)*$/ matches: -1 | 1 | -12,-23 | 12,23 | -123, -234 | 123, 234 | etc.  50  $valid_input[$option['id']] = (preg_match('/^-?\d+(?:,\s?-?\d+)*$/',$input[$option['id']]) == 1) ?$input[$option['id']] : __('Expecting comma separated numeric values','wptuts_textdomain');  51  }else{  52 $valid_input[$option['id']] =$input[$option['id']];  53  }  54   55  // register error  56  if($input[$option['id']] !='' && preg_match('/^-?\d+(?:,\s?-?\d+)*$/', $input[$option['id']]) != 1) {  57  add_settings_error(  58  $option['id'], // setting title  59  WPTUTS_SHORTNAME . '_txt_multinumeric_error', // error ID  60  __('Expecting comma separated numeric values! Please fix.','wptuts_textdomain'), // error message  61  'error' // type of message  62  );  63  }  64  break;  65   66  //for no html  67  case 'nohtml':  68  //accept the input only after stripping out all html, extra white space etc!  69 $input[$option['id']] = sanitize_text_field($input[$option['id']]); // need to add slashes still before sending to the database  70 $valid_input[$option['id']] = addslashes($input[$option['id']]);  71  break;  72   73  //for url  74  case 'url':  75  //accept the input only when the url has been sanited for database usage with esc_url_raw()  76 $input[$option['id']] = trim($input[$option['id']]); // trim whitespace  77 $valid_input[$option['id']] = esc_url_raw($input[$option['id']]);  78  break;  79   80  //for email  81  case 'email':  82  //accept the input only after the email has been validated  83 $input[$option['id']] = trim($input[$option['id']]); // trim whitespace  84  if($input[$option['id']] != ''){  85 $valid_input[$option['id']] = (is_email($input[$option['id']])!== FALSE) ?$input[$option['id']] : __('Invalid email! Please re-enter!','wptuts_textdomain');  86  }elseif($input[$option['id']] == ''){  87 $valid_input[$option['id']] = __('This setting field cannot be empty! Please enter a valid email address.','wptuts_textdomain');  88  }  89   90  // register error  91  if(is_email($input[$option['id']])== FALSE ||$input[$option['id']] == '') {  92  add_settings_error(  93 $option['id'], // setting title  94  WPTUTS_SHORTNAME . '_txt_email_error', // error ID  95  __('Please enter a valid email address.','wptuts_textdomain'), // error message  96  'error' // type of message  97  );  98  }  99  break;  100   101  // a "cover-all" fall-back when the class argument is not set  102  default:  103  // accept only a few inline html elements  104  $allowed_html = array(  105  'a' => array('href' => array (),'title' => array ()),  106  'b' => array(),  107  'em' => array (),  108  'i' => array (),  109  'strong' => array()  110  );  111   112 $input[$option['id']] = trim($input[$option['id']]); // trim whitespace  113 $input[$option['id']] = force_balance_tags($input[$option['id']]); // find incorrectly nested or missing closing tags and fix markup  114 $input[$option['id']] = wp_kses($input[$option['id']],$allowed_html); // need to add slashes still before sending to the database  115  $valid_input[$option['id']] = addslashes($input[$option['id']]);  116  break;  117  }  118  break;  119   120  case "multi-text":  121  // this will hold the text values as an array of 'key' => 'value'  122  unset($textarray);  123   124 $text_values = array();  125  foreach ($option['choices'] as$k => $v ) {  126  // explode the connective  127 $pieces = explode("|", $v);  128   129 $text_values[] = $pieces[1];  130  }  131   132  foreach ($text_values as $v ) {  133   134  // Check that the option isn't empty  135  if (!empty($input[$option['id'] . '|' .$v])) {  136  // If it's not null, make sure it's sanitized, add it to an array  137  switch ($option['class']) {  138  // different sanitation actions based on the class create you own cases as you need them  139   140  //for numeric input  141  case 'numeric':  142  //accept the input only if is numberic!  143 $input[$option['id'] . '|' .$v]= trim($input[$option['id'] . '|' . $v]); // trim whitespace  144 $input[$option['id'] . '|' .$v]= (is_numeric($input[$option['id'] . '|' . $v])) ?$input[$option['id'] . '|' .$v] : '';  145  break;  146   147  // a "cover-all" fall-back when the class argument is not set  148  default:  149  // strip all html tags and white-space.  150  $input[$option['id'] . '|' . $v]= sanitize_text_field($input[$option['id'] . '|' .$v]); // need to add slashes still before sending to the database  151  $input[$option['id'] . '|' . $v]= addslashes($input[$option['id'] . '|' .$v]);  152  break;  153  }  154  // pass the sanitized user input to our $textarray array  155 $textarray[$v] =$input[$option['id'] . '|' .$v];  156   157  } else {  158  $textarray[$v] = '';  159  }  160  }  161  // pass the non-empty $textarray to our$valid_input array  162  if (!empty($textarray)) {  163 $valid_input[$option['id']] =$textarray;  164  }  165  break;  166   167  case 'textarea':  168  //switch validation based on the class!  169  switch ( $option['class'] ) {  170  //for only inline html  171  case 'inlinehtml':  172  // accept only inline html  173 $input[$option['id']] = trim($input[$option['id']]); // trim whitespace  174 $input[$option['id']] = force_balance_tags($input[$option['id']]); // find incorrectly nested or missing closing tags and fix markup  175 $input[$option['id']] = addslashes($input[$option['id']]); //wp_filter_kses expects content to be escaped!  176 $valid_input[$option['id']] = wp_filter_kses($input[$option['id']]); //calls stripslashes then addslashes  177  break;  178   179  //for no html  180  case 'nohtml':  181  //accept the input only after stripping out all html, extra white space etc!  182 $input[$option['id']] = sanitize_text_field($input[$option['id']]); // need to add slashes still before sending to the database  183 $valid_input[$option['id']] = addslashes($input[$option['id']]);  184  break;  185   186  //for allowlinebreaks  187  case 'allowlinebreaks':  188  //accept the input only after stripping out all html, extra white space etc!  189 $input[$option['id']] = wp_strip_all_tags($input[$option['id']]); // need to add slashes still before sending to the database  190 $valid_input[$option['id']] = addslashes($input[$option['id']]);  191  break;  192   193  // a "cover-all" fall-back when the class argument is not set  194  default:  195  // accept only limited html  196  //my allowed html  197 $allowed_html = array(  198  'a' => array('href' => array (),'title' => array ()),  199  'b' => array(),  200  'blockquote' => array('cite' => array ()),  201  'br' => array(),  202  'dd' => array(),  203  'dl' => array(),  204  'dt' => array(),  205  'em' => array (),  206  'i' => array (),  207  'li' => array(),  208  'ol' => array(),  209  'p' => array(),  210  'q' => array('cite' => array ()),  211  'strong' => array(),  212  'ul' => array(),  213  'h1' => array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),  214  'h2' => array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),  215  'h3' => array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),  216  'h4' => array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),  217  'h5' => array('align' => array (),'class' => array (),'id' => array (), 'style' => array ()),  218  'h6' => array('align' => array (),'class' => array (),'id' => array (), 'style' => array ())  219  );  220   221  $input[$option['id']] = trim($input[$option['id']]); // trim whitespace  222  $input[$option['id']] = force_balance_tags($input[$option['id']]); // find incorrectly nested or missing closing tags and fix markup  223  $input[$option['id']] = wp_kses( $input[$option['id']], $allowed_html); // need to add slashes still before sending to the database  224 $valid_input[$option['id']] = addslashes($input[$option['id']]);  225  break;  226  }  227  break;  228   229  case 'select':  230  // check to see if the selected value is in our approved array of values!  231 $valid_input[$option['id']] = (in_array($input[$option['id']],$option['choices']) ? $input[$option['id']] : '' );  232  break;  233   234  case 'select2':  235  // process $select_values  236 $select_values = array();  237  foreach ($option['choices'] as$k => $v) {  238  // explode the connective  239 $pieces = explode("|", $v);  240   241 $select_values[] = $pieces[1];  242  }  243  // check to see if selected value is in our approved array of values!  244 $valid_input[$option['id']] = (in_array($input[$option['id']],$select_values) ? $input[$option['id']] : '' );  245  break;  246   247  case 'checkbox':  248  // if it's not set, default to null!  249  if (!isset($input[$option['id']])) {  250  $input[$option['id']] = null;  251  }  252  // Our checkbox value is either 0 or 1  253  $valid_input[$option['id']] = ( $input[$option['id']] == 1 ? 1 : 0 );  254  break;  255   256  case 'multi-checkbox':  257  unset($checkboxarray);  258 $check_values = array();  259  foreach ($option['choices'] as$k => $v ) {  260  // explode the connective  261 $pieces = explode("|", $v);  262   263 $check_values[] = $pieces[1];  264  }  265   266  foreach ($check_values as $v ) {  267   268  // Check that the option isn't null  269  if (!empty($input[$option['id'] . '|' .$v])) {  270  // If it's not null, make sure it's true, add it to an array  271  $checkboxarray[$v] = 'true';  272  }  273  else {  274  $checkboxarray[$v] = 'false';  275  }  276  }  277  // Take all the items that were checked, and set them as the main option  278  if (!empty($checkboxarray)) {  279 $valid_input[$option['id']] =$checkboxarray;  280  }  281  break;  282   283  }  284  }  285 return $valid_input; // return validated input  286 }  Breaking-down the code Some of the process may remind you of what we did in the setting fields callback function which handled the form field display on the page. We collect our settings fields in the $options variable.

 1 2 // get the settings sections array  3  $settings_output = wptuts_get_settings();  4   5 $options = $settings_output['wptuts_page_fields'];  Then, we run a foreach loop and switch based on the setting field type (text, textarea, select, checkbox etc.) When you customize this function later on, you will want to create a new case for each new setting field type (note: type) you add.  1 2 // run a foreach and switch on option type  3  foreach ($options as $option) {  4  switch ($option['type'] ) {  5  case 'text':  6  // validation code  7  break;  8   9  case "multi-text":  10  // validation code  11  break;  12   13  case 'textarea':  14  // validation code  15  break;  16   17  case 'select':  18  // validation code  19  break;  20   21  case 'select2':  22  // validation code  23  break;  24   25  case 'checkbox':  26  // validation code  27  break;  28   29  case 'multi-checkbox':  30  // validation code  31  break;  32  }  33  } 

Each setting field type, the text and textarea types in particular, may be used for different user input. Sometimes the input may be some text where html elements are allowed but at other times it may be that html is not allowed, or only inline html is OK. Some settings may expect a numeric, email or url user input. All that needs to be validated properly and here is where the class argument in our wptuts_options_page_fields() function comes in.

We run a second switch based on the setting field class (nohtml, numeric, email, url etc.) which will contain different validation/sanitation code depending on what is needed. When you customize this function later on, you will want to create a new case for each new setting field class you may create. Written below, you see the class switch for the text setting field type. Take a moment to study the class switch used for the textarea setting field as well.

 1 2 3 switch ( $option['type'] ) {  4  case 'text':  5  //switch validation based on the class!  6  switch ($option['class'] ) {  7   8  //for numeric  9  case 'numeric':  10  // validation code  11  break;  12   13  //for multi numeric separated with a comma  14  case 'multinumeric':  15  // validation code  16  break;  17   18  //for no html  19  case 'nohtml':  20  // validation code  21  break;  22   23  //for url  24  case 'url':  25  // validation code  26  break;  27   28  //for email  29  case 'email':  30  // validation code  31  break;  32   33  // a "cover-all" fall-back when the class argument is not set  34  default:  35  // validation code  36  break;  37  }  38  break; 

Take the time to study the validation/sanitation done in each case. Should you see any functions used you're not sure about, look them up. A good resource for Data Validation is found in the Codex

Troubleshooting settings that won't save

Should you notice that your settings don't save, the first thing to do is print_r both the incoming $input at the top of the validation function and the outgoing $valid_input at the end before it is returned.

 1 2 function wptuts_validate_options($input) {  3  ?> If the validation code you are using is not written well then the $valid_input array values will be empty even though the $input array values look ok. Isolate the problematic settings and look into your validation code to find out what may be preventing the value of a particular $input key from being passed on as the value of the corresponding $valid_input key. ### Register Errors As you go through the validation code you will notice that what we mostly do is take the user input, "clean it up" and then pass it on to our validated input array. On occation however, such as in the case of email input, we will require the user to correct his input before saving the value in the database. We need to let the user know that there is a problem i.e. his input is not correct and that he needs to re-enter the value needed correctly. The WordPress Settings API allows us to provide such feedback using the add_settings_error() function. You will see this function used on our text setting field type and specifically for the numeric, multinumeric and email classes. Shown below is the validation done on the email input field.  1 2 //for email  3 case 'email':  4  //accept the input only after email has been validated  5 $input[$option['id']] = trim($input[$option['id']]); // trim whitespace  6  if($input[$option['id']] != ''){  7 $valid_input[$option['id']] = (is_email($input[$option['id']])!== FALSE) ?$input[$option['id']] : __('Invalid email! Please re-enter!','wptuts_textdomain');  8  }elseif($input[$option['id']] == ''){  9 $valid_input[$option['id']] = __('This setting field cannot be empty! Please enter a valid email address.','wptuts_textdomain');  10  }  11   12  // register error  13  if(is_email($input[$option['id']])== FALSE ||$input[$option['id']] == '') {  14  add_settings_error(  15 $option['id'], // setting title  16  WPTUTS_SHORTNAME . '_txt_email_error', // error ID  17  __('Please enter a valid email address.','wptuts_textdomain'), // error message  18  'error' // type of message  19  );  20  }  21 break; 

Understand the add_settings_error() parameters

Take note of the add_settings_error() function parameters. The information is taken from the Codex page:

• $setting - Slug title of the setting to which this error applies. • $code - Slug-name to identify the error. Used as part of 'id' attribute in HTML output.
• $message - The formatted message text to display to the user (will be shown inside styled <div> and <p>) • $type - The type of message it is (error or update), controls HTML class.

### Check the Result

If you have followed the above successfully, then you should now be able to edit and save your settings! You will not see any admin messages (neither "success" nor "error") yet - we still have to write this (see step 6) - however your settings will be validated and saved.

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

In Step 5 we talked about whitelisting our settings and saving them. This is all nice however, we need to provide some sort of feedback when settings save successfully and when errors occur. Step 6 talks about displaying such feedback in the form of admin messages.

### The Helper Function

WordPress provides us with an action hook we can use to echo out admin messages and this is what we will be using to display feedback both on "success" and on "error". First, we will create a helper function with 2 parameters: the actual message and the message type ("error", "info", "update", etc). I've seen this at Wp Recipes and I liked the way it was done so, we'll use it here as well.

The code given below and for the rest of Step 6 should be written in the my-theme-settings.php file just after the wptuts_validate_options() function.

 1 2  /**  3  * Helper function for creating admin messages  4  * src: http://www.wprecipes.com/how-to-show-an-urgent-message-in-the-wordpress-admin-area  5  *  6  * @param (string) $message The message to echo  7  * @param (string)$msgclass The message class  8  * @return echoes the message  9  */  10 function wptuts_show_msg($message,$msgclass = 'info') {  11  echo "
$message ";  12 }  ### The Callback Function and Action Hook Next we need to write our callback function that will be hooked to admin_notices  1 2  /**  3  * Callback function for displaying admin messages  4  *  5  * @return calls wptuts_show_msg()  6  */  7 function wptuts_admin_msgs() {  8   9  // check for our settings page - need this in conditional further down  10 $wptuts_settings_pg = strpos($_GET['page'], WPTUTS_PAGE_BASENAME);  11  // collect setting errors/notices: //http://codex.wordpress.org/Function_Reference/get_settings_errors  12 $set_errors = get_settings_errors();  13   14  //display admin message only for the admin to see, only on our settings page and only when setting errors/notices are returned!  15  if(current_user_can ('manage_options') && $wptuts_settings_pg !== FALSE && !empty($set_errors)){  16 17  // have our settings succesfully been updated?  18  if($set_errors[0]['code'] == 'settings_updated' && isset($_GET['settings-updated'])){  19  wptuts_show_msg("

" . $set_errors[0]['message'] . " ", 'updated');  20   21  // have errors been found?  22  }else{  23  // there maybe more than one so run a foreach loop.  24  foreach($set_errors as $set_error){  25  // set the title attribute to match the error "setting title" - need this in js file  26  wptuts_show_msg(" " .$set_error['message'] . "

", 'error');  27  }  28  }  29  }  30 }  31 32 // admin messages hook!  33 add_action('admin_notices', 'wptuts_admin_msgs'); 

Understand the function

I made sure to comment out the function well however it should be noted that the get_settings_errors() function will not only return error messages but all notices in general - including a successfull message when our settings save correctly. So don't let the function name mislead you! This is why we are able to use the same function to display the "Settings saved" admin message on "success" as well as the error messages on "error".

### Check the Result

If you have followed the above successfully, then you should be able now to see the successful "Settings saved." admin message when you pass input validation, as well as the error admin message when you don't.

### Error? But Where?

Now that the error message displays as expected let's add a touch of javascript to draw attention to the setting the user needs to correct. You actually have the code already uploaded on your server. You've done this already in Step 1 so all we need to do is simply include the required files in our settings page so that the browser can execute the script. Copy and paste the following above the wptuts_add_menu() function.

 1 2 /*  3  * Group scripts (js & css)  4  */  5 function wptuts_settings_scripts(){  6  wp_enqueue_style('wptuts_theme_settings_css', get_template_directory_uri() . '/lib/css/wptuts_theme_settings.css');  7  wp_enqueue_script( 'wptuts_theme_settings_js', get_template_directory_uri() . '/lib/js/wptuts_theme_settings.js', array('jquery'));  8 } 

Then we adjust the wptuts_add_menu() function like this:

 1 2 /*  3  * The Admin menu page  4  */  5 function wptuts_add_menu(){  6   7  // Display Settings Page link under the "Appearance" Admin Menu  8  // add_theme_page( $page_title,$menu_title, $capability,$menu_slug, $function);  9 $wptuts_settings_page = add_theme_page(__('Wptuts Options'), __('Wptuts Options','wptuts_textdomain'), 'manage_options', WPTUTS_PAGE_BASENAME, 'wptuts_settings_page_fn');  10   11  // css & js  12  add_action( 'load-'. $wptuts_settings_page, 'wptuts_settings_scripts' );  13 }  What does the js code say? Look inside the twentyeleven/lib/js folder and open the file you see inside: wptuts_theme_settings.js in your code editor.  1 2 jQuery(function(){  3  var error_msg = jQuery("#message p[class='setting-error-message']");  4  // look for admin messages with the "setting-error-message" error class  5  if (error_msg.length != 0) {  6  // get the title  7  var error_setting = error_msg.attr('title');  8   9  // look for the label with the "for" attribute=setting title and give it an "error" class (style this in the css file!)  10  jQuery("label[for='" + error_setting + "']").addClass('error');  11   12  // look for the input with id=setting title and add a red border to it.  13  jQuery("input[id='" + error_setting + "']").attr('style', 'border-color: red');  14  }  15 });  We look for any admin messages with the class setting-error-message. If we have any displaying on the page, we proceed and get the error message title attribute. This will always match a setting label (for attribute) and an input form field (id attribute). All is left to do, is add an error class to the label and a border style to the input form field. Note that the error class is then styled in the css file (twentyeleven/lib/css/wptuts_theme_settings.css). When you open the css file you'll see it is practically empty. Use it as you want to add further stylling to your settings page. ### Check the Result (Again) If you have followed the above successfully, then error settings should be highlighted red when error admin messages display like you see below. "The final code described in this step is found in the Part One/source_ files/step7/ my-theme-settings.php folder" ## Step 7 Contextual Help The final Step 7 in this tutorial will touch on adding contextual help to our settings page. This additional information will be located inside the panel that slides open when you click on the "Help" tab located at the top right of your admin screen. What we need to do, is write the text we want and then tell WordPress where we want it displayed. ### Write the Text Open your my-theme-options.php file in your code editor. Copy and paste the function you see below  1 2 /**  3  * Contextual Help  4  */  5 function wptuts_options_page_contextual_help() {  6   7 $text = "

" . __('Wptuts Settings - Contextual Help','wptuts_textdomain') . "

";  8  $text .= " " . __('Contextual help goes here. You may want to use different html elements to format your text as you want.','wptuts_textdomain') . " ";  9   10  // return text  11  return$text;  12 } 

### Let WordPress Know Where to Display It

First we need to adjust our helper wptuts_get_settings() function to include a value for $output['wptuts_contextual_help']. The code given below and for the remaining part of Step 7 should be written in the my-theme-settings.php file.  1 2  /**  3  * Helper function for defining variables for the current page  4  *  5  * @return array  6  */  7 function wptuts_get_settings() {  8   9 $output = array();  10   11  // put together the output array  12  $output['wptuts_option_name'] = 'wptuts_options';  13 $output['wptuts_page_title'] = __( 'Wptuts Settings Page','wptuts_textdomain');  14  $output['wptuts_page_sections'] = wptuts_options_page_sections();  15 $output['wptuts_page_fields'] = wptuts_options_page_fields();  16  $output['wptuts_contextual_help'] = wptuts_options_page_contextual_help();  17   18 return$output;  19 } 

Then we adjust our wptuts_add_menu() function one last time. We call the add_contextual_help() function which takes in two parameters:
$screen (our setting page) and $text (the help text we output from wptuts_options_page_contextual_help())

 1 2 /*  3  * The Admin menu page  4  */  5 function wptuts_add_menu(){  6   7  $settings_output = wptuts_get_settings();  8  // collect our contextual help text  9 $wptuts_contextual_help = $settings_output['wptuts_contextual_help'];  10   11  // Display Settings Page link under the "Appearance" Admin Menu  12 $wptuts_settings_page = add_theme_page(__('Wptuts Options'), __('Wptuts Options','wptuts_textdomain'), 'manage_options', WPTUTS_PAGE_BASENAME, 'wptuts_settings_page_fn');  13  // contextual help  14  if ($wptuts_settings_page) {  15  add_contextual_help($wptuts_settings_page, $wptuts_contextual_help );  16  }  17  // css & js  18  add_action( 'load-'.$wptuts_settings_page, 'wptuts_settings_scripts' );  19 } 

### Check the Result

If you have followed the above successfully, then our contextual help test should display inside the "Help" tab like you see below.

## Using the Theme Settings in Our Theme

Last but not least we want to look into how we can go about using our theme settings in our theme template files. Copy and paste the following code in the twentyeleven/functions.php after the twentyeleven_setup() function.

 1 2  /**  3  * Collects our theme options  4  *  5  * @return array  6  */  7 function wptuts_get_global_options(){  8   9  $wptuts_option = array();  10 11 $wptuts_option = get_option('wptuts_options');  12   13 return $wptuts_option;  14 }  15 16  /**  17  * Call the function and collect in variable  18  *  19  * Should be used in template files like this:  20  *  21  *  22  * Note: Should you notice that the variable ($wptuts_option) is empty when used in certain templates such as header.php, sidebar.php and footer.php  23  * you will need to call the function (copy the line below and paste it) at the top of those documents (within php tags)!  24  */  25 $wptuts_option = wptuts_get_global_options();  Our settings were saved in a single array with the option name wptuts_options. To retrieve them we call get_option('wptuts_options'). As you can see this is done inside our wptuts_get_global_options() fuction whose output is collected in the $wptuts_option variable.

Note: If you feel that the wptuts_get_global_options() function is somewhat redundant, don't. It's use will make more sense once you go through Part Two of this series.

Echo a particular option in any of your theme templates like this: <?php echo $wptuts_option['wptuts_txt_input']; ?> - the value in the brackets is the id of the option you want to display. ### Worth Noting You will notice that when you try to echo the above in the header.php, sidebar.php and footer.php templates nothing happens! This is not the case in other WordPress templates (index.php, page.php etc.). Try it out for yourself to see. Copy and paste the following in the twentyeleven/header.php after the <body> tag and see how it returns NULL on the front-end.  1 2   Now copy and paste the following just after the wp_head(); call.  1 2 $wptuts_option = wptuts_get_global_options(); 

Note how the variable now returns all our theme settings. Just remember this when you try to display options from your theme settings in your header.php, sidebar.php and footer.php` theme templates.

## Up Next... Part Two

Hope you enjoyed Part One and I look forward to reading your comments on what you thought about it. Part Two (coming tomorrow!) will show how we can create Top Level Admin menus with more than one setting pages. We will throw in some tabs too so you can see how a settings page with tabs can be created.