Advertisement

WordPress Pagination: A Primer

by
Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →

In this article/tutorial we'll look at the basics of WordPress pagination, the default pagination setup and how it can be enhanced.


The Default Pagination Scheme

I'll use the default WordPress Twenty Eleven theme as a reference. Even if you're not using it, you'll find it in your themes directory.

Posts Per Page

Don't forget that when it comes to pagination, WordPress needs to know how many items to list on each page. This value is set in the Admin -> Settings -> Reading settings page.

The "Blog pages show at most" value will be used by WordPress unless you override it, such as when using a custom query.

The Default Paging Code

A typical example of showing a listing of posts is when you view all posts in a category. The display of category posts is handled by the category.php template file. For the Twenty Eleven theme, the category page hands the display of the pagination off to a function called twentyeleven_content_nav, which is found in functions.php.

function twentyeleven_content_nav( $nav_id ) {

  global $wp_query;

  if ( $wp_query->max_num_pages > 1 ) : ?>

  <nav id="<?php echo $nav_id; ?>">
    <h3 class="assistive-text"><?php _e( 'Post navigation', 'twentyeleven' ); ?></h3>
    <div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">←</span> Older posts', 'twentyeleven' ) ); ?></div>
    <div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">→</span>', 'twentyeleven' ) ); ?></div>
  </nav><!-- #nav-above -->

  <?php endif;
}

The above code could just as well have been included directly in category.php but the designers of Twenty Eleven decided to make it a function so that it could be called from many template files. Most of the code is for layout and internationalization purposes, but here's what it does:

  • using the value of the global query variable $wp_query->max_num_pages, we check if we have more than one page; this avoids showing the whole paging block if there's only one page of posts
  • the WordPress function next_posts_link displays a link to the next page of posts and takes an optional argument for custom link text
  • similarly, the WordPress function previous_posts_link displays a link to the previous page of posts

And this is what it'll look like with a setting of two posts per page.

It's pretty basic but it is functional. The problems with this display are that there's no way to tell which page you're on, or how many pages there are in total.

One thing to remember about WordPress's default post listings is that they run in reverse order:

Because post queries are usually sorted in reverse chronological order, next_posts_link() usually points to older entries (toward the end of the set) and prev_posts_link() usually points to newer entries (toward the beginning of the set).

That behavior can be altered if you are creating a custom query. Note in the above example, two paging blocks were used: one before the post loop began and one after. It's always a nice touch to have pagination at both top and bottom so the user doesn't have to scroll too much.

Examples:

To display "Go to next page..." as you link text:

next_posts_link('Go to next page...');

To display an image instead of text:

$previous_posts_image = '<img src="' . get_bloginfo('stylesheet_directory') . '/images/previous_posts.png" />';
previous_posts_link($previous_posts_image);

Alternative

There is an alternative to using the separate functions next_posts_link and previous_posts_link, and that is the posts_nav_link function. Basically, this function outputs both the previous and next links in one fell swoop, with optional link text and link separator arguments.

The default output:

posts_nav_link();

And with custom link text and a separator:

posts_nav_link(':::', '<< Newer Posts', 'Older Posts >>');

I suggest using the separate functions next_posts_link and previous_posts_link as these give you more control over the placement of your links as well as making your code more understandable.


Paging Single Posts

When displaying single posts, it's nice to display a link to the previous and next posts in the sequence. The template file single.php handles that with the following code:

<nav id="nav-single">
  <h3 class="assistive-text"><?php _e( 'Post navigation', 'twentyeleven' ); ?></h3>
  <span class="nav-previous"><?php previous_post_link( '%link', __( '<span class="meta-nav">←</span> Previous', 'twentyeleven' ) ); ?></span>
  <span class="nav-next"><?php next_post_link( '%link', __( 'Next <span class="meta-nav">→</span>', 'twentyeleven' ) ); ?></span>
</nav><!-- #nav-single -->

That will give you this:

