Easy WordPress Theme Options

For the most up-to-date information visit the plugin page

I’ve been getting really annoyed every time I want to add options to my theme and I have to copy a huge mess of code that just isn’t fun to use. You know what I mean. Most theme developers now include configurable options in their themes, which if you ask me, isn’t super easy.

So the other day I set out to write a class that theme developers could package with their file and have easy access to theme options. It’s as easy as adding my theme_options.php file to an include folder in your theme directory, and then adding this code to your functions.php (Using your option values obviously).

Download my ThemeOptions class

require_once( 'includes/theme_options.php' );

define( 'THEME_NAME' , 'Theme Template' );
define( 'THEME_SHORTNAME' , 'themetpl' );

ThemeOptions::add( 'sample_text_field', 'Its a text field'  , array( 'desc' => 'A description of the theme option', 'type' => 'text', 'default' => 'Default Value' ) );
ThemeOptions::add( 'sample_textarea'  , 'Its a text area'   , array( 'desc' => 'A description of the theme option', 'type' => 'textarea', 'default' => "Text\nTest" ) );
ThemeOptions::add( 'sample_checkbox'  , 'Its a checkbox'    , array( 'desc' => 'A description of the theme option', 'type' => 'checkbox', 'default' => 'enabled' ) );
ThemeOptions::add( 'sample_select'    , 'Its a select thing', array( 'desc' => 'A description of the theme option', 'type' => 'select', 'default' => 'Option 2', 'values' => array( 'Option 1', 'Option 2', 'Option 3' ) ) );
ThemeOptions::add( 'sample_radio1'    , 'Its a radio field' , array( 'desc' => 'A description of the theme option', 'type' => 'radio', 'default' => 'val1', 'values' => array( 'val1' => 'Text 1' , 'val2' => 'Text 2' ) ) );
ThemeOptions::add( 'sample_radio2'    , 'Its a radio field' , array( 'desc' => 'A description of the theme option', 'type' => 'radio', 'default' => 'val2', 'values' => array( 'val1' => 'Text 1' , 'val2' => 'Text 2' ) ) );

Now this may seem confusing at first, but if we expand it out, you’ll see it’s similar to other WordPress functions (I did the code like that for that specific reason):

$args = array(
    'desc' => 'This is a description of the option',
    'type' => 'text',
    'default' => 'This is the default value'
);

ThemeOptions::add( 'option_id', 'Option Name', $args );

And to get a value:

$val = ThemeOptions::get('simple_text_field');

Isn’t that easier that what you’ve been doing? I’ve encapsulated my code into a nice class to make everything super simple. The results should look similar to this (Located in Appearance > Theme Options):

Screenshot of the Theme Options Page

Download my ThemeOptions class

Members Only Menu Plugin

Visit my up-to-date page for this plugin

I released my my walker class as a super easy to use plugin (This doesn’t even require you to change your wp_nav_menu commands as it uses a filter to add it). I’ve submitted it to WordPress.org so I’ve linked to it below.

Just install and activate it, and then you can go to a page and mark it as Members Only.

Now featuring full support for wp_page_menu AND wp_nav_menu. Tested on WordPress 2.9+. Also fully compatible with PHP 4+!

Download my super awesome plugin now!

Must Have Have Plugins

With the amount of WordPress sites I’ve been doing lately, I’ve encountered a list of plugins I keep returning too. They may not be perfect, but they do what I need, and they do it well.

  • Contact Form 7
    • Really flexible contact form with changeable elements, optional CAPTCHA, multilingual support, recipients dependent on a drop down value, etc.
  • WPML
    • The best available multilingual plugin available for WordPress, adds a host of features for developing multi language sites.
  • TinyMCE Advanced
    • Adds more commands to the WordPress default editor, such as tables and the option to stop removing extra breaks.
  • Members
    • Adds enhanced role and capability management features, a must for any large or complex CMS built on WordPress. It’s very powerful
  • HTML and Flash Video Player
    • A nice plugin adding shortcodes for inserting a Flash/HTML5 video player in WordPress posts
    • Requires a hook in the template you are using
    • Shortcode is [videoplayer file="video/video.flv" /]
  • WP e-Commerce
    • Full e-commerce functionality wrapped up in a nice plugin. Support for popular payment gateways like PayPal and Google Checkout. Very bloated though.
  • Fluency Admin
    • Changed up the WordPress admin area adding a much needed visual makeover, and some minor new features.
  • Really Simple CAPTCHA
    • Required to add CAPTCHA functionality to Contact Form 7, can be used in your own plugins as well. Very simple, not all that secure but easy to

WordPress Walker Classes

Walkers are used in WordPress to recursively handle data such as menus. As defined in the WordPress codex

The walker class encapsulates the basic functionality necessary to output HTML representing WordPress objects with a tree structure. For instance pages and categories are the two types of objects that the WordPress 2.2 code uses the walker class to enumerate. While one could always display categories as you wished by using right func and looping through them using it takes a great deal of work to arrange subcategories below their parents with proper formatting. The walker class takes care of most of this work for you.

Now, unfortunately there is very little good documentation about Walker classes, even though they give you more customization and flexibility then the default code, all without modifying core WordPress files which is perhaps the most important part. I set out this last week to allow my client to create a members only page which he could add to the site navigation, and have it only show up if the user was logged in. This turned out to be more difficult than I initially expected as private pages cannot be added to the menu.

After searching the Internet and finding nothing, I did the next best thing: Searched through the WordPress code. I eventually came up with this, which adds a checkbox saying “Is Members Only?” to the page editor. Then I added some code to my theme’s functions.php, which could easily be put in a plugin instead which checks to make sure the user is logged in. Now to make it selectively appear in the menus, I wrote my only walker class, extending the default one.

