DiggingIntoWordPress

by Chris Coyier & Jeff Starr

Definitive Guide to WordPress Post/Page Navigation

Posted by on

There are many ways to navigate a WordPress-powered site. There are archive links, category links, page links, internal post links, single post links, admin comment links, tag links, and many other types of navigational links. When it comes to navigating sequentially through your site’s chronological archive pages, category archives, and other types of archive pages, WordPress provides several useful template tags designed to dynamically link the pages together. Likewise, for single permalink post-views, WordPress provides a set of template tags that connects the pages together in chronologically sequential fashion.

When used properly, these page-navigation template tags enable your visitors to browse your site quickly and easily. Unfortunately, these different template tags have similar names, parameters, and functionality, thereby leaving many WordPress designers dazed and confused.

In this DiW article, we’ll dig into each of these different navigational tags and explain each of them in-depth, with plenty of juicy examples to help you take advantage of their full functionality.

Here are the three sets of template tags we’ll be exploring (click on a tag name to jump to that section):

 ] The posts_nav_link() template tag provides a combined pair of “next” and “previous” navigational links for any type of paged archive view. Basically, this tag creates paired navigational links for anything other than single-post views. This includes index, category, archive, tag, and search pages. Best results when used either before or after the loop. Here is an example of the tag showing its three accepted parameters:

<?php posts_nav_link('sep','prelabel','nxtlabel'); ?>

Default usage

Here is the default usage of this template tag, followed by its corresponding output:

<?php posts_nav_link(); ?>

« Previous PageNext Page »

Parameters

Values for each of the following parameters are strings that may be specified in alphanumeric characters or (X)HTML markup:

<?php posts_nav_link('sep','prelabel','nxtlabel'); ?>

  • sep — text/markup that is displayed between the links
  • prelabel — text/markup that is used as the link text for the previous page
  • nxtlabel — text/markup that is used as the link text for the next page

Caution: it’s all backward

Keep in mind that the default implementation of the posts_nav_link() template tag generates links that are essentially backward in order: the “Previous Page” navigation link points to newer posts, while the “Next Page” navigation link points to older posts. Exactly the opposite of what you would expect. Normally, previous posts are older and next posts are newer. To fix this backward behavior, we could simply customize the link text of either navigation link like so:

<?php posts_nav_link(' &bull; ','&laquo; Go forward in time','Go back in time &raquo;'); ?>

This would then generate the following links on your archive pages:

« Go forward in timeGo back in time »

This reflects reality to a greater degree, however the links still seem to appear out of order. It just seems counter-intuitive to have the “Go forward” link on the left side of the page and the “Go back” link on the right side of the page. It seems more intuitive and natural to assume the reverse, link left to go back and link right to go forward. Just like reading a book.

Fortunately, there are two ways to get the links to appear in the reverse (i.e., correct) order. Both methods require us to separate the navigational links so that they may be repositioned with the “Go back” link on the left side of the page and the “Go forward” link on the right. How we go about separating the links depends on the template tag that is used. There is a workaround the posts_nav_link() tag, but it is far easier to simply use the previous_posts_link() and next_posts_link() tags instead. We’ll get to the easy way in the next section; for now, let’s look at the workaround for the posts_nav_link() tag.

To separate the navigational links created by the posts_nav_link() tag, we use two instances of it on the page. In the first instance, we kill the “Go forward” link, and in the second instance we kill the “Go back” link. The result is the following code, which provides us with two properly identified navigation links that may be situated in the correct order:

<?php posts_nav_link('','','Go back in time &raquo;'); ?> &bull; <?php posts_nav_link('','&laquo; Go forward in time',''); ?>

Perhaps the best way to understand this technique is to sequentially test each of the following navigation templates. Along the way, keep an eye on where the links are appearing on the page and where the links are pointing:

<?php posts_nav_link(); // default tag ?>

<?php posts_nav_link(' &bull; ','&laquo; Go forward in time','Go back in time &raquo;'); // switched text ?>

<?php posts_nav_link('','','Go back in time &raquo;'); ?> &bull; <?php posts_nav_link('','&laquo; Go forward in time',''); // switched text and reversed order ?>

“And that’s all I have to say about that,” as the man once said. Let’s break out of this nightmare and move on to some fresh examples.

Examples

Here are some examples to demonstrate the use and flexibility of the posts_nav_link() template tag:

Your basic navigation

Out of the box, the posts_nav_link() template tag displays your navigation links in reverse order, but you can still customize the text to make things a little clearer for your readers. One of the benefits of sticking with the default busted configuration is that you will never have to deal with empty markup elements that may appear when there are no newer or older posts to display. If squeaky-clean source code tickles your fancy, customize the default tag as needed and enjoy the results:

