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.

Literal Barrage is Stephen Fry proof thanks to caching by WP Super Cache