Creating single post templates in WordPress

Recently, a commenter asked me about creating single post templates in WordPress. This was actually something I’ve been working on as a side project for a while now.

The original code I started working with came from Nathan Rice’s post on creating post templates, but I wanted to expand on that idea a bit.

What is a single post template?

Well, they’re sort of like what we can do with page templates or category templates. You can use a specific post template for single posts that you want to function differently.

For example, in this tutorial, I will tell you how to create single templates based on post ID, category, tag, and/or author. You could potentially make all posts by author Jane Doe behave in a different way than other posts.

They should not be used to change the look (style, design) of a particular post though. You can do this with CSS. They should only be used to change how a particular post functions.

Creating the function to handle single post templates

Note that this is an advanced tutorial. You need to know what WordPress filters are and how the template hierarchy works before even considering using this tutorial.

For the sake of this tutorial, all of our additional post templates will reside within a folder named single within our theme folder. So, you’ll have a directory structure that looks like this:

/themes
	/your-theme
		/single

This will be much more helpful in the long run, especially if you’re creating multiple templates.

Open your theme’s functions.php file and add this:

/**
* Define a constant path to our single template folder
*/
define(SINGLE_PATH, TEMPLATEPATH . '/single');

/**
* Filter the single_template with our custom function
*/
add_filter('single_template', 'my_single_template');

/**
* Single template function which will choose our template
*/
function my_single_template($single) {
	global $wp_query, $post;

Now, we’ve set up everything but haven’t finished. I will take you through the different things you can define your single post templates by now.

In the next steps, you can choose to implement any of these methods, but you don’t have to use all of them.

This first part will check for templates within the /single folder labeled like single-100.php. It’s looking for the post ID. So, if you have a post with an ID that matches the template, it will be loaded.

	/**
	* Checks for single template by ID
	*/
	if(file_exists(SINGLE_PATH . '/single-' . $post->ID . '.php'))
		return SINGLE_PATH . '/single-' . $post->ID . '.php';

Let’s suppose you want to check for templates by category slug or ID. This part will tell the script to look for templates such as single-cat-uncategorized.php or single-cat-1.php within the /single folder.

	/**
	* Checks for single template by category
	* Check by category slug and ID
	*/
	foreach((array)get_the_category() as $cat) :

		if(file_exists(SINGLE_PATH . '/single-cat-' . $cat->slug . '.php'))
			return SINGLE_PATH . '/single-cat-' . $cat->slug . '.php';

		elseif(file_exists(SINGLE_PATH . '/single-cat-' . $cat->term_id . '.php'))
			return SINGLE_PATH . '/single-cat-' . $cat->term_id . '.php';

	endforeach;

Now I will show you how to check for single templates based on the tags used in a post. This will check for a template based on tag slug and ID, such as single-tag-example.php and single-tag-100.php.

	/**
	* Checks for single template by tag
	* Check by tag slug and ID
	*/
	$wp_query->in_the_loop = true;
	foreach((array)get_the_tags() as $tag) :

		if(file_exists(SINGLE_PATH . '/single-tag-' . $tag->slug . '.php'))
			return SINGLE_PATH . '/single-tag-' . $tag->slug . '.php';

		elseif(file_exists(SINGLE_PATH . '/single-tag-' . $tag->term_id . '.php'))
			return SINGLE_PATH . '/single-tag-' . $tag->term_id . '.php';

	endforeach;
	$wp_query->in_the_loop = false;

You may even want to check for single templates by author. Well, we can do that too. This will check for author by user nicename and user ID. So, you can set up templates like single-author-admin.php and single-author-1.php.

	/**
	* Checks for single template by author
	* Check by user nicename and ID
	*/
	$curauth = get_userdata($wp_query->post->post_author);

	if(file_exists(SINGLE_PATH . '/single-author-' . $curauth->user_nicename . '.php'))
		return SINGLE_PATH . '/single-author-' . $curauth->user_nicename . '.php';

	elseif(file_exists(SINGLE_PATH . '/single-author-' . $curauth->ID . '.php'))
		return SINGLE_PATH  . '/single-author-' . $curauth->ID . '.php';

And, the final check you can do is for a default single.php or default.php file within the /single folder.

	/**
	* Checks for default single post files within the single folder
	*/
	if(file_exists(SINGLE_PATH . '/single.php'))
		return SINGLE_PATH . '/single.php';

	elseif(file_exists(SINGLE_PATH . '/default.php'))
		return SINGLE_PATH . '/default.php';

Once you’ve added whatever code you wanted to inside of your function, you need to close it off.

	return $single;

}

How to create a custom post template

Before you begin creating templates, you should ask yourself a few questions?

  • What will this template do? What is its purpose?
  • When should it be used? In what context?
  • Will a WordPress action or filter hook work better?
  • Can my goals be achieved through CSS?

I can’t tell you what to actually use your single post templates for, but I can tell you how to create them.

First, you want to create a folder named single in your theme folder if you haven’t done so already. Then, make a copy of your theme’s single.php file and drop it within that folder.

To create a single template based on the category Uncategorized, we would only need to name the file we copied to single-cat-uncategorized.php. Then, all of your posts on their single post view with the Uncategorized category will use that particular template instead of the normal single post template.

You can change the code in your new file to anything. There are no limits. It’s up to you to decide how your template should function though.

Using a child theme?

I know many of my readers are starting to hop on the child-theme bandwagon, and I’m happy about that. You can use this method in your child theme as well.

You only need to change this line in the code above:

define(SINGLE_PATH, TEMPLATEPATH . '/single');

Change it to:

define(SINGLE_PATH, STYLESHEETPATH . '/single');

WordPress 2.7 also has a function called locate_template() that you can use to check for template files that you specify. It will search within a child theme and the parent theme for you. You can see how it works in /wp-includes/theme.php.

Closing thoughts on single templates

You could potentially even do this on a date-/time-based template level, but I figured I’d stop at this point.

I haven’t found any uses for doing this myself, but it is a neat concept to toy around with. Most arguments I’ve seen for using single post templates have been style-based arguments. I strongly suggest using a CSS solution before using additional templates if at all possible.

I’m also thinking of packaging something like this up in a plugin but a more advanced version. Would anyone be interested in that?