Here is my code:

add_action( 'wp' , 'check_for_members_only' );

function check_for_members_only() {
	global $post;

	if ( get_post_meta( $post->ID , '_members_only' , true ) && !is_user_logged_in() ) {
		header( 'Location: /wp-login.php' );
		exit();
	}
}

The above snippet is fairly simple. It executes right after the post data is set, and checks if some post meta is set. If it is, we redirect to the login page.

function add_members_only_meta_box() {
    add_meta_box( 'add_members_only_meta' , 'Members Only' , 'add_members_only_meta' , 'page' , 'side' , 'high' );
}
add_action( 'add_meta_boxes' , 'add_members_only_meta_box' );

function add_members_only_meta() {
    global $post;

    $meta_box_value = get_post_meta( $post->ID , '_members_only' , true ); 

    if ( $meta_box_value == 'true' ) {
        $meta_box_value = 'checked="checked"';
    }

    echo '<input type="hidden" name="members_only_nonce" id="members_only_nonce" value="' . wp_create_nonce( 'members_only' ) . '" />';
    echo '<input type="checkbox" name="members_only" id="members_only" value="true" '.$meta_box_value .' /> Restrict To Members?';
}

/* When the post is saved, saves our custom data */
function members_only_save_postdata( $post_id )
{
    // verify this came from the our screen and with proper authorization,
    // because save_post can be triggered at other times
    if ( !wp_verify_nonce( $_POST['members_only_nonce'], 'members_only' ) )
    {
        return $post_id;
    }

    // verify if this is an auto save routine. If it is our form has not been submitted, so we dont want
    // to do anything
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return $post_id;

    // Save
    update_post_meta( $post_id , '_members_only' , $_POST['members_only'] );

    return $post_id;
}
add_action( 'save_post' , 'members_only_save_postdata' );

This code is also fairly straight forward. We add a meta box to the page editor (Look at the add_meta_box, I specify page). We also add some code to save our post meta, prefixing it with an underscore so it is hidden from the meta box interview.

Now here is the walker class.

class Walker_Nav_Menu_CMS extends Walker_Nav_Menu {
	function start_el(&$output, $item, $depth, $args) {
		global $wp_query;

		$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

		$class_names = $value = '';

		$classes = empty( $item->classes ) ? array() : (array) $item->classes;

		$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
		$class_names = ' class="' . esc_attr( $class_names ) . '"';

		if ( !get_post_meta( $item->object_id , '_members_only' , true ) || is_user_logged_in() ) {
			$output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
		}

		$attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
		$attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
		$attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
		$attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';

		$item_output = $args->before;
		$item_output .= '<a'. $attributes .'>';
		$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
		$item_output .= '</a>';
		$item_output .= $args->after;

		if ( !get_post_meta( $item->object_id, '_members_only' , true ) || is_user_logged_in() ) {
			$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
		}
	}

	function end_el(&$output, $item, $depth) {
		if ( !get_post_meta( $item->object_id, '_members_only' , true ) || is_user_logged_in() ) {
			$output .= "</li>\n";
		}
	}
}

This is almost exactly the same as the default nav function, except I added the line “if ( !get_post_meta( $item->object_id, ‘_members_only’ , true ) || is_user_logged_in() ) {“. Now, in this case I wanted to modify only the Nav Walker, without editing core files. I didn’t need to change much, so all I did was extend the default Nav Walker, instead of the base Walker class.

If you look through the code, it’s not really hard to understand. The walker class has several functions, start_el, end_el, walk, start_lvl, and end_lvl. You can extend the base classes and implement your own versions of these functions if you want. I’ll explain what these do.

start_lvl – Creates the <ul>
end_lvl – Creates the </ul>
start_el – Creates the <li right to the </li> but excluding the </li>
end_el – Creates the </li>
walk – This is a fairly complex function that calls the above functions depending on if a submenu needs to be created, or closed, etc.

I would recommend looking at the Walker class in wp-includes/classes.php and the other classes that extend the Walker class from wp-includes/nav-menu-templates.php.

Now the most important part is getting your code to use the new walker class. This is super simple:

wp_nav_menu( array( 'walker' => new Walker_Nav_Menu_CMS() ) );

WordPress 3.0 Thoughts

I’ve been using WordPress 3.0 at work for a month now, and what do I think of it? It’s fantastic! WordPress 3.0 added many new features, including custom menus which are extremely helpful for using WordPress as a CMS. WordPress 3 implemented over 200 fixes and features, so I recommend checking out the official site to see a list of all of them. Here’s the ones I like the most

  • WordPress Menus – Add menus across your site that are manageable via the admin and are as simple as calling wp_nav_menu in your theme.
  • Custom Headers – You can set the header in your blog via a nice admin panel
  • Custom Backgrounds – WordPress has an API for themes allowing your theme users to easily change the theme background
  • Custom Post Types – These are the most important feature for sure. It allows you to easily (Like 30 lines of code easy) add your own post types. Like videos, services, products, etc. Basically, you pass a few arguments to register_post_type and you’re done. WordPress auto generates an interface similar to the posts/pages interface. You can extend it with your own version of categories and tags as well (For example, you could make a gallery tag/category taxonomy for grouping your video post types).

With the amount of development I’ve been doing, I’ve noticed a lot of really useful functions, actions, and filters have no documentation on the WordPress codex, and some have no documentation anywhere that I could find (Like the Walker Class and making custom Walkers). I’ve registered a codex account and am slowly adding documentation, and any of the really awesome stuff I’ll post here as well.