<?php posts_nav_link(' &bull; ','&laquo; Go forward in time','Go back in time &raquo;'); ?>

Keep ‘em separated

What if you want to display your “Previous” link on the left side of the page and the ”Next” link on the right side of the page? We can acheive this effect by using two instances of the posts_nav_link() template tag (note that this configuration also resolves the “backward-navigation” issue discussed above):

<div class="left">
	<?php posts_nav_link('','','&laquo; Older Posts'); ?>
</div>
<div class="right">
	<?php posts_nav_link('','Newer Posts &raquo;',''); ?>
</div>

Keep ‘em separated with images

Continuing with the previous example, let’s keep the navigation links separate, but use images instead of text:

<div class="left">
	<?php posts_nav_link('','','<img src="images/older.png" />'); ?>
</div>
<div class="right">
	<?php posts_nav_link('','<img src="images/newer.png" />',''); ?>
</div>

Remember, you can use any text or markup you need in this template tag, so knock yourself out and conjure up something fresh.

 ] The previous_posts_link() and next_posts_link() template tags provide separate “next” and “previous” navigational links for any type of paged archive view. Basically, this tag creates individual navigational links for anything other than single-post views. This includes index, category, archive, tag, and search pages. Best results when used either before or after the loop. Here is an example of these tags showing their two accepted parameters:

<?php previous_posts_link('label','max_pages'); ?>

<?php next_posts_link('label','max_pages'); ?>

Default usage

Here is the default usage of these template tags, followed by their corresponding output (bullet added for clarity):

<?php previous_posts_link(); ?> &bull; <?php next_posts_link(); ?>

« Previous PageNext Page »

Parameters

Here are the accepted parameters for each of these template tags:

<?php previous_posts_link('label','max_pages'); ?>
<?php next_posts_link('label','max_pages'); ?>

  • label — alphanumeric string and/or markup used for the link text
  • max_pages — an integer that limits the number of pages on which the link is displayed. The default value is “0” for all pages.

These are backward too

Like the posts_nav_link() tag, the previous_posts_link() and next_posts_link() create links that do the opposite of what you expect them to do. The previous_posts_link() tag links to newer posts and the next_posts_link() tag links to older posts. Again, exactly the opposite of what you would expect.

Fortunately, these tags create links that are spearate from one another, enabling us to implement them according to conventional methods of navigation. Simply customize the link text such that it means the opposite of the tag’s name and then switch the tags’ order in the source code. Let’s look at a few examples to help clarify this technique.

Examples

Here are some examples to demonstrate the use and flexibility of the previous_posts_link() and next_posts_link() template tags:

Customized link text

To keep the navigation operating conventionally, simply switch the meaning of the link text to convey the opposite meaning of the template tag and then position the tags accordingly:

<?php next_posts_link('&laquo; Previous posts'); ?> <?php previous_posts_link('Next posts &raquo;'); ?>

Default WordPress theme

Even the default WordPress theme, Kubrick, uses this technique to display proper navigational links in the correct order and on opposite sides of the page:

<div class="navigation">
<div class="alignleft"><?php next_posts_link('&laquo; Older Entries') ?></div>
<div class="alignright"><?php previous_posts_link('Newer Entries &raquo;') ?></div>
</div>

Thus, we see how to use the previous_posts_link() and next_posts_link() template tags to easily display your post-archive navigational links appear in the conventional, intiuitive, and correct order. Problem solved.

Keep ‘em separated with images (best method)

Here’s the proper way to create navigational links using images instead of text:

<div class="left">
	<?php next_posts_link('<img src="images/older.png" />'); ?>
</div>
<div class="right">
	<?php previous_posts_link('<img src="images/newer.png" />'); ?>
</div>

And as before, you may use any text or markup with this template tag, making it possible to integrate into just about any design.

 ] The previous_post_link() and next_post_link() template tags provide separate links to the previous post and next post, respectively. In doing so, these tags enable visitors to navigate chronologically through your single post permalink pages. These tags may be used anywhere on the sinlge.php template page, either in or out of the loop. Here is an example of these tags showing their four accepted parameters:

<?php next_post_link('format','link','in_same_cat','excluded_categories'); ?>

<?php previous_post_link('format','link','in_same_cat','excluded_categories'); ?>

Default usage

Unlike other navigational tags, next_post_link() and previous_post_link() eliminate navigational confusion and ambiguity by using actual post titles for their link text. Here are some examples of the default usage of these tags, followed by their corresponding output (bullet added for clarity):

<?php previous_post_link(); ?> &bull; <?php next_post_link(); ?>

