DiggingIntoWordPress

by Chris Coyier & Jeff Starr

Optimizing WordPress Post Navigation

Posted by on

Implementing a solid set of navigational links for your WordPress site is one of the best ways to encourage visitors to stick around awhile and check out additional content. As discussed in our definitive guide to WordPress post navigation, there are essentially three different types of navigational tags for WordPress:

Without repeating ourselves, suffice it to say that previous_posts_link and next_posts_link are perfect for setting up separate links for index, category, and archive pages. Likewise, previous_post_link and next_post_link are perfect for setting up separate links for single-view post navigation.

Now that we’re on the same page, so to speak, let’s look at how these tags are typically used and how to improve and optimize their functionality..

Improving the next_posts_link and previous_posts_link (for archive views)

Here are the archive/category navigation links as provided in the default theme that is packaged with WordPress:

<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>

Functionally, this setup works great — the previous-post link is displayed only when there are previous posts, and likewise the next-post link is displayed only when there are newer posts. As convenient as this is, it doesn’t help us with the accompanying markup used to display the links. Any CSS styles applied to the <div>s in our example will be displayed even when the links themselves aren’t displayed. This can result in several issues, including:

  • Padding and margins may prevent proper display when links are missing
  • Background images used to enhance the navigational links will still be displayed
  • Additional text and/or characters will still be displayed even when links absent
  • Use of any markup other than <div>s may result in validation errors when left empty

And we’re not just talking about the front page and last page here — any category, tag, search, date, or author archive will also display botched navigational elements and design flaws when previous and next posts are unavailable. Your main index may always have previous posts, but what about that guest author archive, 2005 archive, and search results? Such pages are frequently one of a kind. Even worse, by defualt, your Home page will never have a page after it, which means a broken navigational element right there on the most important page of your site. Not good.

The easiest way that I have found to prevent this from happening when the “next” link is not generated is to simply test the $paged variable for a value greater than 1:

<?php if ($paged > 1) { ?>

	<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>

<?php } ?>

By checking if there are more posts to display before calling the navigational code, this technique will prevent empty elements from wrinkling your home page and archive pages. Another way of doing this is shared by Eric Martin. Just place this snippet into your active theme’s functions.php file:

// return TRUE if more than one page exists
function show_posts_nav() {
	global $wp_query;
	return ($wp_query->max_num_pages > 1);
}

And then use the function to conditionally display navigational code in your archive.php and other archive-view template files:

<?php if (show_posts_nav()) : ?>

	<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>

<?php endif; ?>

Not sure if there is any benefit to adding the extra code in the functions.php file, but I thought I would share that technique with you as another possible solution (hey you never know).

Also, a great way to improve the functionality and presentation of your blog is to provide some alternate navigational elements to help keep things flowing and balanced on the front pages of your site. For example, at Perishable Press, if the “next” link isn’t displayed, I provide a link to my site Archives:

<?php if ($paged > 1) { ?>

	<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>

<?php } else { ?>

	<div class="navigation">
		<div class="alignleft"><?php next_posts_link('&laquo; Older Entries') ?></div>
		<div class="alignright"><a href="http://perishablepress.com/press/archives/">Site Archives &raquo;</a></div>
	</div>

<?php } ?>

And of course, anything is possible here; the key is to keep things consistent, logical, and well-styled. Now let’s see how to improve navigational display for single-post views.

Improving the next_post_link and previous_post_link (for single views)

Fortunately, the situation is much improved for single-post navigation. By default, the next_post_link and previous_post_link provide parameters that enable us to avoid the “empty-element” syndrome. Let’s take a look at these parameters:

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

The format and link parameters enable us to do something like this:

<div class="navigation">

	<?php previous_post_link('<div class="alignleft">Previous entry: %link</div>', '%title'); ?>
	<?php next_post_link('<div class="alignright">Next entry: %link</div>', '%title'); ?>

</div>

Here we have replicated the markup in our previous examples, but have done so conditionally, such that the markup will only be displayed when the corresponding link is displayed, thereby enabling us to avoid empty elements when either the previous or next post-link is not displayed. As you can see, the single-post nav tags enable us to include the surrounding (X)HTML and text within the function itself. We can do similar tricks with the actual link title. Check out our definitive guide to post navigation for more information.

