Including a Theme Options page for your theme is one of the best ways to increase ease-of-use for managing a complex theme. However, a few quick Google searches later and most people give up. Such a great inclusion for theme design appears to have such little documentation, that it appears to be one of those heavily guarded secrets which only the crème de la crème of designers hold the key to.

In this article we will be incorporating an options panel for the ‘WordPress Classic’ theme. The methods you learn will allow you to very easily integrate it into an existing theme you’re working on.

Firstly, I’d like to give heaps of credit to this post at The Undersigned. A lot of the code used in this tutorial is from their post. I’m simply building on the foundation they provided - Thanks!

What we’ll be making is a section at the top of the ‘Classic’ WordPress theme to display a welcome message. This message will be customizable from an options page in the Dashboard:

Options Preview

Normally, the options page will look a mess and unstyled. However I’m sharing with you the code I use in my projects to give your page a very user-friendly look which also fits in well with the WordPress Dashboard.

The Back-End

Start of by opening the functions.php file in the /wp-content/themes/classic/ folder. The first two lines should be:

<?php if ( function_exists('register_sidebar') )

Above this, insert the following code to get started:

<?php
$themename = "WordPress Classic";
$shortname = "wpc";
$options = array (

You can set $themename and $shortname to whatever you like. The last line starts an array for all our options to go in.

array(    "name" => "Welcome Message",
        "type" => "title"),

array(    "type" => "open"),

array(    "name" => "Title",
        "desc" => "Enter a title to display for your welcome message.",
        "id" => $shortname."_welcome_title",
        "std" => "",
        "type" => "text"),

array(    "name" => "Message",
        "desc" => "Text to display as welcome message.",
        "id" => $shortname."_welcome_message",
        "type" => "textarea"),

array(  "name" => "Disable Welcome Message?",
        "desc" => "Check this box if you would like to DISABLE the welcome message.",
        "id" => $shortname."_welcome_disable",
        "type" => "checkbox",
        "std" => "false"),

array(    "type" => "close")

);

This is where we create the options to display. We are storing each option in an array so that we can insert them into a form later in the code. This saves on a lot of duplicated code. In each array, we use the following:

name - This is the title which will be displayed for this option.

desc - A description for the option.

id - This is very important. We will be using these to retrieve the option. $shortname gets replaced with whatever you set the shortname to (in our case wpc).

std - This is the ‘default’ setting for the option. For example on checkboxes we can use true or false to determine whether the box is pre-ticked or not.

type - This defines what type of option it is. For example, text, textarea, checkbox etc.

As you can see, we start with the title option. Then ‘open’ which is used for purely presentational purposes. It is used to simply open the table for our options (yeah, we’re using tables - so be sure to repent your sins!)

We next have a textbox for the title of our Welcome Message, followed by an textarea for the message itself. We then have a checkbox for disabling the welcome message, followed by ‘Close’ which simply closes any tags created by ‘open’.

And now for the rest of the code. Most of which is a bunch of WordPress functions to tell it this is an options page, so we wont go over most of it:

function mytheme_add_admin() {

    global $themename, $shortname, $options;

    if ( $_GET['page'] == basename(__FILE__) ) {

        if ( 'save' == $_REQUEST['action'] ) {

                foreach ($options as $value) {
                    update_option( $value['id'], $_REQUEST[ $value['id'] ] ); }

                foreach ($options as $value) {
                    if( isset( $_REQUEST[ $value['id'] ] ) ) { update_option( $value['id'], $_REQUEST[ $value['id'] ]  ); } else { delete_option( $value['id'] ); } }

                header("Location: themes.php?page=functions.php&saved=true");
                die;

        } else if( 'reset' == $_REQUEST['action'] ) {

            foreach ($options as $value) {
                delete_option( $value['id'] ); }

            header("Location: themes.php?page=functions.php&reset=true");
            die;

        }
    }

    add_theme_page($themename." Options", "".$themename." Options", 'edit_themes', basename(__FILE__), 'mytheme_admin');

}