« Previous Post TitleNext Post Title »

Parameters

Here are the accepted parameters for each of these template tags:

<?php next_post_link('format','link','in_same_cat','excluded_categories'); ?>
<?php previous_post_link('format','link','in_same_cat','excluded_categories'); ?>

  • format — format string for the link. Here you specify the text/HTML to appear before and after the link. The link itself is specified according to the link parameter by including the %link variable in the format string. For example, a format value of “Next: %link &raquo;” will result in the following output: “Next The Post Title »”
  • link — link text to display. Anything specified here will be used as the %link variable in the format parameter (see previous). By default, this parameter returns the post title via the %title variable. For example, a link parameter with a value of “[[%title]]” will result in the following output: “[[The Post Title]] »”
  • in_same_cat — boolean value indicating whether or not the next or previous post must be in the same category as the current post. If set to TRUE, only posts from the current category will be displayed. Options are: TRUE or FALSE (default).
  • excluded_categories — string indicating any collection of category IDs from which the next post should not be listed. In all versions of WordPress except 2.2, multiple categories are separated via “ and ”, for example: ‘1 and 3 and 7’ Oddly enough, in WordPress version 2.2, a comma is used to concatenate multiple excluded categories, for example: ‘1, 3, 7

Examples

Here are some examples to demonstrate the use and flexibility of the previous_post_link() and next_post_link() template tags:

Custom title with link description before/after post link

Here we are displaying custom link titles with the text “Previous post: ” and “Next post: ” appearing before the previous and next post, respectively:

<?php previous_post_link('Previous post: %link', '[ %title ]'); ?> &bull; 
<?php next_post_link('Next post: %link', '[ %title ]'); ?>

Links to posts within the same category, excluding one

Here is how to display next and previous post links only to posts that are in the same category as the current post unless the current post is in category 7. Any number of categories may be excluded from this “same-category” navigation by using “ and ” as a delimiter:

<?php previous_post_link('%link', '%title', TRUE, '7'); ?> &bull; 
<?php next_post_link('%link', '%title', TRUE, '7'); ?>

Display images as links

Instead of using text for the next/previous-post links, we can use a custom set of images:

<?php previous_post_link('%link', '<img src="images/older.png" />', TRUE, '7'); ?> &bull; 
<?php next_post_link('%link', '<img src="images/newer.png" />', TRUE, '7'); ?>

Indeed, there is much that may done with this set of template tags. If you know of any juicy tricks not covered here, share them in the comments!

One for the road

Every now and then, you may encounter an older WordPress theme that includes the following navigation tags:

<?php previous_post(); ?>
<?php next_post(); ?>

For the record, these are the now-deprecated predecessors of the previously discussed previous_post_link() and next_post_link() template tags. The deprecated versions provide navigation of single permalink post views and use essentially the same parameters as the current tags. Now you know! :)

References