It is the functions next_post_link and previous_post_link that produce the paging links at top right. These functions accept a couple of parameters that allow us to customise their output quite nicely. The parameters are:

next_post_link( format, link, in_same_cat, excluded_categories );

The format and link parameters work together. Format is how you want the link to appear: %link in the format is used as a placeholder for the content of the link parameter, which is the actual text we wish to use for the link. So this:

previous_post_link( '%link', '<< Next Newest Post' );
next_post_link( '%link', 'Next Oldest Post >>' );

Would give us this:

If we wanted to display the actual title of the next or previous post, we would use the special value %title in the link parameter. So this:

previous_post_link( '%link', '<< Previous Post: %title' );
next_post_link( '%link', 'Next Post: %title >>' );

Would give us this:

The remaining parameters allow you to ensure that the next post linked to is in the same category and to exclude certain categories. Consult the documentation as linked above.

You could display an image for the the link like:

$previous_post_link_image = '<img src="' . get_bloginfo('stylesheet_directory') . '/images/previous_post_link.png" />';
previous_post_link( '%link', $previous_post_link_image );

A Better Solution

As easy as the above methods are, they are also limited. Fortunately, WordPress gives us the paginate_links function. This allows us to create a true set of pagination links, such as this:

Below is the code that outputs the above pagination. Let's take a look at what it does.

global $wp_query;

$total_pages = $wp_query->max_num_pages;

if ($total_pages > 1){

  $current_page = max(1, get_query_var('paged'));
  
  echo paginate_links(array(
      'base' => get_pagenum_link(1) . '%_%',
      'format' => '/page/%#%',
      'current' => $current_page,
      'total' => $total_pages,
    ));
}
  • globalize the wp_query object so we can retrieve the max_num_pages value: this is the total number of pages returned by the query
  • find the current page by retrieving the 'paged' variable with get_query_var: we use the max function to cause the current page to default to 1
  • the paginate_links function takes an array of parameters: the four most important are shown
  • retrieve the base URL for the page with the get_pagenum_link function and append the %_% pattern to it which will be replaced by the format parameter, next
  • in our case, specify a format pattern that conforms to the way that pretty permalinks (set with %postname% in Admin -> Settings -> Permalinks) appear: the %_% in the base parameter will be replaced by this
  • set the current and total pages as retrieved previously

The URL of paged results using pretty permalinks will look something like this:

http://2011.rosselliot.co.nz/category/honda/page/2/

The get_pagenum_link(1) call will retrieve this part of the URL:

http://2011.rosselliot.co.nz/category/honda/

We then provide a format parameter for the remainder of the URL which is:

page/2

The %#% part of the format holds our current page number

Based on this set of parameters, paginate_links will output a set of paging links. You could insert the code directly into a template file that handles paging (such as category.php) or save it as a function in your functions.php and then call it from any template you like.

paginate_links has other parameters that allow you to tailor the output, how the numbers appear and what the labels say. Consult the documentation. With a bit of styling it's easy to come up with an impressive pagination display. With this amended code and added styling:

global $wp_query;

$total_pages = $wp_query->max_num_pages;

if ($total_pages > 1){

  $current_page = max(1, get_query_var('paged'));
  
  echo '<div class="page_nav">';
  
  echo paginate_links(array(
      'base' => get_pagenum_link(1) . '%_%',
      'format' => '/page/%#%',
      'current' => $current_page,
      'total' => $total_pages,
      'prev_text' => 'Prev',
      'next_text' => 'Next'
    ));

  echo '</div>';
  
}
.page_nav .page-numbers{
  padding:4px 8px;
  margin:0px 4px;
  border:1px solid gray;
  color:#FFB134;  
}
.page_nav .current{
  border:1px solid #FFB134;
  background-color:#FBEFDB;
}
.page_nav .prev, .page_nav .next{
  border:none;
  color:blue;
}

It was easy to produce this:

I hope you've enjoyed this primer on pagination. Do you have any further tips on pagination with WordPress? Let us know in the comments below.

Advertisement