Conditional navigational display for single posts

Just as we did with the archive nav tags (next_posts_link and previous_posts_link), we can implement some conditional functionality to display alternate navigational links when viewing the first and last posts in any archive view. For example, if I also wanted to provide a link to my Site Archives when the “next” and/or “previous” links were not displayed, I could do so using the following code:

<div class="navigation">

	<?php previous_post_link('<div class="alignleft">Previous entry: %link</div>', '%title'); ?>
	<?php if(!get_adjacent_post(false, '', true)) { 
		echo '<div class="alignleft"><a href="http://perishablepress.com/press/archives/">Site Archives</a></div>'; 
	} ?>

	<?php next_post_link('<div class="alignright">Next entry: %link</div>', '%title'); ?>
	<?php if(!get_adjacent_post(false, '', false)) { 
		echo '<div class="alignright"><a href="http://perishablepress.com/press/archives/">Site Archives</a></div>'; 
	} ?>

</div>

Here we are using the get_adjacent_post function to determine whether or not there is a post before/after the current post. This enables us to conditionally display some sort of fallback navigation in the first- and last-post case. The get_adjacent_post tag accepts the following parameters:

  • $in_same_cat – specifies whether or not the adjacent post should be in the same category
  • $excluded_categories – a comma-delimited list of categories for which the adjacent post should not belong
  • $previous – specifies whether the previous post should be displayed

That does it for the single-post views. Let’s wrap things up with a way to consolidate and streamline the single and archive navigational methods..

Optimize your theme’s navigational code

Finally, here is a nice way to clean up your theme files and source code. The first step is to streamline production by getting more fine-grained with includes. This basically means that you can clean things up and save time/effort by moving your navigational code to its own file, named something like “navigation.php” or similar. You would then remove your nav code from your other template files and consolidate them all into that one location. You would then include navigation.php in any theme file where you want the navigation section to appear:

<?php include_once("navigation.php"); ?>

This technique makes maintaining and modifying your code a breeze. And, you can even streamline things further by using some conditional logic to display either archive or single navigation depending on the current page being viewed:

<?php if (is_single()) : ?>

	<div class="navigation">
		<?php previous_post_link('<div class="alignleft">Previous entry: %link</div>', '%title'); ?>
		<?php next_post_link('<div class="alignright">Next entry: %link</div>', '%title'); ?>
	</div>

<?php else : ?>

	<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>

<?php endif; ?>

This is a great way of staying organized and reducing your workload during theme development and maintenance.

Wrap up

The tips and tricks in this article will help you create a consistent, logical, and design-friendly set of navigational links for your next theme design. In the process, you can also streamline production by consolidating your code into a single file and using conditional logic to deliver the appropriate code.

10 Responses

  1. Great post Jeff. Always love to see the better way of doing things with what is apparently a simple thing!

  2. Nice article…

    I just happen to be half way through writing a plugin that displays fall back text for the previous_post_link() and next_post_link() functions. Making use of the {$adjacent}_post_rel_link filter.

  3. Jean-Baptiste Jung December 15, 2009

    Very cool read! I usually directly include a pagination in my theme, but your solution is excellent as well.

  4. Jeff Starr

    Thanks for the feedback guys — very much appreciated :)

  5. Thanks for the great post!

    With one layout I had this broblem where I needed to expand the scope of previous/next_post_link to a subcategories of a particular category. Not only to the one category.

    If you guys know a hack for it, let me know :)

    Cheers!

  6. Krasen Asenov December 16, 2009

    So, why you don’t have such navigation on this very site? I just discovered it and would like to read it like a book, post after post …

  7. Your tutorials are always fantastic, Jeff. Keep ‘em comin’!

  8. I only use plugin page navi

  9. Thanks for posting so much helpful info with this post and the previous post (Definitive guide to WordPress post navigation).

    I would like to learn more about the post thumbnail and how to incorporate the thumbs with previous next links.

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

Code is poetry