31 Responses

  1. Great article!

    Page navigation has always been a bit of a misty subject for me…

  2. Guys, love this site, thanks for this, this answered so many questions.

  3. Mark Fulton August 25, 2009

    Great guide here, thank you.. will be sharing this with my WordPress buddys.

    Maybe you can point me in the right direction because I have a serious problem related to pagination.

    My WordPress install has been broken for some time now… I have tried in vain to search for a solution as to why my http://www.dotsauce.com/page/2/ directory structure does not work. It simply shows the homepage content.

    I have tried disabling all plugins and it still happens. If anyone can help it would be greatly appreciated.

  4. Very nice article, good job. Nice info about wp page nav`s.

  5. Hi Jeff,
    Thanks very much for sharing. I will try today !
    I really love your site

  6. Great tutorial!

    How about an example of using images instead of Prev/Next text link, with hover effect :)

  7. I am using a parent page to list its child pages.
    I am set to show 9 posts per page.

    I need some page nav to get people to the rest of the pages of results.

    when I use it does load up the correct number of pages, but my query only shows the same 9 items listed.

    any ideas?

    the query looks for child pages of the current parent page.

    • Jeff Starr

      It sounds like you might be using the query_posts function? If so, there is a known issue with pagination not working with it. You may need to put the query into a variable or else use a custom single template for the post display. See this support thread for more info.

    • oh and just to reiterate. These are actual PAGES and not posts.
      So there is a parent page named “spots” and it has a query to list all of it’s child pages.

  8. the wordpress navigation is lacking, but with wp page navi its a better place to play. http://wordpress.org/extend/plugins/wp-pagenavi/

  9. wow. that is quite a thread.
    I opted to put my pages in as posts instead and used a category for them.

    This way whenever we add new ones or update it, there will be a way of letting people know on the front of the site when it’s been updated.

    I am interested though in that thread and of course now, am going to go play around!

  10. great site with compelling content. thanks!

  11. Travis Neilson September 15, 2009

    Jeff, Thanks for the post. I have a concern with the <?php previous_post_link(); ?> &bull; <?php next_post_link(); ?> way of things. It turns out that bullet point is there regardless if there is one page or many, if the links show or not. Any work around?

    • Jeff Starr

      Hi Travis, yes there are many ways to workaround this issue, with the easiest being simply not using the bullet. On many of my sites, I do something similar to the Default theme where the previous-post link is floated to the left and the next-post link to the right.

      To keep the bullet and prevent it from showing up on the first page, we can include the bullet only in the next-post link tag, like so:

      <?php previous_post_link('&laquo; %link','%title'); ?>
      <?php next_post_link('&bull; %link &raquo;','%title'); ?>

  12. Thanks for a great article. I think lots of people have hassles with WordPress pagination, so this is a great resource.

    I have a question about using images with previous_posts_link() and next_posts_link().

    Previously the only way I’ve got this to work is to include a div within the (). With a background image defined for it in the css. Like –

    <?php next_posts_link('') ?>

    <?php previous_posts_link('') ?>

    This obviously isn’t the best solution, but unlike in your example – I cannot include the image source as ('') in wordpress.

    You have to use
    ('<img src="/images/older.png" />').

    Which of course breaks my site when I include php in the ().

    Is there another solution in sourcing the image file other than using an absolute url?

    • Jeff Starr

      Hi Brendon, it is looking like WordPress ate some parts of your code.. Feel free to re-post, only remember to wrap your code in <code> elements.

  13. Great article. I am glad I found it.
    Quick Question:
    What happens when a post is found in 2 or more categories. Is it possible to show next and previous links specific to a category.
    Example:
    Post A is found in Category 1 and Category 2

    Output would read:
    Category 1
    Previous Post – Next Post
    Category 2
    Previous Post – Next Post

    • Jeff Starr

      I don’t think this is possible with default WordPress tags, but there is probably a plugin floating around out there that could get the job done.

  14. I’d like to replace my nav link text with an image. I followed the instructions but my image isn’t getting recognized. I get a question mark where my image is supposed to be.

    Here’s what I have:

    <div id="nav-below" class="navigation">
           <div class="nav-previous"><?php previous_post_link('%link', '<img src="images/pointleft.png" />', TRUE); ?> </div>
           <div class="nav-next"><?php next_post_link('%link', '<img src="images/pointright.png" />' , TRUE); ?></div>
    </div>

  15. edit:

    <div class="nav-previous"><?php previous_post_link('%link', '<img src="images/pointleft.png" />', TRUE); ?></div>
    <div class="nav-next"><?php next_post_link('%link', '<img src="images/pointright.png" />' , TRUE); ?></div>

    • Jeff Starr

      Not sure, the only thing that seems likely to cause an issue would be the file paths. Are you sure they are correct?

  16. How about the use of a custom field (lets say a thumbnail from the next/previous post) ?

    This breaks, but does anyone know how to write it properly?

    <?php next_posts_link('<img src="<?php echo get_post_meta($post->ID, "Thumbnail", true);?>" />'); ?>

    <?php previous_posts_link('<img src="<?php echo get_post_meta($post->ID, "Thumbnail", true);?>" />'); ?>

  17. I use the code here to show my latest post on a static Page used as my homepage. I can’t seem to get next/prev links working; is this because it’s a Page?

  18. so does anyone know how to achieve what I’m talking about 2 comments up?

    Thumbnail Previews of previous/next posts?

    • I have been searching for something similar but have not found anything. WordPress 2.9 is coming very soon and it will have thumbnails for individual posts. I hoping with the 2.9 code that this can be done very easily…. Use the post thumbnail in the sidebar or under the post for the next/ previous post.

      • Yeah, thats exactly what I’m looking for. Basically to really enhance my archives! (fingers crossed)

  19. I searched Google for “wordpress page navigation” and this page was rightly the first result.

    Somehow three navigation links were appearing on every page! I didn’t know what each was for, or how each got there, but with the help from your guide I deleted them all and copied an example. Thank you!

  20. squizeers June 13, 2012

    Is there any way to make the post navigation work only if the posts are in the same ANCESTOR category?
    For example:

    category-A
    cat1
    subcat1-1
    subcat2-1
    cat2
    subcat2-1
    subcat2-2

    The want the post navigation to work withing all the posts in “category-A”.

    Allows navigation only into the same parent category not ANCESTOR category.
    Please help.

Comments are closed. Contact us with any critical information. Thank you!

Code is poetry