The WordPress Theme Index Template

Update: We’ve created a second edition of this article, with updated code samples and coverage of the latest theme development techniques. Check it out at The WordPress Theme Index Template. It’s part of The ThemeShaper WordPress Theme Tutorial: 2nd Edition.

Index.php is the most crucial WordPress Theme Template. Not only because WordPress needs to use it if you’re missing any of it’s brother and sister templates (like, category.php or tag.php) but because the work we do here, getting this template right, will help us breeze through the rest of our templates (with the exception of the dreaded comments template; that’s just plain difficult no matter how you look at it).

The Loop

Even though it’s stuck right in the middle of your template, in a metaphorical sense index.php begins and ends with The Loop. Without it you don’t have anything. Here’s what it looks like.

<?php while ( have_posts() ) : the_post() ?>
<?php endwhile; ?>

Simple really. And not even deceptively simple. While you’ve got posts in your database your theme will loop through them and for each one, do something. Getting the “do something” just right is the tricky part. But even that can be simple.

Try out this loop to get started and we’ll work on building it up. Put the following code inside your #content div in index.php.

<?php while ( have_posts() ) : the_post() ?>
<?php the_content(); ?>
<?php endwhile; ?>

What do you get if you do that? All the post content in a big smushed up pile. But it could be different.

<?php while ( have_posts() ) : the_post() ?>
    <?php the_excerpt(); ?>
<?php endwhile; ?>

Do you see what we just did there? Now you’ve got an unordered list of post excerpts. (Plus, now you can see what the_content() and the_excerpt() do)

Basically, you make a loop (starts with while ends with endwhile) and put some stuff in it—stuff being WordPress Template Tags that pull information out of the posts we’re looping though, just like bloginfo() pulled information out of our WordPress settings in the last lesson.

Alright, let’s make a really awesome loop. Let’s start with our basic, smushed up one. But we’ll make sure it’s ready for the More Tag and the Next Page Tag. We’ll also put it in it’s own div and let machines know it’s the content of a blog post with the microformat class “entry-content”.

					<div class="entry-content">
<?php the_content( __( 'Continue reading <span class="meta-nav">&amp;raquo;</span>', 'your-theme' )  ); ?>
<?php wp_link_pages('before=<div class="page-link">' . __( 'Pages:', 'your-theme' ) . '&amp;after=</div>') ?>
					</div><!-- .entry-content -->

How about the post title? That’s pretty simple too. We’ll use the Template Tag the_title() to get the title of the post and wrap it in an a tag that links to the_permalink() (that’s the permanent link to any particular post). We’ll also add in a title attribute and another microformat (bookmark) that tells machines (like Google) that this is the permalink to a blog post. Try putting the following just above the .entry-content div.

					<h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( __('Permalink to %s', 'your-theme'), the_title_attribute('echo=0') ); ?>" rel="bookmark"><?php the_title(); ?></a></h2>

Now for all the extra bits that attend to any blog post: who wrote it, the time it was published, categories, tags, comments links. I like to break all this up into two sections: the meta stuff (author and entry date) which I put before the post content, and the utility stuff (categories, tags and comments link) that I put after the content. And both sections We’ll also put the post in it’s own containing div with the title.

Let’s take a look at the whole loop together. I’ve inserted some PHP comments in here to help guide you along.

<?php /* The Loop — with comments! */ ?>
<?php while ( have_posts() ) : the_post() ?>

<?php /* Create a div with a unique ID thanks to the_ID() and semantic classes with post_class() */ ?>
				<div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<?php /* an h2 title */ ?>
					<h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( __('Permalink to %s', 'your-theme'), the_title_attribute('echo=0') ); ?>" rel="bookmark"><?php the_title(); ?></a></h2>

