WP Theme Options: Getting Started

 

Okay, so you know what theme options are and you have a fair idea what you want to bundle with your theme. The question is, where do you start?

In essence you can get started by simply using the following file:

  • functions.php – This is the basic entry point for all your theme’s functions. If you are creating a theme, this file should be in the same folder as your header.php, footer.php etc. If you are modifying an existing theme, chances are that this file is already present. If so, work with that file and if not, create a new file.

At the start of functions.php, first define some basics regarding your theme:

<?php
    $themename = "My New Theme";
    $shortname = "mnt";

Try to keep the $shortname unique, because we are going to be using a lot of it. You will be prefixing all your options with your $shortname, just to ensure that there is no conflict between the options you are providing and the options that some other theme or plugin is providing.

Next, we will define a list of options. Before that let’s examine what types of options we want to provide:

  1. A text field (text) – A single-line plain-text field. You might use this kind of field to capture a URL or some other free-form text, like a title
  2. A text area (text-area) – A multi-line variant of a plain-text field. HTML constructs have different input types for single line text and multi-line text. This kind of a field could be used to capture a multi-line description or a script
  3. A color-picker (color-picker) – This can be a special case of a plain-text field: something that is tied to a JavaScript-based color-picker
  4. A radio-select (or a single-select from a drop-down) (radio, or select) – This is one of the most commonly used option types, since very often you will be picking a single value from a list.
  5. A multi-select (multi-select) – A somewhat less frequently used option, but very useful to code. We will see why.

Now that we have narrowed down our option types, let us see how we can provide these options. To start with, let’s define the following core attributes of an option:

  • id – This is the internal name you will use to track an option. It will be stored in the database with this id. As a result the id has to be unique.
  • name – This is the name that you will see on the theme options configuration page.
  • type – This is the type of option you are going to create (text, text-area, color-picker, radio, select or multi-select)

Creating Our First Option: A Radio Button


So, a typical option that you provide would start off looking like this:

    array("name" => "Sidebar Position",
            "id" => $shortname."_sidebar_alignment",
            "type" => "radio",
    )

In the above, the internal id is going to be “mnt_sidebar_alignment”, the display name is “Sidebar Position” and type is “radio”. The very first thing that jumps out here is that we are building a radio button, but are not specifying any options for it. Also, the user needs to be told what the “Sidebar Position” is for. So let us do this by adding an “options” element and a “desc” element to the array:

    array("name" => "Sidebar Position",
            "id" => $shortname."_sidebar_alignment",
            "type" => "radio",
            "desc" => "Which side would you like your sidebar?",
            "options" => array("left" => "Left", "right" => "Right"),
    )

So now I have to build a radio button with options for “left” and “right”. Can we specify which option should be selected by default? Let’s do that by defining a “standard” (“std”) element:

    array("name" => "Sidebar Position",
            "id" => $shortname."_sidebar_alignment",
            "type" => "radio",
            "desc" => "Which side would you like your sidebar?",
            "options" => array("left" => "Left", "right" => "Right"),
            "std" => "right",
    )

We are stating in the above that by default “right” should be selected. Let us now write the code to actually process this option:

function create_section_for_radio($value) {
    create_opening_tag($value);
    foreach ($value['options'] as $option_value => $option_text) {
        $checked = ' ';
        if (get_option($value['id']) == $option_value) {
            $checked = ' checked="checked" ';
        }
        else if (get_option($value['id']) === FALSE && $value['std'] == $option_value){
            $checked = ' checked="checked" ';
        }
        else {
            $checked = ' ';
        }
        echo '<div class="mnt-radio"><input type="radio" name="'.$value['id'].'" value="'.
            $option_value.'" '.$checked."/>".$option_text."</div>n";
    }
    create_closing_tag();
}

In the above we are passing the array we have defined as the $value argument to the create_section_for_radio function. The function goes through the list of defined options, it checks against the option value defined in the database and marks the appropriate option as “checked”. If an option doesn’t have a value in the database, it selects the value defined in the “std” attribute.

