A Theme Tip For WordPress Theme Authors

NOTE: This tutorial is old and out of date and predates much of what is now state-of-the-art in the WordPress world. Instead of pursuing this method, check out One Design’s How to Create a WordPress Theme Options Page for an up-to-date take on creating theme options pages. I’ve removed the downloadable .zip file containing my old functions.php in order to remove confusion.

NOTE: The contents of this post may shift about a bit as time goes on. For some reason, the code-highlighting plugin I’m attempting to use isn’t working correctly. There may end up being some more code snippets that find their way into this post if I figure out what’s going wrong. Fixed it by moving to a different code-highlighting plugin. Dunno what the issue was, but it’s gone now.
For theme authors looking to customize their theme offerings with a fancy options/administration screen, functions.php is the place to start. By default, WordPress loads it whenever your theme is active — on the front page or on the back end. A brief discussion on the wp-hackers mailing list today prodded me to post the following code from the functions.php I’m including in Elbee Elgee (whenever I get around to releasing it, that is…). I took the guide offered by The Undersigned as a jumping-off point and added some nice tweaks. In particular, The Undersigned’s version only allowed for text and select form inputs — I wanted/needed more flexibility.
The file itself is fairly simple and almost self-documenting, but in the interests of full disclosure, I’ll comment upon it here:
1. I set the descriptive and short names of my theme at the head of the file.

$themename = "Elbee Elgee";
$shortname = "lblg";


2. Elbee Elgee looks for layouts and stylesheets in a couple of sub-directories in order to let end users drop custom stylesheets in and have them detected automatically. (Line 5)

if ( is_dir($layout_path) ) {
	if ($layout_dir = opendir($layout_path) ) {
		while ( ($file = readdir($layout_dir)) !== false ) {
			if(stristr($file, ".css") !== false) {
				array_push($layouts, $file);
			}
		}
	}
}
if ( is_dir($alt_stylesheet_path) ) {
	if ($alt_stylesheet_dir = opendir($alt_stylesheet_path) ) {
		while ( ($file = readdir($alt_stylesheet_dir)) !== false ) {
			if(stristr($file, ".css") !== false) {
				array_push($alt_stylesheets, $file);
			}
		}
	}
}
$layouts_tmp = asort($layouts);
$layouts_tmp = array_unshift($layouts, "Select a layout:");
$alt_stylesheets_tmp = asort($alt_stylesheets);
$alt_stylesheets_tmp = array_unshift($alt_stylesheets, "Select a stylesheet:");

3. I set all the options in an array. (Line 39)

$options = array (
				array(	"name" => "Use Custom Headers",
						"id" => $shortname."_use_custom_header",
						"std" => "false",
						"type" => "checkbox"),
				array(	"name" => "Display \"About\" Text",
						"id" => $shortname."_display_about",
						"std" => "false",
						"type" => "checkbox"),
				array(	"name" => "\"About\" Text",
						"id" => $shortname."_about_text",
						"std" => "This is a little blurb about your site.",
						"type" => "textarea",
						"options" => array(	"rows" => "5",
											"cols" => "40") ),
				array(	"name" => "Layout Stylesheet",
			    		"id" => $shortname."_layout_stylesheet",
			    		"std" => "Select a layout:",
			    		"type" => "select",
			    		"options" => $layouts),
				array(	"name" => "Theme Stylesheet",
					    "id" => $shortname."_alt_stylesheet",
					    "std" => "Select a stylesheet:",
					    "type" => "select",
					    "options" => $alt_stylesheets),
				array(	"name" => "Number of Previous Posts",
			    		"id" => $shortname."_previous_posts",
			    		"std" => "5",
			    		"type" => "text"),
				array(	"name" => "Del.icio.us Username",
					    "id" => $shortname."_delicious_username",
					    "std" => "zamoose",
					    "type" => "text")
		  );

4. mytheme_add_admin() is responsible for adding the theme options page to the admin bars in WordPress and saving the theme options to the database. It’s fairly uninteresting and so I won’t reprint it here.
5. mytheme_admin() is where the real meat of the options screen gets generated. In particular, the following loop iterates through the options array set in the top of the file and generates the inputs for the form options. (Line 128)

<?php foreach ($options as $value) {
	switch ( $value['type'] ) {
		case 'text':
		?>
		<tr valign="top">
		    <th scope="row"><?php echo $value['name']; ?>:</th>
		    <td>
		        <input 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>
		<?php
		break;
		case 'select':
		?>
		<tr valign="top">
	        <th scope="row"><?php echo $value['name']; ?>:</th>
	        <td>
	            <select 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>
		<?php
		break;
		case 'textarea':
		$ta_options = $value['options'];
		?>
		<tr valign="top">
	        <th scope="row"><?php echo $value['name']; ?>:</th>
	        <td>
				<textarea name="<?php echo $value['id']; ?>" id="<?php echo $value['id']; ?>" cols="<?php echo $ta_options['cols']; ?>" rows="<?php echo $ta_options['rows']; ?>"><?php
				if( get_settings($value['id']) != "") {
						echo get_settings($value['id']);
					}else{
						echo $value['std'];
				}?></textarea>
	        </td>
	    </tr>
		<?php
		break;
		case "radio":
		?>
		<tr valign="top">
	        <th scope="row"><?php echo $value['name']; ?>:</th>
	        <td>
	            <?php foreach ($value['options'] as $key=>$option) {
				$radio_setting = get_settings($value['id']);
				if($radio_setting != ''){
		    		if ($key == get_settings($value['id']) ) {
						$checked = "checked=\"checked\"";
						} else {
							$checked = "";
						}
				}else{
					if($key == $value['std']){
						$checked = "checked=\"checked\"";
					}else{
						$checked = "";
					}
				}?>
	            <input type="radio" name="<?php echo $value['id']; ?>" value="<?php echo $key; ?>" <?php echo $checked; ?> /><?php echo $option; ?><br />
	            <?php } ?>
	        </td>
	    </tr>
		<?php
		break;
		case "checkbox":
		?>
			<tr valign="top">
		        <th scope="row"><?php echo $value['name']; ?>:</th>
		        <td>
		           <?php
						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; ?> />
		            <?php  ?>
		        </td>
		    </tr>
			<?php
		break;
		default:
		break;
	}
}
?>

