Faking Multiple Templates in WordPress

One of the things that surprised me when I first switched from Movable Type to WordPress was its lack of multiple templates. In MT you create numerous templates which allow you to change the look of different pages on your site (i.e., the homepage, archive pages, individual entries, etc.). If you want a list of your favorite links to appear on the homepage, but not on the page for an individual entry, you just delete that section of code from the appropriate template.

WordPress handles its pages a bit differently. Everything is based off of a single template, and through the magic of database queries and dynamic page generation, the right content is always shown according to which type of page you’re looking at.

The Problem

By using a single template, the default installation of WP will show the exact same sidebar on every page, and likewise, whenever you view an entry listing, it will always look the same. This one-template structure is viewed as a blessing to some, but an over-simplification to others.

What if you want to show a list of just the entry titles on your archive pages, rather than the entire entry itself? What if you want to hide the sidebar’s calendar on your individual entry pages? There are countless scenarios like these that require a little more flexibility than the default index.php file can give you.

This issue has been discussed many times on the WordPress support forums, but I’ve found most of the proposed solutions to be less than ideal. It’s rumored that the functionality to control these types of things will be built into WordPress 1.3, but for the time being, it seems we’re on our own.

A Common Solution

Many people suggest using .htaccess rules and simply forward visitors to templates other than index.php. I feel this method over-complicates things, and here’s why:

  1. It creates duplicate code when most of the time you’ll have the exact same basic page structure in each template. Not only that, but multiple templates aren’t very easy to maintain if you ever need to change that underlying structure.
  2. There’s no guarantee that all WP users will be able to create, edit, and use .htaccess files. Some hosting companies just don’t allow it.
  3. Writing .htaccess rules can be downright confusing!

My Solution

Using some simple PHP and the functionality that’s already built into WordPress, you can easily control what appears on different page types without having to create multiple templates. The key lies in exploiting a few under appreciated variables…

$single, $cat, $m, and $year are all built in variables used by WP to determine information about the type of page you’re looking at. The $single variable corresponds to individual entry pages, the $cat variable to categorical listing pages, $m to monthly listings, and $year to yearly listings.

When you’re viewing each variable’s corresponding page type, only that variable will be assigned a value. If you’re viewing the main page of your site, then none of those variables will be assigned a value. Thus, a simple test of whether or not each variable has a value can be use to control exactly what is displayed and when. Here’s the basic idea:

if ($single) {
    // individual post contents
} else if ($cat) {
    // categorical listing contents
} else if ($m) {
    // monthly listing contents
} else if ($year) {
    // yearly listing contents
} else {
    // main page contents
}

All you have to do is place the content you want to appear in the appropriate spot. If you don’t want to do anything different in a particular section from how WP handles it by default, just leave out that variable’s test.

How to Apply It

Using one of the scenarios from above as an example, let’s say that you want to show just the entry titles when viewing a categorical listing. All you’d have to do is change the <div id="content"> section of your index.php file to be something like this:

<div id="content">
    <?php
    if ($posts) : foreach ($posts as $post) : start_wp();

    if ($cat) { ?>
        <h3 class="storytitle" id="post-<?php the_ID(); ?>"><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link: <?php the_title(); ?>"><?php the_title(); ?></a></h3>
    <?php } else { ?>
        <?php the_date('','<h2>','</h2>'); ?>

        <div class="post">
            <h3 class="storytitle" id="post-<?php the_ID(); ?>"><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link: <?php the_title(); ?>"><?php the_title(); ?></a></h3>

            <div class="meta">
                <?php _e("Filed under:"); ?> <?php the_category() ?> &#8212; <?php the_author() ?> @ <?php the_time() ?> <?php edit_post_link(); ?>
            </div>

            <div class="storycontent">
                <?php the_content(); ?>
            </div>

            <div class="feedback">
                <?php wp_link_pages(); ?>

                <?php comments_popup_link(__('Comments (0)'), __('Comments (1)'), __('Comments (%)')); ?>
            </div>

            <!--
            <?php trackback_rdf(); ?>
            -->

            <?php include(ABSPATH . 'wp-comments.php'); ?>
        </div>
    <?php }

    endforeach; else: ?>
        <p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
    <?php endif; ?>
</div>


The process would be just as easy to change what appears in the sidebar of your page…just edit the <div id="menu"> section. Once you get the hang of it, these variables can be used to manipulate just about anything.

Taking It a Step Further

Adding in code for each of these page types can get confusing really fast. With that much information packed in to one file, the scanability of index.php drops considerably and it becomes difficult to find what you want when you need it.

