WordPress Theme Options Framework Ver 2

By Jeremy Clark
Filed In guides, tech, wordpress  |  Tagged , , ,  |  6,997 views
TOP       digg

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 require_once(TEMPLATEPATH . '/controlpanel.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.

$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"))
);

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.

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');

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
global $shortname;
$settings = get_option($shortname.'_options');
// Options are called like this $settings['option_id'];
?>

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
if(in_array("Item",$settings['theme_checkbox']));
?>

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
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>

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

	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');

?>

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
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;
?>

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.

<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>

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.

Related posts:

  1. WordPress Theme Options Framework
  2. WordPress Theme Dev Tip – Dynamic Stylesheets
  3. Optimize your WordPress theme for Search Engines – Part 1
  4. WordPress 2.7 Comment Callback Function
  5. Optimize your WordPress theme for Search Engines – Part 3
1 Star2 Stars3 Stars4 Stars5 Stars |  (12 votes, average: 4.92 out of 5)
Loading ... Loading ...

45 Comments

  • 11

    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

    • 11.1

      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.

      • 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

        • 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")
          
  • 12

    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?

    • 12.1

      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.

      • 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.

  • 13

    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

    • 13.1

      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.

    • 13.2

      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 :)

  • 14

    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)

  • 15

    global $shortname;
    $settings = get_option($shortname.’_options’);
    // Options are called like this $settings['option_id'];

    $theme_text_box;

  • 16

    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″ />


    —————————————————————————–

    • 16.1

      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.

  • 17

    Hm, not so brief. Didn’t all fit. ;)

  • 18

    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?

  • 19

    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.

  • 20

    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?

    • 20.1

      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?

      • 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.

Trackbacks / Pingbacks

Leave a Reply

Want an Avatar like seen here. Sign up for Gravatar

Subscribe without commenting