6. I then register sidebar Widgets in mytheme_wp_head(), as well as detect whether we should use the WP Custom Header code. (Line 263)

if ( function_exists('register_sidebar') ) {
	register_sidebar(array('name'=>'Navigation'));
	register_sidebar(array('name'=>'Extra'));
	register_sidebar(array('name'=>'Bottom-Left'));
	register_sidebar(array('name'=>'Bottom-Right'));
}
$use_custom_header = $shortname."_use_custom_header";
if(get_settings($use_custom_header) == true){
	// Set up custom header code
	define('HEADER_TEXTCOLOR', 'cfcfd0');
	define('HEADER_IMAGE', '%s/styles/default/newbanner2.png');
	define('HEADER_IMAGE_WIDTH', '1024');
	define('HEADER_IMAGE_HEIGHT', '279');
	add_custom_image_header('header_style', 'elbee_admin_header_style');

7. I do a few things as per the Custom Header specs and then, last of all, to sew it all up, I hook in to the WP head and admin_menu. (Line 346)

add_action('wp_head', 'mytheme_wp_head');
add_action('admin_menu', 'mytheme_add_admin'); 

That’s pretty much it. If you want to download the whole thing (as currently incarnated), click the download link below.
(05-19-2008) Note: I’ve updated the download to reflect my current functions.php file. There’s a lot of changes — I’m working on an updated post to cover the additions and changes.
Download removed
Download removed
Hope it’s a help to someone out there.

Doug
Doug

Husband & father with youngins; Presbyterian; Will devops for boardgames; Dadjoke Enthusiast; Longtime WordPress user; The failure mode of “clever” is...

Articles: 2529

21 Comments

  1. I know this post is kinda old, but i find it very usefull but i have a problem when i input some text with ” ” it adds to many \ to the items :S do you know any way to fix this? would realy apriciate if u could answer this

  2. Nice catch, Adam. I’ll update my example to do so — don’t know why I haven’t come across that before.

  3. sorry for doble posting, but after doing what adam said i came up with something so i dont have to add stripslashes() everytime i need to use the values i set
    if ( ‘save’ == $_REQUEST[‘action’] ) {
    foreach ($options as $value) {
    $dato = stripslashes($_REQUEST[$value[‘id’]]);
    update_option( $value[‘id’], $dato ); }
    foreach ($options as $value) {
    $dato = stripslashes($_REQUEST[$value[‘id’]]);
    if( isset( $_REQUEST[ $value[‘id’] ] ) ) { update_option( $value[‘id’], $dato ); } else { delete_option( $value[‘id’] ); } }
    }
    simple add the stripslashes before the data is added 😀

  4. Omar:
    You’re coming at it from the wrong direction, though. The slashes generally get inserted by php at save time by magic_quotes so as to avoid confusing (certain) MySQL servers. This will result in all data returned from the DB having the slashes in it, thus displaying them in your options page.
    You want to clean the data on retrieval if possible so as to avoid \”options\” showing up in your options page.

  5. ohh ok thanks… kinda wierd cause the code i posted works perfectly on my server… just that functions.php is messing up the headers in wordpress admin panel and yet i see no posible way this could happen :S

  6. A Theme Tip For WordPress Theme Authors…
    For theme authors looking to customize their theme offerings with a fancy options/administration screen, functions.php is the place to start. By default, WordPress loads it whenever your theme is active — on the front page or on the back end….

  7. Ive spent last 3 hours implementing a much-better theme options page to my later WP theme, largely with thanks to the info posted above and within these comments.
    However, after a lot of head-scratching and editing, I have managed to strip the slashes from inside my WP options page (I want to add a “text-area” field for a google adsense banner code), the adsense code when saved no longer has the slashes, but when I return to the site, clear cache and refresh, the adsense code doesn’t work as when I view the source it’s still showing the adsense code WITH slashes.
    So can anyone tell me of a way to make the adsense banner code work on-site?
    Any help would be GREATLY appreciated – I can offer a free theme from stylewp.com to anyone who solves this problem I have 🙂

  8. Old but golden tip this.
    There’s one “fix” I’ve added to your code, namely that standard values aren’t saved until you actually press save. This issue, incidentally, also makes standard values for checkboxes not work.
    Update the code to look like this:
    } else if( ‘reset’ == $_REQUEST[‘action’] ) {
    // delete options
    foreach ($options as $value) {
    delete_option( $value[‘id’] ); }
    // update standards
    foreach ($options as $value) {
    update_option( $value[‘id’], $value[‘std’] ); }
    header(“Location: themes.php?page=theme-options.php&reset=true”);
    die;
    After this, boolean standard values for checkboxes should be input without quotes, i.e.
    array( “name” => __(‘Windows Live Writer?’,’proto’),
    “desc” => __(‘Use Windows Live Writer?’,’proto’),
    “id” => $shortname.”_wlw”,
    “std” => true,
    “type” => “checkbox”),

  9. Is there somewhere else I can download the functions-2.0.zip file? I get an error when I try to download it: “Download path is invalid!” Thanks!

Comments are closed.