<?php /* Microformatted, translatable post meta */ ?>
					<div class="entry-meta">
						<span class="meta-prep meta-prep-author"><?php _e('By ', 'your-theme'); ?></span>
						<span class="author vcard"><a class="url fn n" href="<?php echo get_author_link( false, $authordata->ID, $authordata->user_nicename ); ?>" title="<?php printf( __( 'View all posts by %s', 'your-theme' ), $authordata->display_name ); ?>"><?php the_author(); ?></a></span>
						<span class="meta-sep"> | </span>
						<span class="meta-prep meta-prep-entry-date"><?php _e('Published ', 'your-theme'); ?></span>
						<span class="entry-date"><abbr class="published" title="<?php the_time('Y-m-dTH:i:sO') ?>"><?php the_time( get_option( 'date_format' ) ); ?></abbr></span>
						<?php edit_post_link( __( 'Edit', 'your-theme' ), '<span class="meta-sep">|</span><span class="edit-link">', '</span>' ); ?>
					</div><!-- .entry-meta -->

<?php /* The entry content */ ?>
					<div class="entry-content">
<?php the_content( __( 'Continue reading <span class="meta-nav">&amp;raquo;</span>', 'your-theme' )  ); ?>
<?php wp_link_pages('before=<div class="page-link">' . __( 'Pages:', 'your-theme' ) . '&amp;after=</div>') ?>
					</div><!-- .entry-content -->

<?php /* Microformatted category and tag links along with a comments link */ ?>
					<div class="entry-utility">
						<span class="cat-links"><span class="entry-utility-prep entry-utility-prep-cat-links"><?php _e( 'Posted in ', 'your-theme' ); ?></span><?php echo get_the_category_list(', '); ?></span>
						<span class="meta-sep"> | </span>
						<?php the_tags( '<span class="tag-links"><span class="entry-utility-prep entry-utility-prep-tag-links">' . __('Tagged ', 'your-theme' ) . '</span>', ", ", "</span><span class="meta-sep">|</span>" ) ?>
						<span class="comments-link"><?php comments_popup_link( __( 'Leave a comment', 'your-theme' ), __( '1 Comment', 'your-theme' ), __( '% Comments', 'your-theme' ) ) ?></span>
						<?php edit_post_link( __( 'Edit', 'your-theme' ), '<span class="meta-sep">|</span><span class="edit-link">', '</span>' ); ?>
					</div><!-- #entry-utility -->
				</div><!-- #post-<?php the_ID(); ?> -->

<?php /* Close up the post div and then end the loop with endwhile */ ?>

<?php endwhile; ?>


Now we need a way to navigate back through our posts. We’ll do this with 2 WordPress Template Tags: next_posts_link() and previous_posts_link(). These 2 functions … they don’t do what you think they do. I think the WordPress codex says it best.

next posts link
This creates a link to the previous posts. Yes, it says “next posts,” but it’s named that just to confuse you.
previous posts link
This creates a link to the next posts. Yes, it says “previous posts,” but it’s named that just to confuse you.

Just like everything in index.php, post navigation needs to be given some careful thought when we’re building it for the first time because we’re going to wind up using it on almost every page in our blog.

I like to have post navigation above and below the content. Depending on how you use this code in any particular situation, you may not use it though. No matter, we can always hide it like so.

.single #nav-above {

That CSS will hide post navigation above the content on single posts.

We’ll also want to hide any navigation code IF there’s nothing to navigate too. That is, if, say, on a search, there are no older pages of posts, we don’t want to output any navigation code at all to the browser. We’ll do that by wrapping our code in the following statement:

<?php global $wp_query; $total_pages = $wp_query->max_num_pages; if ( $total_pages > 1 ) { ?>
<?php } ?>

What we’re doing is checking to see what the maximum number of pages is in any loop we’re going to be looking at and if the number of pages is greater than 1, we’ll output our navigation.

Alright, here’s the code we’ll need for your navigation, top and bottom, just before, and just after the loop.

<?php /* Top post navigation */ ?>
<?php global $wp_query; $total_pages = $wp_query->max_num_pages; if ( $total_pages > 1 ) { ?>
				<div id="nav-above" class="navigation">
					<div class="nav-previous"><?php next_posts_link(__( '<span class="meta-nav">&amp;laquo;</span> Older posts', 'your-theme' )) ?></div>
					<div class="nav-next"><?php previous_posts_link(__( 'Newer posts <span class="meta-nav">&amp;raquo;</span>', 'your-theme' )) ?></div>
				</div><!-- #nav-above -->
<?php } ?>


