As I’ve worked more on my theme and increased my coding skills I’ve added to my original theme option framework. I’ve become more aware of best practices of coding and WordPress, a big issue with the original framework was the way options were added to the wp_options database table. Each theme option got it’s own entry in the table, this might be okay for small theme, but I’ve grown to over 40 different options in my Techozoic theme. It was time to optimize, with the new framework the entries added to the wp_options table went from 40 to 2. I’ll continue below with code examples and explanations. As an added bonus I’ve included an example of how to pull your theme options into a external stylesheet, based off of this concept.
Here is the updated framework files:
After you have the controlpanel.php file uploaded to your server into your theme’s main directory you’ll need to add this line to your functions.php file
[php light=”true”]<?php require_once(TEMPLATEPATH . ‘/controlpanel.php’); ?>[/php]
Now you’ll need to start editing the array values to add your options. The way you add options to the framework is still the same following the below templates.
[php]
$options = array (
array( "name" => "Radio Selection Set",
"desc" => "This is a descriptions",
"id" => $shortname."_radio",
"type" => "radio",
"std" => "3",
"options" => array("3", "2", "1")),
array( "name" => "Text Box",
"desc" => "This is a descriptions",
"id" => $shortname."_text_box",
"std" => "Some Default Text",
"type" => "text"),
array( "name" => "Bigger Text Box",
"desc" => "This is a descriptions",
"id" => $shortname."_bigger_box",
"std" => "Default Text",
"type" => "textarea"),
array( "name" => "Dropdown Selection Menu",
"desc" => "This is a descriptions",
"id" => $shortname."_dropdown_menu",
"type" => "select",
"std" => "Default",
"options" => array("Default", "Option 1", "Option 2")),
array( "name" => "Checkbox selection set",
"desc" => "This is a descriptions",
"id" => $shortname."_checkbox_menu",
"type" => "checkbox",
"std" => "Default",
"options" => array("Default", "Option 1", "Option 2")),
array( "name" => "Multiple selection box",
"desc" => "This is a descriptions",
"id" => $shortname."_multi_select_dropdown_menu",
"type" => "multiselect",
"std" => "Default",
"options" => array("Defaults", "Option 1s", "Option 2s"))
);
[/php]
Another new feature I’ve added is a theme init script. It’s useful for adding default values to the wp_options table. This code will also pull values already in separate wp_options entries and put them into the single array wp_option, then delete the old entries. Then the code sets a separate value in the wp_options table as a check so the script will only run if it doesn’t find that value. Then the function is added to the dashboard and main page header via the action hook. So the first time any visits a page in the dashboard or on the blog the mytheme_add_options will run, but only the first time.
[php]
function mytheme_add_options() {
global $themename, $shortname, $options;
foreach ($options as $value) {
$key = $value[‘id’];
$val = $value[‘std’];
if( $existing = get_option($key)){
$new_options[$key] = $existing;
delete_option($key);
} else {
$new_options[$key] = $val;
delete_option($key);
}
}
add_option($shortname.’_options’, $new_options );
}
function first_run_options() {
global $shortname;
$check = get_option($shortname.’_activation_check’);
if ( $check != "set" ) {
mytheme_add_options();
add_option($shortname.’_activation_check’, "set");
}
}
add_action(‘wp_head’, ‘first_run_options’);
add_action(‘admin_head’, ‘first_run_options’);
[/php]
After you have your option page the way you like you’ll need some way of get the variables onto other pages of you theme. You’ll need to add these next few lines to every page on which you plan to use the theme variables. Then the variables will be called like an array with the key being the option id.
[php light=”true”]
<?php
global $shortname;
$settings = get_option($shortname.’_options’);
// Options are called like this $settings[‘option_id’];
?>
[/php]
Now you can use the variables on this page. The variables will look like this let’s assume you set $shortname = “theme”, then your variables will look like this $theme_radio, $theme_text_box, $theme_bigger_box, $theme_dropdown_menu. Also keep in mind that you can add one than one of any kind of element, you can also rename any of the elements for easier variable management. Where “id” => $shortname.”_radio”, is defined you can change the _radio part to reflect what the option is actually for. To check the value of your multiple selection or checkbox variables you’ll need to use this. Where Item is the value that your checking that is selected or checked.
[php light=”true”]
<?php
if(in_array("Item",$settings[‘theme_checkbox’]));
?>
[/php]
Now I’ll show how to use your theme options on an external stylesheet rather than placing them in the head of the theme, which is bad web practice. It also has the added benefit of the page being cached by the browser so it will also save on bandwidth.
[php]
<?php
global $options, $shortname;
$settings = get_option($shortname.’_options’);
//Options will be called like this $settings[‘shortname_option_name’]
<head>
<link rel="stylesheet" type="text/css" media="screen" href="<?php bloginfo(‘home’) ?>/?css=css"/>
<?php
if ( is_singular() ) wp_enqueue_script( ‘comment-reply’ );
wp_head(); ?>
</head>
[/php]
This code uses something called a query variable that is registered in the functions.php file like shown below to call the style.php file and allow it to use WordPress builtin functions for calling options. Much cleaner and safer than the $_GET method I used earlier.
[php]
<?php
function add_new_var_to_wp($public_query_vars) {
$public_query_vars[] = ‘css’;
return $public_query_vars;
}
function dynamic_css_display(){
$css = get_query_var(‘css’);
if ($css == ‘css’){
include_once (TEMPLATEPATH . ‘/style.php’);
exit;
}
}
add_filter(‘query_vars’, ‘add_new_var_to_wp’);
add_action(‘template_redirect’, ‘dynamic_css_display’);
?>
[/php]
This registers the query variable called css and if that variable is set to css as it is when the stylesheet is called in the header with the ?css=css appended to the end then the style.php file is included then the everything else is stopped with the exit in the code.
[php]
<?php
global $shortname;
header(‘Content-type: text/css’);
header("Cache-Control: must-revalidate");
$offset = 72000 ;
$ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
header($ExpStr);
$settings = get_option($shortname.’_options’);
// Variables should be added with {} brackets
echo <<<CSS
/*Style Sheet Start*/
body {
background-color: {$settings[‘theme_option_color’]};
}
CSS;
//More php can go here
echo <<<CSS
/*Style Sheet End*/
CSS;
?>
[/php]
The style.php file can now use the WordPress function get_option for retrieving options from the database. Once this is done then the option variables will be called as an array with the option id being the key ie: $settings[‘theme_option_color’]
Update
I’ve had a request for adding an upload form to the options page for adding a custom header image. I’ve done this same thing in my Techozoic theme, if you would like to look at it to see a practical use of it you can download it here. Basically you’ll need to add a separate file to process the uploaded files, and the form to upload the files. An example upload file can be downloaded here. Then the form can be added to the options page with this code.
[php light=”true”]
<form enctype="multipart/form-data" encoding="multipart/form-data" action="<?php bloginfo(‘template_directory’) ?>/upload.php" method="post">
<input type="file" name="file" /><br />
<input type="submit" name="submit" value="Upload" />
</form>
[/php]
You just need to upload the file and make sure it’s in the root of your theme directory and named upload.php. You can also edit the upload.php file to change the restrictions on file size and file type. I’ve set the upload.php file to only accept jpg, gif, and png files under 1 MB which should be fine for uploading header images.