function mytheme_admin() {

    global $themename, $shortname, $options;

    if ( $_REQUEST['saved'] ) echo '<div id="message" class="updated fade"><p><strong>'.$themename.' settings saved.</strong></p></div>';
    if ( $_REQUEST['reset'] ) echo '<div id="message" class="updated fade"><p><strong>'.$themename.' settings reset.</strong></p></div>';

?>
<div class="wrap">
<h2><?php echo $themename; ?> settings</h2>

<form method="post">

<?php foreach ($options as $value) {

Next is the code which tells WordPress how to display the ‘type’ of option used (title, open, close, text, textarea, checkbox etc.)

switch ( $value['type'] ) {

case "open":
?>
<table width="100%" border="0" style="background-color:#eef5fb; padding:10px;">

<?php break;

case "close":
?>

</table><br />

<?php break;

case "title":
?>
<table width="100%" border="0" style="background-color:#dceefc; padding:5px 10px;"><tr>
    <td colspan="2"><h3 style="font-family:Georgia,'Times New Roman',Times,serif;"><?php echo $value['name']; ?></h3></td>
</tr>

<?php break;

case 'text':
?>

<tr>
    <td width="20%" rowspan="2" valign="middle"><strong><?php echo $value['name']; ?></strong></td>
    <td width="80%"><input style="width:400px;" name="<?php echo $value['id']; ?>" id="<?php echo $value['id']; ?>" type="<?php echo $value['type']; ?>" value="<?php if ( get_settings( $value['id'] ) != "") { echo get_settings( $value['id'] ); } else { echo $value['std']; } ?>" /></td>
</tr>

<tr>
    <td><small><?php echo $value['desc']; ?></small></td>
</tr><tr><td colspan="2" style="margin-bottom:5px;border-bottom:1px dotted #000000;">&nbsp;</td></tr><tr><td colspan="2">&nbsp;</td></tr>

<?php
break;

case 'textarea':
?>

<tr>
    <td width="20%" rowspan="2" valign="middle"><strong><?php echo $value['name']; ?></strong></td>
    <td width="80%"><textarea name="<?php echo $value['id']; ?>" style="width:400px; height:200px;" type="<?php echo $value['type']; ?>" cols="" rows=""><?php if ( get_settings( $value['id'] ) != "") { echo get_settings( $value['id'] ); } else { echo $value['std']; } ?></textarea></td>

</tr>

<tr>
    <td><small><?php echo $value['desc']; ?></small></td>
</tr><tr><td colspan="2" style="margin-bottom:5px;border-bottom:1px dotted #000000;">&nbsp;</td></tr><tr><td colspan="2">&nbsp;</td></tr>

<?php
break;

case 'select':
?>
<tr>
    <td width="20%" rowspan="2" valign="middle"><strong><?php echo $value['name']; ?></strong></td>
    <td width="80%"><select style="width:240px;" name="<?php echo $value['id']; ?>" id="<?php echo $value['id']; ?>"><?php foreach ($value['options'] as $option) { ?><option<?php if ( get_settings( $value['id'] ) == $option) { echo ' selected="selected"'; } elseif ($option == $value['std']) { echo ' selected="selected"'; } ?>><?php echo $option; ?></option><?php } ?></select></td>
</tr>

<tr>
    <td><small><?php echo $value['desc']; ?></small></td>
</tr><tr><td colspan="2" style="margin-bottom:5px;border-bottom:1px dotted #000000;">&nbsp;</td></tr><tr><td colspan="2">&nbsp;</td></tr>

<?php
break;

case "checkbox":
?>
    <tr>
    <td width="20%" rowspan="2" valign="middle"><strong><?php echo $value['name']; ?></strong></td>
        <td width="80%"><? if(get_settings($value['id'])){ $checked = "checked=\"checked\""; }else{ $checked = ""; } ?>
                <input type="checkbox" name="<?php echo $value['id']; ?>" id="<?php echo $value['id']; ?>" value="true" <?php echo $checked; ?> />
                </td>
    </tr>

    <tr>
        <td><small><?php echo $value['desc']; ?></small></td>
   </tr><tr><td colspan="2" style="margin-bottom:5px;border-bottom:1px dotted #000000;">&nbsp;</td></tr><tr><td colspan="2">&nbsp;</td></tr>

<?php         break;

}
}
?>

Basically, if the ‘type’ is text, we display a textbox with the title and desc tags next to it. The same goes for each of the others.

Note that we are using tables and inline-styling. Seriously, repent your sins ;)