<?php /* Bottom post navigation */ ?>
<?php global $wp_query; $total_pages = $wp_query->max_num_pages; if ( $total_pages > 1 ) { ?>
				<div id="nav-below" class="navigation">
					<div class="nav-previous"><?php next_posts_link(__( '<span class="meta-nav">&amp;laquo;</span> Older posts', 'your-theme' )) ?></div>
					<div class="nav-next"><?php previous_posts_link(__( 'Newer posts <span class="meta-nav">&amp;raquo;</span>', 'your-theme' )) ?></div>
				</div><!-- #nav-below -->
<?php } ?>

One last thing and we’re done index.php. You’ll be itching to see what we can do with it, but for now we’re just going to put in the function call just before get_footer().

<?php get_sidebar(); ?>

How To Create a WordPress Theme

This post is part of a WordPress Themes Tutorial that will show you how to create a powerful WordPress Theme from scratch. Read it from the beginning and code yourself up something awesome.

  1. WordPress Theme Tutorial Introduction
  2. Theme Development Tools
  3. Creating a Theme HTML Structure
  4. Template and Directory Structure
  5. The Header Template
  6. The Index Template
  7. The Single Post, Post Attachment, & 404 Templates
  8. The Comments Template
  9. The Search Template & The Page Template
  10. The Archive, Author, Category & Tags Template
  11. The Sidebar Template
  12. Reset-Rebuild Theme CSS & Define Your Layouts