To combat this, I’ve taken the fake template concept a step further…rather than listing all of the code directly in index.php, I use PHP includes to import each custom section from an external file. Rather than make this tutorial any longer than it already is, here’s how I set it up:

<div id="content">
    <?php
    if ($posts) : foreach ($posts as $post) : start_wp();
        // Faking multiple templates
        if ($single) {
            require('includes/single.php');
        } else if ($cat) {
            require('includes/category.php');
        } else if ($m) {
            require('includes/month.php');
        } else if ($year) {
            require('includes/year.php');
        } else {
            require('includes/main.php');
    }
    endforeach; else:
        require('includes/nomatches.php');
    endif;
    ?>
</div>

In the external files themselves, simply put what content you want to appear, and that’s it! I hope this helps some of you guys out.

28 Comments

  1. Posted October 8th, 2004 at 4:01am | Permalink

    Thanks for this great tutorial!!!

    It is very useful and I will try to use it on our site 8-) But at the moment I have a very strange problem with the pagenavi, I have to solve this first…

    greetings from Lueneburg

  2. Posted October 9th, 2004 at 10:00am | Permalink

    This looks like a good solution – I was looking for something exactly along these lines. Not using .htaccess and using existing functionality instead. One question though. I am using .htaccess for permalinks – is this solution going to interfere with that?

  3. Posted October 9th, 2004 at 2:39pm | Permalink

    Nope, this technique won’t interfere with clean permalinks at all. It works exactly the same whether you use .htaccess or not…that’s one of the reasons I like it :-)

  4. Posted October 10th, 2004 at 3:31am | Permalink

    Thank you!!!!!!!!

  5. Posted October 11th, 2004 at 12:07pm | Permalink

    Nice tutorial. The code is also nicely displayed, well done.

    I use code that is the same as yours for my categories but the display order is by date (as nearly everything is in Blog software!)but I need it alphabetized from the post title. Is there any easy way?

    TIA
    Phillip

  6. Posted October 11th, 2004 at 12:14pm | Permalink

    Thanks for this. It will certainly help.
    One question–
    Is there a variable for what you see on the index, where the postings are listed?

    thanks again-
    Ron

  7. Posted October 11th, 2004 at 7:36pm | Permalink

    I’ve read over this a few times and think I understand it now; and answered my own question about the index (answer: none of those variables are populated).

    I’m going to find a tutorial on php includes.

    How would one not show something that was outside of the loop? I have static content on another part of the site. Can I import a new stylesheet based on one of those variables?

  8. Posted October 11th, 2004 at 10:34pm | Permalink

    “answer: none of those variables are populated”

    Correct!

    “How would one not show something that was outside of the loop?”

    These tests can be executed anywhere within your index.php file. There are two options…you can do a test to show something extra:

    if ($single) {
        \\ Show this content ONLY on individual entries
    }
    

    …or the negative of that test to take something away:

    if (!$single) {
        \\ Show this content on everything BUT individual entries
    }
    

    Yes, you could use this technique to import a different style sheet depending on the page type.

    I got busy today and didn’t get the chance to clarify this more in the entry, but likewise, if you want to show some static content additional to what would usually be in the loop, just do the testing outside of the loop, then put the loop structure back inside of each of the individual tests, fitting your content around it.

  9. Dennis
    Posted October 14th, 2004 at 7:15am | Permalink
    if ($single) {
        require('includes/single.php');

    I would recommend putting these files in wp-content/somedir instead of includes. It would prevent possible future name collision.

  10. Posted October 14th, 2004 at 8:14am | Permalink

    That’s a good point Dennis. I forgot that I’ve changed the structure of my site, so my includes aren’t actually in the WordPress directory structure at all…my index.php file is located at the root of my site, but all the WordPress files have their own directory in order to keep things clean.

  11. Posted October 14th, 2004 at 9:52am | Permalink

    Wonderful – I’d be doing something similar, but using $p instead of $single, which was preventing me from using a permalink structure. This solves that problem though.

  12. Posted October 21st, 2004 at 11:41am | Permalink

    Good work Aaron. Smart thinking. Even a PHP-challenged bonehead like me can follow your clear and concise instructions. Thanks. This is going to come in VERY handy. Keep up the good work.

  13. Posted November 20th, 2004 at 10:46am | Permalink

    Hi, just wanted to drop by and thank you for the tutorial. I know nothing about PHP, but with the help of your code and after some poking around in the WordPress documentation I was able to generate category pages with dates and excerpts in addition to the post titles. Really a nice solution.

  14. Posted December 12th, 2004 at 4:13pm | Permalink

    This is how I did OrangePolitics.org. It works great.

    Now I’m in the process of moving my static website and Blogger-run blog over to WP and I’m going to through the same thing. Some of teh conditions are a little more complicated because I want the category listing to look different if it’s the “blog” category. Fun! ;=}

  15. Posted December 13th, 2004 at 7:35pm | Permalink

    Just wanted to say “Thank you”. I’ve been searching for a method like this for a while now and you’ve provided me with the solution.

    Great work.

  16. Posted December 18th, 2004 at 10:58am | Permalink

    Thank you for your clean, concise
    and thoroughly understandable tutorial. Not only that, your instrucions serve as an example for people like me who’s not as dumb as many think, to actually go out on a limb, poke around php and do some experimentation.

  17. Michiel
    Posted December 20th, 2004 at 12:51pm | Permalink

    Hi! There are some errors on the page: the code is not showing, example:

    “section of your index.php file to be something like this:

    [The requested file http://elasticdog.com/code/2004/10/wp-template-example.txt could not be found]

    The process would be just as easy to change what appears in the sidebar”

  18. Posted December 22nd, 2004 at 10:13am | Permalink

    does anyone else have trouble implementing the $m variable? Since i am using the permalink structure blog/year/month/title/ – the year variable takes over whether it is a year view or month view. Having a poor understanding of php, is there someway that I can use something to the degree of elseif {$m && $year}??

    thanks,.
    amory

  19. Michiel
    Posted December 25th, 2004 at 6:05am | Permalink

    Hi! I have now been poking around with the code… above you say it would be easy to change what appears in the sidebar of your page? just edit the <div id="menu"> section. How do I do that to for example remove the calendar from the page? Example would be: user clicks on a permalink of content in category 2 in the blog roll. Once opened the calendar should be removed from the screen.

  20. Posted December 28th, 2004 at 3:57pm | Permalink

    Hmmmm, so I coudl introduce variables to the else if ($cat) bit and create templates for each category as includes?

    Actually, since all I am doing is making a different graphic for the sidebar, I suppose I could just place the graphic there, name it as the category and use one template.

    Sheesh, I love overcomplicating things.

  21. imissmymt
    Posted January 8th, 2005 at 1:51am | Permalink

    Thank you, thank you, thank you!

  22. RK
    Posted October 8th, 2005 at 2:23am | Permalink

    Your code in the post is not showing up: [The requested file http://elasticdog.com/code/2004/10/fmt01.txt could not be found]

  23. Posted October 16th, 2005 at 5:22pm | Permalink

    the references to your code arent shown anymore :(

    [The requested file http://elasticdog.com/code/2004/10/fmt01.txt could not be found]

  24. Posted April 8th, 2006 at 11:16am | Permalink

    Uh, there *are* multiple templates.

    archive.php for post archives, month.php for month view, category.php for category (and category-id.php for specific categories), and so on…

    It falls back, so if you don’t have one template it falls back to another one.

  25. Posted May 13th, 2006 at 9:08am | Permalink

    I’m pretty naive with php still, but this SEEMS to be what I’ve been looking for since September last year. Couple questions:

    1. Is it still valid in WP 2.0x?

    2. Would I be able to use this to create unique page renderings for different category listing pages? For instance, have different sidebars and headers on EACH different category listing page. Or, more accurately, on selected category listing pages.

    For instance, on the category listing page that calls up a summary of every article ever posted about ‘Nighttime light pollution” might have a header that showed a glowing city nightscape and might have a sidebar that contained lots of links to outside sites that deal with specifics of this issue; while…. A category listing page about “Clean air” might have a header image that shows a murky, smoggy sky obliterating the view of a red-rock arch in Utah, and the sidebar might feature links to outside sites that deal specifically with this issue.

    I’d like to be able to do that with–in time–several dozen category-listing pages.

    Can I do that somehow with your clever workaround?

    Thanks,
    kwc

  26. afton
    Posted June 12th, 2006 at 12:43am | Permalink

    Perfect pages… tnx

  27. Posted September 26th, 2007 at 8:52am | Permalink

    Aaron,
    It seems that some code has diseappeared from your post… Between
    here

  28. Jesse
    Posted September 12th, 2009 at 12:14pm | Permalink

    Thank you. so. much.

Post a Comment

Your email address is never published nor shared. Required fields are marked *

*
*