Here are three function calls that you see in the above code:

  • create_opening_tag – This is a custom function that I have written, to abstract out some repetitive code. Every time I create an option, I run this code and it does some HTML formatting for me.
  • get_option – This is a standard WordPress function call. It runs against the database and retrieves an option value. Take a look at http://your-domain/your-wp-install/wp-admin/options.php. The get_option call retrieves the option value as listed in this page.
  • create_closing_tag – This is another custom function that I have written, which is run when I am closing an option section.

In the subsequent sections I have put in code samples for the other option types.

Options for Text


For a plain-text field, the first thing to note is that we don’t require any options element. We still require a standard value, though:

    array("name" => "Header Image",
            "desc" => "Set the image to use for the header background. ",
            "id" => $shortname."_header_background_image",
            "type" => "text",
            "std" => "")

The processing for the text field is similar to that of a radio-button, except that, well, this is a text field:

function create_section_for_text($value) {
    create_opening_tag($value);
    $text = "";
    if (get_option($value['id']) === FALSE) {
        $text = $value['std'];
    }
    else {
        $text = get_option($value['id']);
    }

    echo '<input type="text" id="'.$value['id'].'" name="'.$value['id'].'" value="'.$text.'" />'."n";
    create_closing_tag();
}

Options for Text-Area


A text-area field behaves very similar to a text field:

    array("name" => "Custom Google Analytics Tracking Code",
            "desc" => "Enter your tracking code here for Google Analytics",
            "id" => $shortname."_custom_analytics_code",
            "type" => "textarea",
            "std" => "")

Instead of an <input> element, we use a <textarea> element:

function create_section_for_textarea($value) {
    create_opening_tag($value);
    echo '<textarea name="'.$value['id'].'" type="textarea" cols="" rows="">'."n";
    if ( get_option( $value['id'] ) != "") {
        echo get_option( $value['id'] );
    }
    else {
        echo $value['std'];
    }
    echo '</textarea>';
    create_closing_tag();
}

Options for Color Pickers


Now we address the first tricky subject – a color picker. You could cut the Gordian knot here and say, “I am going to assume my theme user is familiar with RGB colors and he will put in the values himself, so I will treat a color field just like a text field”. Unfortunately for a large number of users this is not the case and you might be better off providing a JavaScript based color picker. You could take a look at a pretty good collection of JavaScript color pickers. I personally use the color picker provided by JSColor, because it is incredibly easy to set up. You simply include the JavaScript file in a <script> tag and assign a class called "color" to the input field.

So the option looks like this:

    array("name" => "Body Background Color",
            "desc" => "Set the color of the background on which the page is. ",
            "id" => $shortname."_body_background_color",
            "type" => "color-picker",
            "std" => "444444")

And this is the code to process it:

function create_section_for_color_picker($value) {
    create_opening_tag($value);
    $color_value = "";
    if (get_option($value['id']) === FALSE) {
        $color_value = $value['std'];
    }
    else {
        $color_value = get_option($value['id']);
    }

    echo '<div class="color-picker">'."n";
    echo '<input type="text" id="'.$value['id'].'" name="'.$value['id'].'" value="'.$color_value.'" class="color" />';
    echo ' &laquo; Click to select color<br/>'."n";
    echo "<strong>Default: <font color='".$value['std']."'> ".$value['std']."</font></strong>";
    echo " (You can copy and paste this into the box above)n";
    echo "</div>n";
    create_closing_tag();
}

The above code simply adds a class called “color” to the input field. It also tells you what the default color is and shows you the color.

Options for Multi-Select


This is the second tricky subject. A traditional multi-select is built with a <select multiple> HTML construct. However this presents some UI challenges for the end-user, like holding the Ctrl key pressed down while making all selections, inadvertently resetting all selections etc:

Multi-Select Using SELECT tags

Multi-Select Using SELECT tags

So you might want to explore another option, of using a set of check-boxes to simulate your multi-select:

Multi-Select Using Checkboxes

Multi-Select Using Checkboxes

