Advertisement
Theme Development

WordPress Pagination: A Primer

by

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.

Related Posts
  • Code
    Creative Coding
    Advanced Use of Attachments in WordPress: Creating Custom Queries for AttachmentsAdvanced use of attachments in wordpress 400
    This tutorial is the second in a four part series in which you'll learn some techniques for working with images in attachments in WordPress which give you advanced options.Read More…
  • Code
    Theme Development
    Custom Controls in the Theme CustomizerTheme customizer custom control 400
    In the last article, we explored the advanced controls available in the Theme Customizer, and how to implement them. We’re going to look at how to create our own custom control, allowing you to choose which Category of Posts are displayed on the home page. To get started, download version 0.6.0 of our Theme Customizer Example.Read More…
  • Code
    Theme Development
    Creating a WordPress Theme from Static HTML: Creating an Archive TemplateCreating wordpress theme from html 400
    If you've been working your way through this series, you now have a functioning theme with two page templates. The steps I've demonstrated to this point are: preparing your markup for WordPress converting your HTML to PHP and splitting your file into template files editing the stylesheet and uploading your theme to WordPress adding a loop to your index file adding meta tags, the wp_head hook and the site title and description to your header file adding a navigation menu adding widget areas to the header and sidebar adding widget areas, a colophon and the wp_footer hook to the footer file creating template files for static pages. Read More…
  • Code
    Creative Coding
    Using WordPress for Web Application Development: WP_User_QueryApplication foundation 400
    In this series, we've been taking a look at how WordPress can be used to development web applications much like a number of different frameworks and other tools that are available. Starting in the last article, we began looking at the different options that we have as it relates to querying the WordPress data. First, we reviewed WP_Query.Read More…
  • Code
    Creative Coding
    Using WordPress for Web Application Development: Features: Custom Queries with WP_QueryApplication foundation 400
    We've been looking at how WordPress can be used as a foundation for application development, but one of the things that we've yet to cover that most modern frameworks offer is how to query the database to retrieve results for any given view. Specifically, we haven't talked about how to get information out of the database and insert it into our pages.Read More…
  • Code
    Theme Development
    Creating a WordPress Theme From Static HTML: Creating Template FilesCreating wordpress theme from html 400
    In the first part of this series, I showed you how to prepare your HTML and CSS files for WordPress, ensuring the structure would work, the code was valid and that the correct classes were being used. In this tutorial you'll learn how to take your index.html file and split it up into a set of template files for use by WordPress.Read More…