Next is the final piece of code for the options page. It displays ‘Submit’ and ‘Reset’ buttons. At the end is the final code to tell WordPress to add this as a page in the Admin Dashboard.

<p class="submit">
<input name="save" type="submit" value="Save changes" />
<input type="hidden" name="action" value="save" />
</p>
</form>
<form method="post">
<p class="submit">
<input name="reset" type="submit" value="Reset" />
<input type="hidden" name="action" value="reset" />
</p>
</form>

<?php
}

add_action('admin_menu', 'mytheme_add_admin'); ?>

So that’s the Options page done. Test it out by enabling the Classic theme if you haven’t already, and going to Design -> WordPress Classic Options.

Making Use of the Options

Now that we’ve made the options page, we need to make them do something. For this, open header.php.

What we’ll be doing is:

  1. Retrieve the options.
  2. Check if the disable box is checked. If it hasn’t, we…
  3. Check if a title was provided. If it was, we display it.
  4. Otherwise, we display a generic “Welcome!” title.
  5. Check if a message was provided. If it was, we display it.
  6. Otherwise, a generic message is used.
  7. Finally, if the box was checked, we display nothing.

1. Retrieve Options

At the bottom of your header.php page, type the following

<?
global $options;
foreach ($options as $value) {
    if (get_settings( $value['id'] ) === FALSE) { $$value['id'] = $value['std']; } else { $$value['id'] = get_settings( $value['id'] ); }
}
?>

The above retrieves our options and places them in a variable for us to reference. The options are now avaliable as:

$wpc_welcome_disable

$wpc_welcome_title

$wpc_welcome_message

2. Check the ‘Disable’ box

<?
if ($wpc_welcome_disable == "false") { ?>

A checkbox will return “false” if unchecked, and “true” is checked. The next code we enter will only be processed if the checkbox is returning false.

3. Check a title was provided & display it

<?
if ($wpc_welcome_title) { ?>
<h4><? echo $wpc_welcome_title; ?></h4>

Here we check if there was something entered for the Title. Then display it (echo) inside H4 tags.

4. Otherwise, display a generic title

<? } else { ?>
<h4>Welcome!</h4>
<? } ?>

If there isn’t a title (else), we display a simple “Welcome” title.

5 & 6. Check a message was provided. Display it. Otherwise, generic.

<? if ($wpc_welcome_message) { ?>
<p><? echo $wpc_welcome_message; ?></p>
<? } else { ?>
<p>Hello and welcome to our site. We hope you enjoy your stay!</p>
<? } ?>

The above code uses the same methods as in the previous steps, but uses $wpc_welcome_message instead.

7. If the box was checked, display nothing

<? } else { ?>

    <!-- You could insert something here which will display when the box IS checked. -->

<? } ?>

If the box was checked, the above is processed - in our case, just a HTML comment. Ideally, you can just use the last line.

Summary

And there you have it! While the actual options we created are very simplistic, you can use the very same techniques to create a much more robust page.

For example, here is a part of the options page for my GamePress theme:

GamePress Options

Thanks for reading this tutorial and I hope it was useful. Look out for more WordPress-related articles here each week!

/* Download Complete Source Files */

Comments