I prefer the second option myself, but it does not come without its own share of difficulties. To start with, here is the option definition:

    array("name" => "Pages to show in Navigation Bar",
            "desc" => "Select the pages you want to include. All pages are excluded by default",
            "id" => $shortname."_nav_pages",
            "type" => "multi-select",
            "options" => mnt_get_formatted_page_array($shortname."_nav_pages"),
            "std" => "none")

Here you see a hack in place. The mnt_get_formatted_page_array dynamically fetches the list of pages and creates an array with it. The trick here, since we are using checkboxes, is to have each page in the array associated with its own id. In other words, if the page called “Tutorials” has an id “5”, it will correspond to the checkbox: <input type="checkbox" name="mnt_nav_pages_5" value="true" class="depth-1" />Tutorials. Basically we are appending “_5″ to the id of the field, “mtn_nav_pages”.

The processing of this piece involves an additional check, too:

function create_section_for_multi_select($value) {
    create_opening_tag($value);
    echo '<ul class="mnt-checklist" id="'.$value['id'].'" >'."n";
    foreach ($value['options'] as $option_value => $option_list) {
        $checked = " ";
        if (get_option($value['id']."_".$option_value)) {
            $checked = " checked='checked' ";
        }
        echo "<li>n";
        echo '<input type="checkbox" name="'.$value['id']."_".$option_value.'" value="true" '.$checked.' class="depth-'.($option_list['depth']+1).'" />'.$option_list['title']."n";
        echo "</li>n";
    }
    echo "</ul>n";
    create_closing_tag();
}

This essentially goes through all options in the database with the “mnt_nav_pages_” prefix and identifies those pages that have been included, then marks them as “checked”. The option “mnt_nav_pages” itself has nothing in the database – only when used in conjunction with the option values is it populated. Even if you weren’t using a dynamic list, you would do the same thing. This code is reusable for any such array, with very minor tweaks.

If you were using the first approach of a SELECT element, you would store all the selections in a single option, “mnt_nav_pages” as a comma-separated list. You would then parse the list out and mark the appropriate elements as selected. This is easier to code, but the effort to maintain it on the UI is high.

Some Small Bells and Whistles


Let us define some headers as well, just to help us group the options better. We will also add a “category” and a “parent” for the purposes of grouping. The “category” will be defined for the group and the “parent” will be defined for every option in that group:

  • One for headers:
        array("name" => "Header Customization",
                "type" => "sub-section-3",
                "category" => "header-styles",
    	)
    
  • One for the body:
        array("name" => "Body Background Settings",
                "type" => "sub-section-3",
                "category" => "body-styles",
    	)
    
  • One for the navigation menu
        array("name" => "Navigation Bar Setup",
                "type" => "sub-section-3",
                "category" => "nav-setup",
    	)
    
  • One for the sidebar
        array("name" => "Sidebar Setup",
                "type" => "sub-section-3",
                "category" => "sidebar-setup",
    	)
    
  • And one for Analytics
        array("name" => "Analytics",
                "type" => "sub-section-3",
                "category" => "analytics-setup",
    	)
    

A function to handle these:

function create_suf_header_3($value) {
    echo '<h3 class="suf-header-3">'.$value['name']."</h3>n";
}

Putting it All Together


Now that we have the different pieces, let’s see how they fit. First we define a big array with all our options:

$options = array(
    array("name" => "Header Customization",
            "type" => "sub-section-3",
            "category" => "header-styles",
	),
    array("name" => "Header Image",
            "desc" => "Set the image to use for the header background. ",
            "id" => $shortname."_header_background_image",
            "type" => "text",
            "parent" => "header-styles",
            "std" => ""),
    array("name" => "Body Background Settings",
            "type" => "sub-section-3",
            "category" => "body-styles",
	),
    array("name" => "Body Background Color",
            "desc" => "Set the color of the background on which the page is. ",
            "id" => $shortname."_body_background_color",
            "type" => "color-picker",
            "parent" => "body-styles",
            "std" => "444444"),
    array("name" => "Sidebar Setup",
            "type" => "sub-section-3",
            "category" => "sidebar-setup",
	),
    array("name" => "Sidebar Position",
            "id" => $shortname."_sidebar_alignment",
            "type" => "radio",
            "desc" => "Which side would you like your sidebar?",
            "options" => array("left" => "Left", "right" => "Right"),
            "parent" => "sidebar-setup",
            "std" => "right"),
    array("name" => "Navigation Bar Setup",
            "type" => "sub-section-3",
            "category" => "nav-setup",
	),
    array("name" => "Pages to show in Navigation Bar",
            "desc" => "Select the pages you want to include. All pages are excluded by default",
            "id" => $shortname."_nav_pages",
            "type" => "multi-select",
            "options" => mnt_get_formatted_page_array($shortname."_nav_pages"),
            "parent" => "nav-setup",
            "std" => "none"),
    array("name" => "Analytics",
            "type" => "sub-section-3",
            "category" => "analytics-setup",
	),
    array("name" => "Custom Google Analytics Tracking Code",
            "desc" => "Enter your tracking code here for Google Analytics",
            "id" => $shortname."_custom_analytics_code",
            "type" => "textarea",
            "parent" => "analytics-setup",
            "std" => ""),
    );

We then create the function to go through this array and display the options as required. We also add buttons for save and reset. Since we have defined “categories”, we now have the flexibility to save / reset options for a particular category only. So we can create one form for each category. However we will tackle that later. For now we will simply provide a single form with a save and a reset button:

function create_form($options) {
    echo "<form method="post" name="form">n";
    foreach ($options as $value) {
        switch ( $value['type'] ) {
            case "sub-section-3":
                create_suf_header_3($value);
                break;

            case "text";
                create_section_for_text($value);
                break;

            case "textarea":
                create_section_for_textarea($value);
                break;

            case "multi-select":
                create_section_for_multi_select($value);
                break;

            case "radio":
                create_section_for_radio($value);
                break;

            case "color-picker":
                create_section_for_color_picker($value);
                break;
        }
    }
    echo "<input name="save" type="button" value="Save" class="button" onclick="submit_form(this, document.forms['form'])" />n";
    echo "<input name="reset_all" type="button" value="Reset to default values" class="button" onclick="submit_form(this, document.forms['form'])" />n";
    echo "<input type="hidden" name="formaction" value="default" />n";
    echo "</form>n";
}

This concludes the section on creating the options and writing the functions to handle them. The above code seems like a lot of work, but it is a one-time investment. If you have thought out your options well, then you can be up and running in a couple of days.

In the next section we will see how to Display, Save, Reset and Use the options.

  14 Responses to “WP Theme Options: Getting Started”

Comments (12) Pingbacks (2)
  1. Thanks for posting this. I was looking for a little more information about how to set up the options array and defining radio buttons etc. I have a post about using theme options with Thematic. Just linked you.

     
  2. Hi Sayontan,

    THANKS for this tutorial, I’m just starting to develop theme options. This you shared will definitely prove very helpful. I’m eagerly awaiting the remainder TUT on this subject.

    Thank You Kindley

     
  3. Just wanted to add my thanks too. Your choice of Google Analytics for an example was perfect; it’s the same problem I was trying to solve!

     
  4. This may be a dumb question, but for the color picker, where do you put the style tag? Would that also go in functions or the index?

     
  5. how do i create one form for each category with save and reset buttons ?

     
  6. Great tutorial, and love Suffusion! OK, kinda new to php & theme options here but muddling thru. 2 quick questions:
    1. How do I refer to (call) my list of pages to include from my header file if I use the multi-select code you’ve provided? Seems like I’ll need another function for that, yes? Any sample code available?
    2. It doesn’t appear my checkmarks are being saved to the DB when I click my save button (they display unchecked on reload after save); all my other fields load with their saved info. Is this normal behavior, or should the checkmarks be getting saved?
    Thanks for any help!

     
  7. hi bro youtube video player size is too big. How to reduce it??

     
  8. Thank you for this post. I have been struggling with creating themes, or heck even editing them on my website. I am going to practice with some of your tips here on one of my domains. Thanks for being clear and conside, and not blowing this non-techie out of the water.

     
  9. I got to this page as I’m just getting started with Suffusion, but I just wanted to say what a great WP Theme it is and what amazing help and info there is available here. Many, many thanks!