WordPress Single Post Templates

I’ve recently released a plugin that is far more robust than the methods outlined below. It actually duplicates the functionality of WordPress Page Templates, and allows you to create individual post templates, selectable on a per post basis via a dropdown menu. Head over to my WordPress Plugins page and find the “Post Templates Plugin”

UPDATED:
Austin recommends using a filter in your functions.php file as an alternative to the method below. IMO, his suggestion is much simpler and quite elegant. Here’s the code to add to your theme’s functions.php file. (be sure you paste this code between <?php ?> tags):

add_filter('single_template', create_function('$t', 'foreach( (array) get_the_category() as $cat ) { if ( file_exists(TEMPLATEPATH . "/single-{$cat->term_id}.php") ) return TEMPLATEPATH . "/single-{$cat->term_id}.php"; } return $t;' ));

It helps solve the multiple categories issue since it cycles through all the categories in the array and checks to see which one of them has an associated post template. When it finds one, it uses the post template file, but if it doesn’t, then it falls back on the default single.php template.

So if you are used to placing posts in multiple categories, be sure to only create post templates for the categories you know won’t ever conflict.

Again, I highly recommend using this technique. It’s much simpler and works much better. If you care to, however, the original article is still below.
END UPDATE

A few months ago, I wrote a post over at the Blog Herald explaining how to set up and use WordPress Page Templates to control the way indivudual WordPress “Pages” appeared on your blog.  The process was pretty simple … create the page template, insert the necessary code at the top of the file, and upload it to your themes folder.

What what about blog posts?  As far as I could tell, there’s no way to do a similar thing with single posts without some manual code (see the “Unique Single Template” section).

Is it possible to have post templates like page templates???

Cory sent me this simple question a few days ago, and it got me thinking. So I started investigating.

The Setup

You’re going to need 3 things:

  1. A basic knowledge of WordPress Themes
  2. A single.php file
  3. Multiple single templates, named according to category ID

The Code

What we’re going to do is create single post templates according to the ID of the category the post is filed under.  In order to determine what category a post is filed under, we’re going to use the get_the_category template tag.  Then we’re going to pull out the first category the post is filed under. Insert the following code at the TOP of your single.php file in your theme folder:

cat_ID;
?>

Be aware, if you file posts under multiple categories, chances are this method will not work as you intended.

Then, we’ll add a little PHP magic to pull in the template file you created for a particular category:

cat_ID;
if (file_exists(TEMPLATEPATH."/single-$currentcat".".php")) {
include(TEMPLATEPATH."/single-$currentcat".".php");
} else {
?>

This code defines the first category the post is filed under, checks to see if a single post template exists for that category (template files look like this: single-1.php, single-2.php, single-3.php, etc.), and uses it if it does.

Finally, we need to put the following code at the very bottom of the single.php file, normally just below the wp_footer function:


The reason we have to do this is to be able to use the default single.php code as fallback in case you haven’t created a template for a certain category.

After you’ve got the code in place, just find the ID of the category you want to create a template for, then create a new file called single-ID.php (be sure to replace ID with the category number). Just insert the code you want to use for any posts filed in that category and you’re good to go!

Limitations

Like I mentioned earlier, if you are in the habit of filing posts under multiple categories, this code probably won’t work as intended. Since we’re working with templates for use on single posts in single categories, posts in multiple categories may end up falling back to the default single.php template. You have been warned!

Sample Code Download

As always, I like to provide a sample file for you to look at yourself. In this instance, I’ve edited the single.php file for the WordPress Default theme to pull in single post templates, if they exist. Take a look at the code if you have any questions about how it should look in your theme’s single.php file. I’ve also commented the code quite thoroughly.

Download single.php

Comments

  1. says

    That’s an interesting approach, and it got me thinking that you could do the same thing with just the following one line added to your theme’s functions.php file:

    add_filter('single_template', create_function('$t', 'foreach( (array) get_the_category() as $cat ) { if ( file_exists(TEMPLATEPATH . "/single-{$cat->term_id}.php") ) return TEMPLATEPATH . "/single-{$cat->term_id}.php"; } return $t;' ));

    This should avoid the problem you mention when a post has multiple categories.

  2. says

    @Austin,
    Forgive my ignorance … I’m not a plugin writer, so bear with me :-)

    What is the “term_id”? It’s not in the codex doc for the “get_the_category” function.

    Also, does this account for a default fallback? In the event that a single post template doesn’t exist for that particular category, does the theme just parse the single.php file as usual?

    I’m not sure if this helps the “multiple categories” problem though. Won’t this just return the first (or perhaps last) category in the array?

    Thanks!

  3. says

    What is the “term_id”?

    That’s the category id. Since WP version 2.3 categories and tags are both “terms.”

    Also, does this account for a default fallback?

    Yes, if there is no such file, it just goes with the default single template.

    I’m not sure if this helps the “multiple categories” problem though. Won’t this just return the first (or perhaps last) category in the array?

    It will return the first category for which there is a corresponding single-[category id].php template.

  4. says

    That’s the category id. Since WP version 2.3 categories and tags are both “terms.”

    Yes, if there is no such file, it just goes with the default single template.

    It will return the first category for which there is a corresponding single-[category id].php template.

    So, essentially it does everything my code does … just way better :-) I’m gonna add it to the top of this story as an alternate, better way of doing it. Thanks!!!

  5. says

    @Austin
    Do you think it would be possible for WordPress to parse post templates like they do page templates and let you choose (on a per post basis) which post template they would like to use (again, just like the page templates work)?

    That would be an interesting addition to the core, IMO.

  6. says

    That’s sort of what’s going on in the new Monotone theme: each post has a differently-styled template, based on the colors of its photo.

    That’s automatically done, but I think you’re talking about something that would allow someone to manually select a template for individual posts. I don’t see that becoming part of core, because I think it wouldn’t be commonly used, and the core WordPress devs don’t like there to be too many options. :)

  7. says

    @Austin:
    I guess it would have to be a plugin. I can see it being useful, but definitely not useful enough to warrant inclusion in the core. Good point.

  8. says

    This is excellent – top work both Nathan and Austin.

    I was wondering though – would it be possible to do the same thing using tags, rather than categories?

  9. says

    I like this approach. I’m using Brain Gardners vertigo theme, and there isn’t a sigle.php file in it. So I’m confused, how would I implement this?

  10. says

    @Kathy:
    I’ve always used index.php as my front page template, and single.php as my single post template, but Brian does it a little different …

    He uses home.php as his front page, and index.php as his single post template. So just copy the index.php file, rename the copy as single.php and use then start the instructions.

    Nathan

  11. says

    This is great – thanks for the code, and hats off to Austin for the upgrade.

    My question is this: I’m trying to create a site that has four different categories (I’m controlling styles through the body tag), but I can’t find a way to link directly to the latest post in each category (from the home page or the nav bar, basically).

    If I link to the category, I get a category/archive look (i.e. no comments). Is there a way to link directly to the single view of the latest post in a given category?

    Thanks; if anyone has a solution, this’ll totally save my bacon.

  12. says

    Thanks for this. I’ve been creating a PTA section for a school website, for which they would like a different look and feel. They use both posts and page. I’d worked out how to apply the new style to the pages, but not the posts. This has been invaluable. Saved my bacon as well! ;-)

    Thanks,

    Jeremy
    http://www.webswonder.co.uk

  13. Cory Glauner says

    It works, but now I get the following error when I try to edit posts:

    Warning: Cannot modify header information – headers already sent by (output started at /home/content/j/u/s/justhuntit/html/wp-content/themes/Outdoors_International_2.0/functions.php:10) in /home/content/j/u/s/justhuntit/html/wp-includes/pluggable.php on line 850

  14. Rebecca says

    Hi
    Thanks very much for this.

    I have tried to use Austin’s solution by pasting that line in as the very last line in my functions.php page.

    As so:

    term_id}.php”) ) return TEMPLATEPATH . “/single-{$cat->term_id}.php”; } return $t;’ )); ?>

    I’m getting an error when I try to create or delete pages:

    “Warning: Cannot modify header information – headers already sent by (output started at /wp-content/themes/default/functions.php:847) in /wp-includes/classes.php on line 1571″

    What am I doing wrong?

    • says

      Be sure you’re pasting that code in your functions.php file, but make sure you’re pasting it somewhere between PHP opening and closing tags.

      Also, make sure that the final closing PHP tag ( looks like this: <? ) has NO spaces after it.

      Nathan

  15. says

    For those who wonder what purpose this might serve, check out my site. It’s a photoblog that I’ve set up to turn the posts into “galleries” via cat and post templates. My problem was that I could easily create the category template to give a decent view for the “gallery home” page (ie category home page), but when i clicked on an individual post(photo), the post page (individual photo page) would revert into the default function of the theme, which is to display the most recent photos timewise at the bottom of the post. This has added great functionality to my site and makes the “gallery” feel a lot more like a gallery. thanks a ton!

  16. says

    Hi, great addition. I got this to work using Austin’s code but I have encountered a side problem.

    I have 25 categories within a parent category. I want all those 25 categories to use the same template but specifiying the parent category does not cause the posts to use the parent-category template. When I specifiy each individual category ID it works fine. Is there any way I can specify to use 1 template for the parent category which will filter down into all its subcategories?

    You may be thinking why dotn I set this to default template but I have another 25 subcategories in a different parent category also to customize…

  17. says

    Wow, incredible script. Why isn’t this added to the WordPress core so that WordPress behaves this way by default? Seems like including this by default would be an automatic of-course.

  18. says

    Nice, but how do we make it work with all the posts of a child category. Ex.: I name a single-category-3 and work for my posts on category 3 (Cars). But the child categories posts (Ford, GM, Ferrari) must be the same layout. To make it work I have to copy the file and rename ir several times, everytime I made a change….Tanks

  19. says

    Great little snippet of code here. Thanks!

    I am commenting and subscribing, with the hope that the Parent and Child category questions are addressed at some time.

  20. says

    @WhiteKnight, @Emanoel, @Joe

    I’m afraid that is far more involved, and would probably require a whole new post. I’ll put it on the list, but it’s such a rare case, I’m not sure there would be much demand for it, and thus, I’m not sure when I’d be able to get to it.

    Stay subscribed though. I will try to get to it eventually.

    Nathan

  21. says

    Using your PHP, I get the following error.

    Parse error: syntax error, unexpected ‘}’ in /home/gamer/public_html/wp-content/themes/zinmagremedy/single.php on line 20

    All I did was copy and paste the PHP from the top of your example and the one line at the bottom into my file.

  22. says

    I figured it out. I also put the code in my single-8.php which was causing the error. After taking that out, it works perfectly.

    I didn’t add anything to functions.php though, only single.php.

  23. says

    @WhiteKnight, @Emanoel, @Joe

    Regarding setting the category ID to the parent category if the post belongs to a subcategory:

    This seems (used in single.php — not quite sure how to adapt this to Austin’s code for functions.php):


    $category = get_the_category();
    $currentcat = $category[0]->cat_ID;

    //look to see if has parent - WordPress will return 0 if it's already top-level
    $parentcat = $category[0]->category_parent;

    //test for parent categories
    if ($parentcat != '0') {

    //if a parent exists then make that the current cat
    $currentcat = $parentcat;
    }

    if (file_exists(TEMPLATEPATH."/single-$currentcat".".php") ) {

    include(TEMPLATEPATH."/single-$currentcat".".php");
    } else {

    include(TEMPLATEPATH . "/single-default.php");
    }

  24. says

    [Nathan, please delete first post and use this one instead]

    @WhiteKnight, @Emanoel, @Joe

    Regarding setting the category ID to the parent category if the post belongs to a subcategory:

    This seems to work (used in single.php — not quite sure how to adapt this to Austin’s code for functions.php):

    $category = get_the_category();
    $currentcat = $category[0]->cat_ID;

    //look to see if has parent - WordPress will return 0 if it's already top-level
    $parentcat = $category[0]->category_parent;

    //test for parent categories
    if ($parentcat != '0') {

    //if a parent exists then make that the current cat
    $currentcat = $parentcat;
    }

    if (file_exists(TEMPLATEPATH."/single-$currentcat".".php") ) {

    include(TEMPLATEPATH."/single-$currentcat".".php");
    } else {

    include(TEMPLATEPATH . "/single-default.php");
    }

  25. says

    Thanks Tyler, I’ll check it out and let you know if I run into any problems. Thanks for the additional code.

    • says

      @ Joe

      I’ll be interested to know if it works for you.

      Also, note that the way I currently have it, it will only check one level up — if you have grandfather categories, etc., the code will have to be modified…

  26. steven says

    Cool! But what if I want to create different layouts for posts within the index.php file?
    I want to give different posts different colors depending on the category.
    But with your solution I only see the color when I click on the post. (So when I go to single.php)

  27. Slob Jones says

    This doesn’t make any sense. You title the post, “WordPress Single Post Templates,” but the tutorial describes calling a custom template for a specific category, not a specific post.

    How is this method going to allow users to create templates for single, specific posts?

  28. says

    This doesn’t make any sense. You title the post, “WordPress Single Post Templates,” but the tutorial describes calling a custom template for a specific category, not a specific post.”

    No reason to go to the extra work of creating a template, for a post if it is only going to be used once.

    Title refers to a single post per page versus a archive type page with several posts on it.

  29. Dylan van der Heij says

    Hi Everyone,

    Very useful article and discussion, thank you! Does anybody know how to make sure that a visitor that types a link that does not exist is linked to an error page instead of index.php?

    So my link is http://www.example.nl, a user types http://www.example.nl/hello, but that page does not exist. In the basic theme a user is redirected to the theme without page content. How can I make sure the user receives an error page or the basic page that I want to display first?

    Thanks for your reply in advance!

    With regards,
    Dylan