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:

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;"> </td></tr><tr><td colspan="2"> </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;"> </td></tr><tr><td colspan="2"> </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;"> </td></tr><tr><td colspan="2"> </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;"> </td></tr><tr><td colspan="2"> </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:
- Retrieve the options.
- Check if the disable box is checked. If it hasn’t, we…
- Check if a title was provided. If it was, we display it.
- Otherwise, we display a generic “Welcome!” title.
- Check if a message was provided. If it was, we display it.
- Otherwise, a generic message is used.
- 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:
Thanks for reading this tutorial and I hope it was useful. Look out for more WordPress-related articles here each week!





clarklab
October 28th, 2008
Excellent, been thinking about building an options page into my next theme. Great info to get me started.
Kieren
October 28th, 2008
Nice one Dan!
But I could of really done with this a few months ago when struggleing to create my first options page…
Ryan
October 28th, 2008
Thanks for the great write-up! This will definitely come in handy for the several in-development themes that I’m working on!
Jauhari
October 28th, 2008
Just Perfect Dan
Stefan Ashwell
October 29th, 2008
Great tutorial, definately a great idea to include with WP Themes!
Valentino Aluigi
October 30th, 2008
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?
Jauhari
October 31st, 2008
Why I can display the code on the front page themes. It’s only work on themes admin.
Please help
Jauhari
October 31st, 2008
Sorry. That I mean I can’t
I was add on thi header.php
But when I tried get the parameters, just got blank.
Please help
Valentino Aluigi
November 2nd, 2008
Jauhari, if you send me your files I can try to fix your problem (free, sure!)
Kyle
November 2nd, 2008
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.
Danh ba web 2.0
November 7th, 2008
Thanks for great tutorial. It’s very useful
Keep it up !
Yogi
November 11th, 2008
Thanks for the tutorial mate, really helpful for me. And hopefully I can add this kinda feature to all my WordPress themes.
Jamie Fehr
November 12th, 2008
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;
DDDepressionnn
November 20th, 2008
There has come winter

It became cold and cloudy!
Mood very bad
Depression Begins
DDDDepressionnnn
November 20th, 2008
Depression Depression Depression aaaaaaaa
:( 
HEEEEELP
I hate winter! I want summer!
Abe
December 28th, 2008
Thanks a lot Dan! Your intro paragraph described my situation perfectly and this article has saved me a lot of time
roman
January 10th, 2009
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!
Mishanya
January 14th, 2009
Privet, meny zovut Misha/. Hpchu vam predlogit kor chto novoe - заказать любительское порно отрезали косу изнасиловали фото анна сосет хуй
жестокое порно изнасилования фото
antareja
January 18th, 2009
great.. I will incorporate this lesson in my next website
Stu | Self Conlusion
January 24th, 2009
Fantastic! This has helped me so much for my nerdpress theme I am releasing soon! http://nerdpress.co.uk
Thank you so much!
Ali
January 27th, 2009
Very Good !!
qwik
February 18th, 2009
Is there a way to include a wyiswyg editor in the text area?
Erika
February 23rd, 2009
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?
ardee
February 24th, 2009
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…
Zack
February 25th, 2009
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.
Sayontan
February 25th, 2009
Wow! This is excellent! I am definitely going to use this.
michael austin
March 3rd, 2009
me likey. i always wondered how this was done.
Johnb
March 7th, 2009
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
Yustian
March 9th, 2009
Wow….. i think this’s once of the best article for developing wordpress themes. Once again i say thank for this.
MegaFill
March 11th, 2009
GoooooooD!!!
Karl
March 20th, 2009
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!
Adam Wolfs
March 24th, 2009
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!
Rahul Chowdhury
March 26th, 2009
Dude this is really cool. Its a great thing for managing a theme with much ease.
diekzo
March 27th, 2009
excellent, thanks allot.
RaiulBaztepo
March 28th, 2009
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
PiterKokoniz
April 7th, 2009
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
ccvid
April 14th, 2009
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.
Zowswotsmob
April 16th, 2009
nice, really nice!
steven
April 23rd, 2009
Hi, thanks for the tutorial! But does somebody knows a tutorial that shows you all the options you got with custom theme options?
Steven
Roger
April 26th, 2009
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.
Hiranthi
April 29th, 2009
the get_settings function is deprecated you should use the get_option function instead.
Steve
May 2nd, 2009
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
Matt
May 4th, 2009
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
Cosmin
May 11th, 2009
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)
michael soriano
May 21st, 2009
@Matt - make sure there are no spaces before . check lines 182 and 698
Fernanda Thiesen
May 25th, 2009
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.
valik
June 6th, 2009
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.
paul
June 7th, 2009
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.
Noel Nuguid
June 9th, 2009
Does this work with Wordpress 2.8?
FreewareMatter
June 10th, 2009
Very cool. Thank you for this article.
Jay
June 11th, 2009
Anyone know how to create a dropdown menu with the categories there work with version 2.8?
Daniel Groves
June 24th, 2009
4 weeks: 4 wordpress themes; man this is just in time!
CSS designer
June 24th, 2009
Thanks great article
ibibi
June 29th, 2009
How can I add localization to this?