Leave a Comment
  1. Excellent, been thinking about building an options page into my next theme. Great info to get me started.

  2. Nice one Dan!

    But I could of really done with this a few months ago when struggleing to create my first options page…

  3. Thanks for the great write-up! This will definitely come in handy for the several in-development themes that I’m working on!

  4. Just Perfect Dan ;)

  5. Great tutorial, definately a great idea to include with WP Themes!

  6. I suggest to use this technique to change the css. Look at the the original post for instructions on how to create a style.php file.

    Anyway, I used this technique in my template and it’s great!
    But implementing a multi-checkbox option was a real pain…
    Wouldn’t it be great if someone writes a library for common options type?

  7. Why I can display the code on the front page themes. It’s only work on themes admin.

    Please help

  8. Sorry. That I mean I can’t :(

    I was add on thi header.php

    <?
    global $options;
    foreach ($options as $value) {
    if (get_settings( $value['id'] ) === FALSE) { $$value['id'] = $value['std']; } else { $$value['id'] = get_settings( $value['id'] ); }
    }
    ?>

    But when I tried get the parameters, just got blank.

    Please help

  9. Jauhari, if you send me your files I can try to fix your problem (free, sure!)

  10. This tutorial was a huge help! I’ve got it working, but I have a small problem and I was hoping someone could help. Everything on the backend is working perfectly and it’s saving all of my values, the problem comes when I want to display those values on any page other than header.php or index.php. I have a workaround for now by adding that same code you add to header.php to any file that has a call to one of the values (i.e. within single.php I’m trying to call $ksuchallenge_single_intro_para, so I have to add the “header code” from this tutorial to that template file to make it work).

    I’m a PHP beginner, but if I had to guess I would say it has to do with the order PHP executes things. I think the “header code” is running before the includes are and so it doesn’t know about the $options variable yet. So what I need is some way of globally declaring the options variable before any other process is executed on the server. Or, maybe a method to cache the values stored in $options until they are changed?

    As you can imagine, those extra array formulations take up a bit of loading time that I’d like to cut out. Does anyone know how to fix this?

    Here’s my functions.php code, but I honestly don’t think the problem can be fixed there.

    http://pastie.org/306225

    Thanks for the help.

  11. Thanks for great tutorial. It’s very useful
    Keep it up !

  12. Thanks for the tutorial mate, really helpful for me. And hopefully I can add this kinda feature to all my WordPress themes.

  13. You didn’t cover it in your excellent and most informative tutorial but I when I tried to use a select list I had a problem getting the correct option highlighted.

    The problem was that the code you have makes it possible to have two options selected.

    Sample select item

    array("name" => __("Select", "ThemeDomain"),
    "desc" => __('A list to select from.', 'ThemeDomain'),
    "id" => $shortname."_some_option",
    "options" => array('One', 'Two', 'Something else'),
    "std" => "Something else",
    "type" => "select"),

    In the loop if the save option and the default are different they both will get highlighted, so I added a variable outside the loop to determine if the option did already come out of the database and if so not select the default option. It looks like this.


    case 'select':
    ?>

    <label for="">

    <select name="" id="">

    <option>

    <?php
    break;

  14. Gravatar

    DDDepressionnn

    There has come winter :(
    It became cold and cloudy!
    Mood very bad :(
    Depression Begins

  15. Gravatar

    DDDDepressionnnn

    Depression Depression Depression aaaaaaaa
    HEEEEELP :( :( :(
    I hate winter! I want summer!

  16. Thanks a lot Dan! Your intro paragraph described my situation perfectly and this article has saved me a lot of time

  17. Hi!
    very nice and simple, but I have Big problem with it in Wordpress mu, can you help me why it do not work and actually i even can not take these modifications back, what i should to do? my whole blog is in mess becouse of it. I always get error message prom functions.php and plugable.php that headers are allready send, and i get it I am editing whatever in my wp-admin.
    Thanks for advice!

  18. great.. I will incorporate this lesson in my next website

  19. Fantastic! This has helped me so much for my nerdpress theme I am releasing soon! http://nerdpress.co.uk

    Thank you so much!

  20. Very Good !!

  21. Is there a way to include a wyiswyg editor in the text area?

  22. I ran into the same problem as Jauhari above - I can tell that the parameters are passing because the “generic” statements aren’t coming through, but for some reason I can’t get the actual content to come through. Anyone have any suggestions?

  23. To Qwik: I’ve ever make that in my site comment form… I use NicEdit… a small and less scripting (and also instant) wysiwyg editor that work in your frontend…

  24. Great tutorial, I’ve been looking for this for a long time. Thank you very much, I am going to add some options to my themes.

  25. Wow! This is excellent! I am definitely going to use this.

  26. me likey. i always wondered how this was done.

  27. I finally got it to work. My output wasn’t showing up. My solution was to NOT put that chunk of php code in the header.php file. I put that code at the top of all my other pages instead. Now it works! Hopes this helps others who had the same problem as me!

    John

  28. Wow….. i think this’s once of the best article for developing wordpress themes. Once again i say thank for this.

  29. GoooooooD!!!

  30. Great, thanks for this, I’d been wondering if adding options to a theme was easy or not.. when making custom themes for clients, it’s really useful to be able to offer just a few specific input areas and choices.

    Thanks for the clear write-up!

  31. Dude you are a legend! I implemented the code, and customized with very little issue whatsoever.

    The only thing i would like to know, is with the new version of word press, how i could set it to me it’s own section of the admin menu like woo themes does it.

    But honestly, spectacular!

  32. Dude this is really cool. Its a great thing for managing a theme with much ease.

  33. excellent, thanks allot.

  34. Gravatar

    RaiulBaztepo

    Hello!
    Very Interesting post! Thank you for such interesting resource!
    PS: Sorry for my bad english, I’v just started to learn this language ;)
    See you!
    Your, Raiul Baztepo

  35. Hi !!! ^_^
    I am Piter Kokoniz. oOnly want to tell, that I like your blog very much!
    And want to ask you: is this blog your hobby?
    Sorry for my bad english:)
    Thank you:)
    Your Piter Kokoniz, from Latvia

  36. Use CCViD share-this blog widget at your blog. Using this blog widget you can easily allow your users to share your article.

    http://www.ccvid.com/apps/share-this/get-code.php

    If you are a new blogger, then its must for you. Just add it to your blog, and see how your blog gets more traffic.

  37. nice, really nice!

  38. Hi, thanks for the tutorial! But does somebody knows a tutorial that shows you all the options you got with custom theme options?

    Steven

  39. Found a solution to the variable scope problem. Just use the php include instead of the wordpress function to include the php files. Like:

    Another solution is to create your own include function in functions.php like this (found on php.net).


    function safeinclude($filename) {
    //This line takes all the global variables, and sets their scope within the function:
    foreach ($GLOBALS as $key => $val) { global $$key; }
    /* Pre-Processing here: validate filename input, determine full path
    of file, check that file exists, etc. This is obviously not
    necessary, but steps I found useful. */
    if ($exists==true) { include("$file"); }
    return $exists;
    }

    To use the variables in functions.php, just define them as global.

  40. the get_settings function is deprecated you should use the get_option function instead.

  41. Hi,

    Excellent tutorial - worked like a charm! I just have one quick query: How would I go about adding the option to allow users to enter their Google Analytics code, or anything else that would require the user to enter single or double quotes. The reason I ask is because whenever I input anything into the textarea and hit save in the options area, those backwards slashes turn up in front of the quotes, ie: a href=\”link.html\”

    And this is breaking the code for me. How would I go about fixing this? If anyone could help then I would be forever grateful. I’ve tried toying with “htmlspecialchars” but sadly I’m not quite as PHP-savy as I might like to be.

    Cheers,
    Steve

  42. This doesn’t work at all for me, I keep getting the following error:

    Warning: Cannot modify header information - headers already sent by (output started at /nfs/c03/h02/mnt/52292/domains/staging.thepsdcoder.com/html/wp-content/themes/classic/functions.php:182) in /nfs/c03/h02/mnt/52292/domains/staging.thepsdcoder.com/html/wp-includes/functions.php on line 698

  43. I know he’s competition, but damn, has anyone seen the options panel for the eBusiness Theme from Elegant Themes? I have a subscription there, and when I installed it to test it, I was left mouth open…

    That is soooo cool…to bad it’s very very hard to create custom admin panels for themes :| (hard if you don’t know php)

  44. @Matt - make sure there are no spaces before . check lines 182 and 698

  45. Thanks for the great tutorial! I would like to suggest you create a tutorial about how to add a stylesheet theme switcher one the theme so the users can switch the css while browsing a theme demo.

  46. Nice article!! Hey does anyone know how to make wordpress take you right to this options page right after this theme is activated? So to make the user have to go and set the options first before anything else is done. Thanks.

  47. i have been using this, but once you start to use it all over a site, you need to run the code to get the options in each file your using, which (i think) means more http requests. is there a way of using the same code but assigning a $_session variable instead?

    so $$value['id'] would be $_session[$$value['id']], which doesnt work, and thats where im stuck.

  48. Does this work with Wordpress 2.8?

  49. Very cool. Thank you for this article.

  50. Anyone know how to create a dropdown menu with the categories there work with version 2.8?

  51. 4 weeks: 4 wordpress themes; man this is just in time!

  52. Thanks great article

  53. How can I add localization to this?

Add a Comment

Name Email Website

Note: The avatars shown next to comments are Gravatars. You can get a Gravatar account for free and any other site that supports it will show your avatar too!

 

Trackbacks

Leave a Trackback