By RJ February 10, 2010 - 1:02 am
Hey Jeremy,
I’ve tried running v2 of your theme framework, and running into what seems an odd error. After just copying the cp.php into my folder and making absolutely no changes, I’ve tried to go into the theme options on my xampp install. For some reason, the arrays are looping 3-6 times (I didn’t count exactly, sorry). I’m not as versed in loops as I’d like to be, so I can’t troubleshoot here. Should I have included the additional files in the zip folder?
v1 doesn’t do this continuous loop, so I’m not certain what’s up here. I just wanted to let you know here.
Thanks for providing such a valuable resource. The theme that I’ve been working on for some friends needs a lot of optioning, and rather than have them hard-code the changes (which they’re entirely capable of), it’s easier to provide them an option to do it in the admin area.
By Jeremy Clark February 10, 2010 - 8:22 am
Alright I spotted the problem, I was updating the old version I had and for some reason I added a second loop before the original loop. I’ve updated the download with the corrected script if you would like to download again and give it a try. Hope this helps you out.
By Zach February 24, 2010 - 9:17 am
Would an upload function be possible? For custom headers, etc. Thanks!
By Jeremy Clark February 24, 2010 - 10:26 am
I’ve updated the post with how to do this.
By Zach February 25, 2010 - 4:03 pm
Will definitely give it a shot, thank you so much!
By Zach February 25, 2010 - 4:20 pm
Jeremy,
I downloaded that template and also took a look at the upload.php and I believe I understand the logic behind how this works – would I need to create a separate upload.php for every other type of ‘upload’ element I would have in my template though?. I guess I’m a little confused on the actual display of some of these text/select/radio options. I had been looking at http://www.aquoid.com/news/tutorials/wordpress-theme-options/w-theme-options-setting-and-retrieving/ and that seemed to be what I was looking for, but I wanted the ‘upload image’ option simliar to how WooThemes (http://www.woothemes) does it. Sorry if I’m being confusing and asking for a lot, I just really enjoy using WordPress and would love to learn more about Theme Option pages. I really appreciate it. Thanks!
By Jeremy Clark February 28, 2010 - 10:31 am
I use the same logic in that aqoid.com uses saving and retriving options from one field in the wp_options table. As far as the upload element if you have one than one place that you would like something saved to then you’ll have to create a different upload file with the path set for each in the file. To display an option you just need to copy and edit the right array block that has the right type then just edit the array values and the other coding in the controlpanel.php file handles looping through the array and displaying the option form. I’ll contact you through email and see if I can help more.
By wpnewbie March 8, 2010 - 6:27 pm
the code to get the theme variables on the page doesn’t work for me 🙁 i get the following error
Warning: Invalid argument supplied for foreach()
By Jeremy Clark March 9, 2010 - 12:18 pm
I’ve updated the post now to reflect some changes that I was made aware of recently. See if it works for you now.
By wpnewbie March 9, 2010 - 12:35 pm
Thanks for the great tutorial Jeremy it works fine now
By wpnewbie March 9, 2010 - 2:10 pm
Rather than add the code to the top of every page i created a custom function to get the options value here’s the code
function theme_get_option($name) {
global $shortname;
$options = get_option($shortname.’_options’);
if (isset($options[$name])) {
return $options[$name];
} else {
return false;
}
}
then i can call it anywhere on my theme pages like so
theme_get_option(‘themeShortName_text_box’);
is this a better way ?
By Jeremy Clark March 9, 2010 - 2:48 pm
Since WordPress caches get_option calls it is a perfectly good way of getting the options.
By wpnewbie March 9, 2010 - 8:13 pm
how can i check if a single check box returns true or false and check the box accordingly instead of multi check boxes ?
By Jeremy Clark March 9, 2010 - 8:37 pm
The way the code works now it should work fine for single checkbox. Whenever your specifying the checkbox only give one option. You can use the isset php function to check if the option has been set or not on other wordpress pages.
By wpnewbie March 10, 2010 - 10:15 am
i can’t get a single check box working i have tried isset also it shows the word Default at the side of the check box but i would like no options but just a check box to return true or false or maybe on or off is it possible to add this featured ? i created a section like
elseif ($value[‘type’] == “checkbox2”) {
code here for check box
}
and added another option for checkbox2 however i could not get it to return true or false 🙁 help is much appreciated
By wpnewbie March 10, 2010 - 12:33 pm
Forget my last comment and once again thanks for the tutorial i managed to solve it by checking if the value is empty like so
if (!empty($settings[‘theme_image_slider’])) {
include(TEMPLATEPATH . ‘/slider.php’);
}
By Gilad March 12, 2010 - 2:29 pm
Wonderful! Worked as described upon first attempt! (A rarity for me lately…)
Two questions:
1. How can I create admin pages (using your framework) in a completely new/separate/dedicated node in the admin menu? In other words, instead of having a single new admin page show under the “Appearance” node, I’d like to have a new node (perhaps something like “Snazzy Control Panel”), with several pages under that node (perhaps something like “Layout”, “Style”, and “Advertising”).
2. Is this framework a deliverable you plan on maintaining in the long term? If so, should I be checking some other or additional addresses to keep updated?
Thanks!
Gilad
By Jeremy Clark March 13, 2010 - 7:53 am
1. You’ll have to use add_menu_page and add_submenu_page. I’ve never done it before, but you should just be able to replace the add_submenu_page with add_menu_page function in the controlpanel.php file you downloaded. You’ll also need to create a separate function for each of the submenu pages. Here is the reference for admin menus in WordPress. http://codex.wordpress.org/Adding_Administration_Menus
2. If I update the framework it will be on my blog here, I’ll also put a link on this page to the new version, so you could subscribe to the main blog feed.
By Gilad March 14, 2010 - 1:41 pm
Thank you, Jeremy!
I have it working (mostly). I’ll have to work on elegance later, though… 🙂
As you advised, I converted
—> add_theme_page($themename.” Options”, “Current Theme Options”, ‘edit_themes’, basename(__FILE__), ‘mytheme_admin’);
to
—> add_menu_page($themename.” Options”, “Current Theme Options”, ‘edit_themes’, basename(__FILE__), ‘mytheme_admin’);
Question: Any idea why focus always returns to the “Appearance” menu/node after I submit changes? This seems to happen both when I use only the above changes to create the independent node, as well as when I add subpages. Obviously, I would prefer focus remain with this menu/node.
Thanks again!
Gilad
By Jeremy Clark March 15, 2010 - 9:29 am
Yes you’ll also need to change the code that sets the header location after saving the file. Lets assume you keep the name of the control panel file controlpanel.php. Your php header function should look like these.
header("Location: admin.php?page=controlpanel.php&reset=true") header("Location: admin.php?page=controlpanel.php&saved=true")By Tod April 15, 2010 - 8:48 pm
Hi Jeremy. I have a question about including the upload feature. You wrote:
“An example upload file can be downloaded _here_. Then the form can be added to the options page with this code.”
So I have pasted upload.php into the root of my theme (same level where controlpanel.php is sitting). However, I’m unsure where to insert the form code (which starts with “form enctype=”multipart/form-data”…etc). When I opened Techozoic Fluid to see where you put it there, I see it’s inside header-admin.php. This wasn’t mentioned in the above tut, so I’m somewhat confused.
The only custom admin files I have are controlpanel.php and now upload.php. So I’m guessing it needs to go in controlpanel.php, but how? Could you please describe how to insert said code?
By Tod April 15, 2010 - 9:14 pm
Update: I found a good place to insert: search controlpanel.php for this line:
table class=”optiontable”
Paste upload form code below it with whatever additional layout markup you may like.
By Jeremy Clark April 15, 2010 - 9:43 pm
Glad you figured it out, sorry I wasn’t clear enough in the guide. Since I’ve written this guide I’ve updated my Techozoic Fluid theme with a different code for uploads instead of the separate file it’s actually included in the code for when options are saved, a much more complicated way but cleaner for my purposes.
By Ed Nailor April 19, 2010 - 11:03 am
Jeremy,
I love the code, and am working to implement this. I am running across an issue, and need urgent help.
In the text input, I am needing the ability to allow HTML characters, such as quotes. One of the options I am wanting to use if for font family, in which one would need quotes for specific fonts, e.g “Trebuchet MS”
I have been able to get this to work in the options page for the theme using html_entity_decode in the array for the default, and a combination of stripslashes(htmlentities()) to display the stored information back in the input box properly when updated. However, when used in the CSS sheet, I am getting slashes in front of the quotation marks, and can not seem to figure out how to remove them. I tried to use stripslashes, but that got me nowhere. Any ideas?
Thanks
Ed
By Jeremy Clark April 20, 2010 - 8:39 am
The beauty of working with the get_option and update_option functions are that they automatically escape characters and really the only one to worry about is the quote since it’s stored in a serialized array, it will store everything else fine.
Another thing to think about and this is what I do just put a list of all the “web safe” fonts in a dropdown box and when you call it in the CSS just wrap the php variable with quotes then.
By Hernan Silva July 22, 2010 - 5:42 am
Ed,
you can workaround this and make your code cleaner inserting the following code inside your functions.php file:
if ( get_magic_quotes_gpc() ) {
$_POST = array_map( 'stripslashes_deep', $_POST );
$_GET = array_map( 'stripslashes_deep', $_GET );
$_COOKIE = array_map( 'stripslashes_deep', $_COOKIE );
$_REQUEST = array_map( 'stripslashes_deep', $_REQUEST );
}
This is a good practice stated in a wordpress codex page: http://codex.wordpress.org/Function_Reference/stripslashes_deep
Hope it works for you, it worked for me 🙂
By Taragh April 20, 2010 - 7:35 am
I just want one theme option, a text box. I’ve followed everything clearly and got the admin page working. Now I don’t understand how to get it to display on my page (home.php). Below is not working. Guess it’s how I am writing this bit $hom_text_box; Any advice greatly appreciated? (Designer, rather than programmer)
By Taragh April 20, 2010 - 7:37 am
global $shortname;
$settings = get_option($shortname.’_options’);
// Options are called like this $settings[‘option_id’];
$theme_text_box;
By Jeremy Clark April 20, 2010 - 8:33 am
To call the option it will have to bee in this format:
$settings[‘theme_text_box’];
If you just want to show the value you just use echo:
echo $settings[‘theme_text_box’];
By Taragh April 21, 2010 - 12:16 pm
Thank you. That worked perfectly.
By Tod April 21, 2010 - 5:30 pm
2 brief questions:
I’m setting this up for image width. My array in controlpanel.php looks like this:
—————————————————————————–
array( “name” => “Image width”,
“desc” => “Enter the image’s width.”,
“id” => $shortname.”m_width”,
“std” => “137”,
“type” => “text”
),
—————————————————————————–
style.php looks like this:
—————————————————————————–
.first_li span {
background: transparent url(‘path/image.png’) no-repeat;
width: px;
height: 62px;
top: -87px;
left: -40px;
}
—————————————————————————–
The css works fine, but the php variable for ‘m_width’ isn’t being recognized.
What am I missing here?
*************************************************************
*************************************************************
Also, how do you handle a second set of options? ie: 2 seperate arrays?
—————————————————————————–
$options = array (
/* Image #1. Option: Image Width. */
/* This is the option for TEXT BOX. */
array( “name” => “Image width”,
“desc” => “Enter the image’s width.”,
“id” => $shortname.”m_width”,
“std” => “137”,
“type” => “text”
),
/* Image #1. Option: Image Height. */
/* This is the option for TEXT BOX. */
array( “name” => “Image height”,
“desc” => “Enter the image’s height.”,
“id” => $shortname.”m_height”,
“std” => “62”,
“type” => “text”
)
);
$options2 = array (
/* Image #2. Option: Image Width. */
/* This is the option for TEXT BOX. */
array( “name” => “Image width”,
“desc” => “Enter the image’s width.”,
“id” => $shortname.”m_width”,
“std” => “132”,
“type” => “text”
),
/* Image #2. Option: Image Height. */
/* This is the option for TEXT BOX. */
array( “name” => “Image height”,
“desc” => “Enter the image’s height.”,
“id” => $shortname.”m_height”,
“std” => “82”,
“type” => “text”
)
);
Image #1
:
<input name="” id=”” type=”” value=”” size=”40″ />
Image #2
:
<input name="” id=”” type=”” value=”” size=”40″ />
—————————————————————————–
By Jeremy Clark April 21, 2010 - 10:20 pm
Whenever you call the variable on the style.php keep in my that the id also has the $shortname in front so the id would be $settings[‘mouseoverm_width’]. Instead of two array just use one and append a number to the end of all the second options. So “id†=> $shortname.â€m_widthâ€, would become “id†=> $shortname.â€m_width_2â€. This makes saving options much easier as you don’t have to duplicate code for saving the second option array.
By Tod April 21, 2010 - 5:31 pm
Hm, not so brief. Didn’t all fit. 😉
By Karl April 29, 2010 - 11:19 am
Hi Jeremy
I have an options page and i want to add multiple upload forms, how do i go about it using the upload file?
By Jeremy Clark April 29, 2010 - 11:32 am
You could just create multiple copies of the upload.php file changing the directory in the upload.php file then when inserting the form in the action section where upload.php is called just use the name of the file with the correct directory. This is probably the easiest way but not necessarily the best way.
You could also use a hidden field in the form to specify the directory and in the upload.php file look for that field being submitted.
By Michelle May 2, 2010 - 10:58 pm
Hi Jeremy, thanks so much for this tutorial, it’s very helpful in my project. I will credit you when I finish it! I’m just having one problem. When I try to use this code:
I get this error: Warning: in_array(): Wrong datatype for second argument
(Of course, I’ve replaced “Item” and the theme name/option name with my own names)
Any idea why this might happen?
By Michelle May 2, 2010 - 11:00 pm
The comment ate my PHP code. It was this:
Hi Jeremy, thanks so much for this tutorial, it’s very helpful in my project. I will credit you when I finish it! I’m just having one problem. When I try to use this code (I took away the PHP tags, but imagine they’re there)
if (in_array(“Item”,$settings[‘theme_checkbox’])) { ….do something… };
I get this error: Warning: in_array(): Wrong datatype for second argument
(Of course, I’ve replaced “Item” and the theme name/option name with my own names)
Any idea why this might happen?
By Jeremy Clark May 3, 2010 - 8:57 am
Glad you found it helpful, I’ve run into this problem myself. It took me awhile to figure it out as well, but it was very simple once I found the problem. Basically when multiple checkboxs or multiselect boxes are chosen and the data posted is an array the code then coverts it into a single string separated with commas with implode before saving options. So all you need to to is explode it before running the in_array test. Something like this would work.
$theme_checkbox_array = explode(‘,’, $settings[‘theme_checkbox’]);
if (in_array(“Itemâ€,$theme_checkbox_array’)) { ….do something… };
Hope this helps.
By EsteWeb May 26, 2010 - 6:47 pm
First off, thank you very much for this tutorial, it’s really helped me a lot with my current project and I know it will be useful knowledge on future ones. Now on to my question: Say I wanted to be able to make it so that I can choose categories for certain pages (or even call upon pages for certain options), how would I go about doing that? I’m having a tough time trying to figure it out, it’s driving me nuts…
By Wok Doan June 30, 2010 - 12:33 am
Is there in way to
to have a the dynamically generated style sheet have a name appended.
With the current provided sample code
http://www.fakedomain.com/?css=css, would work
but
http://www.fakedomain.com/directoryname/filename.css?css=css
would provide a 404 error in the response headers, even though you can pull up the page in a web browsers
Any thoughts?
By Introducing the new UA WordPress Theme « WebTide June 30, 2010 - 9:17 am
[…] noticeable differences with this theme is the addition of a UA Theme Options panel. Thanks to an open source framework for creating theme options WordPress users with admin rights will be able to control major design aspects of their theme […]
By Chris Kendrick September 7, 2010 - 1:57 am
How do I add a title to the options page using
array(
“desc” => __(“Choose a layout below”),
“type” => “title”),
By Delicious Bookmarks for September 6th through September 7th « Lâmôlabs September 7, 2010 - 11:07 am
[…] WordPress Theme Options Framework Ver 2 | Jeremy Clark – TechNet.com – September 6th %(postalicious-tags)( tags: wordpress options theme framework template example tip trick )% […]
By Vlad January 20, 2011 - 6:06 am
Hey, thanks for this framework. I have a question about the upload. I’m getting the message that comes from else in upload.php, i do change the permissions of the folder.
Thanks.
By Jesse January 21, 2011 - 2:29 pm
I agree about using the options table – bad form. If you have more than a couple of options, it get very clunky. Thanks for the share of your code.
By arafat June 18, 2011 - 1:24 am
i am trying to use multiselect
$options[] = array( “name” => “Multiple selection box”,
“desc” => “This is a descriptions”,
“id” => $shortname.”_multi_select_dropdown_menu”,
“type” => “multiselect”,
“std” => “Default”,
“options” => array(“Defaults”, “Option 1s”, “Option 2s”));
But its showing nothing. How can i fiex it
Thanks
By arafat June 18, 2011 - 1:26 am
i am trying to use multiselect I have used your code but nothing showing in my theme options
$options[] = array( “name” => “Multiple selection box”,
“desc” => “This is a descriptions”,
“id” => $shortname.”_multi_select_dropdown_menu”,
“type” => “multiselect”,
“std” => “Default”,
“options” => array(“Defaults”, “Option 1s”, “Option 2s”));
How can i fiex it
Thanks