42 thoughts on “The WordPress Theme Index Template”

  1. nice. i’m loving these step by steps. thanks.

    i don’t understand what the ‘your-theme’ piece is or what its for though.

  2. I’m a little unclear of where entry-content is supposed to go. Could you make things more clear by including the line directly prior and directly after where the code should be entered?

    Also, would you consider showing how each of the changed files should look in their entirety at the end of each post, or would that be overkill?

    1. I’m struggling too with where to put this new code too. I’ll read it again and see if it hits me.

      1. It goes in #content which you said at the top of the page. Of course there are a few exceptions which you noted. 🙂

  3. Ian, there are total 28 errors on your style.css after W3C CSS validation. But I found no problems for your theme while viewing, so do you think W3C makes mistakes too? Or we do not need to rely on it when creating themes?

    1. You mean my ThemeShaper CSS, Young? It’s beside the point when it comes to this tutorial but if you look at the errors they’re not exactly “errors”. The validator is choking on proprietary browser properties that mimic eventual CSS3 properties. And choking on CSS3 properties too.

      Do you need to rely on valid code? No. As long as you know why and how your code isn’t valid. You can have a pixel-perfect, perfectly accessible site without valid code. You should always shoot for it but—if you have valid reasons of your own—not feel constrained by it.

  4. Hi, thanks for this tutorial. It’s very usefull. I’m following it and i cut and paste the code for creating a navigation but when i preview the blog i can’t see the navigation links. Why?
    Thank you!

    1. use a query and put it before the loop like this:

      replace “blog” with the name of your category, and replace “5” with the number of posts you want to display.

  5. hmm… cut out my code… maybe this will work?
    in php brackets:

    1. Broom, does that query replace this line; max_num_pages; if ( $total_pages > 1 ) { ?>
      or is it first or what?

  6. In the thematic theme, there is more information in the post class than is in the WordPress post_class(). Is there a way to add some of that additional information into the post class using a function? Say, for example, one wanted to add the “comments-open” or “comments-closed” class to post_class()? Or the post author?

  7. Hey,

    Great tutorial! Been easy to follow so far, but now I’m confused. Where is the ‘entry-content’ div supposed to go?


  8. So I really loved the “Making a new Page Theme” post and was very successful in making a very clean Page Template I called static_page Theme. So simple it contains only a Header, body, and footer tags.
    The result of the static page template is here at my testing site:
    However, instead of the single image in the body portion of the page I would like to insert a table with 2 cells, the left cell would have a graphic and the right cell would contain code that shoots me your email address. I made such a page in HTML (you can view it here: ) but would like to bring it into WordPress.

    My question is, how do I insert a picture on the left and code on the right that shoots me your email when you enter it. Thanks in advance for the help – I love the ‘Thematic’ theme !!

  9. Firstly, thank you so much for taking the time to create a tutorial on coding your own theme. I can definitely appreciate the time it takes and the effort you’ve given.

    That being said, I’m a bit disappointed. I have followed your tutorial up to this point and I just have no idea why you add each line of code. I think it’d be a bit more helpful if you explained each line /why you need it and made us type them out as we go, instead of copying and pasting. I can’t understand why I failed miserably if I don’t know what it is I’m coding and why….

    I have previously followed Small Potato’s tutorial and I understood every line of code I wrote. I am upset that he stopped running the site and with all the new updates of WordPress his is kind of outdated. His teaching style was a bit easier to understand and retain.

    Definitely not knocking your effort, just wish as a newbie, you ‘d be a lil’ more in depth. =)

  10. thanx for ur well tutorial. i like that.

    but something, i m in confusion.
    under which tag i will put the navigation code?

    plz reply me soon

    note that, i m new in word press
    and beginner in web languages

  11. Before I start, thanks for this tutorial. It’s helped me out a lot when designing my own site (not finished yet, but it helped).

    Now, I do have one important question: Is this theme compatible with multiple loops? I ask because I’m working on a webcomic site (using the Webcomic plugin) and it needs to use two loops: one for the latest comic and its post, and one for the rest of the blog items that don’t belong on the designated comic categories. I followed the instructions on how to set up the second loop (basically copy/paste the whole loop above the regular loop and add the template tags), and it works – mostly. The comic displays fine and you can switch from page to page without any bugs, but while it’s on the main page the comic loop shows the latest post instead of the designated comic post. I used the same method on a couple of other themes and it worked fine for them, so why can’t I do it with this theme? Do I have to set it up a different way or something?

    Please respond soon, and thanks.

  12. Hi,
    I”m tweaking a theme which didn’t have a comment link under posts. I have added the comment link but here is the problem: I don’t want it to show the comment link if commenting for that post is disabled.
    how do i do that?

    thank in advance for the help

  13. in the loop code – where is the opening tag for the “<!– #post-"

    its the last div in the while/endwhile loop but i cant seem to find the opening

    1. nm- i see that its there. its just the coloring in my text editor that made it look like there was an extra div in there.

  14. I’m trying to follow in the index page layout and I don’t understand why new posts aren’t being pulled when I use the “older entries” and “newer entries” links. I don’t really see any code that necessarily forces the next page of entries.

    Any help? Thanks.

  15. This is great.
    Can you please explain how to take advantage of the unique divs created by this line:
    <div id="post-” >
    Obviously, you aren’t creating a style sheet with a style like this:
    #post-2440 { };
    What purpose is served?
    Thanks a lot!

  16. i’m beginning to like it.. I’m following it .. Step by Step!! Hope this is done before my jobs.. 🙂 Thanx for the instructions.. 🙂 Loved it..

  17. Just a quick question about the _e function.

    After a quick google I’ve found this is to do with internationalization, therefore in the following from your tutorial ‘By’ can be translated, however I’ve found no reference for the second argument, in our case the theme name.

    This second argument isn’t output in the resulting source, and a google offers no answers.

    Can you shed some light?

    Thanks in advance


  18. Starting to find it confusing this page now. I did what was asked and then go to a certain point where it went over my head. A little more explanation and example of a theme you are building would be better to show. Not all you write is clear and concise but good starting point for someone who is not into html much.

  19. Everything was going well until I hit the top and bottom post navigation (older and newer posts) – nothing shows up… Copy/pasted inside #content, just before and after the loop, as per the instructions…

  20. Hey Ian! Everything seems to work fine, until I plug in the extended loop with comments code. I’m copying and pasting exactly, but when I load my page I’m getting the error: Parse error: syntax error, unexpected ‘meta’ (T_STRING) in C:\wamp\www\wordpress\wp-content\themes\mytheme\index.php on line 37. Any hints as to why?

    1. Hi Bill, try looking on line 37 of your index.php file in a code editor that can highlight PHP code to show syntax errors. You may be missing a small required bit of the code, like a ” or } or ; or other necessary character.

  21. btw, line 37 also draws a syntax error in Dreamweaver. The line is this:

    <?php the_tags( '’ . __(‘Tagged ‘, ‘novalumen’ ) . ”, “, “, “|” ) ?>

Comments are closed.