WordPress Pagination: A Primer

WordPress Pagination: A Primer

Tutorial Details
  • Program: WordPress
  • Version: 3.3+
  • Difficulty: Beginner - Intermediate
  • Estimated Completion Time: 30mins

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.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.quentin-ravinet.fr Quentin

    Hi, nice tut.
    A good alternative to pagenavi plugin even if it’s a bit less complete.

  • Jiri Benes

    Thx! Great and usefull tut!

  • Pingback: WordPress Pagination: A Primer | Shadowtek | Hosting and Design Solutions

  • http://www.lickmydesign.co.uk Adam

    Very handy guide, I’ve replaced my WP-PageNavi plugin with this code.

    • http://thomasgbennett.com Thomas Bennett

      Always better to do it the right way if you can. Never know when a plugin is going to cause you trouble. Good decision.

  • http://dedos.info Rafael Trabasso

    Really useful, not only “special effects” as most tutorials.
    This is about usability and making stuff work.

  • http://lazaac.com lazaac

    Thanks for very well explained up there , I still will using page-navi with custom style, it’s look awesome..

  • Pingback: Rapid Crush Inc. Says Selling a Simple Wordpress Plugin Can Give People Good … | Open Knowledge

  • Jeffrey

    Really helpful info, i will use it in my future project. Thanks!

  • http://thomasgbennett.com Thomas Bennett

    Very clean example. Thank you. I will probably revisit my code for this.

  • http://wpthemepower.com Zeeshan

    I’ve always wanted to customize it. Thanks to this tutorial I have finally replaced the default pagination with numbered pagination.

  • Connor Crosby

    For the “better solution” paginate, there is a small error with your code. When you have the format set to /page/%#% with a backslash at the beginning, it results in a double backslash. So, simply use page/%#%.

    Anyways, great tutorial!

  • http://www.customicondesign.com/ custom icon design

    good article and I will no need to use the plugin to the pagination for wordpress. many thanks.

  • http://www.whatsthebigidea.com David Radovanovic

    Thanks for the tip… wouldn’t it be even better if the title (or custom field) is displayed instead of numbers? Better SEO and user navigation? Thanks again!

  • http://www.whatsthebigidea.com David Radovanovic

    Although I haven’t used any of these best practices, here is a good pagination article: http://www.seomoz.org/blog/pagination-best-practices-for-seo-user-experience

  • http://intronex.pl/ Projektory multimedialne

    A little to late with the article. I was having some hard time with pagination. That post would be really helpful.

  • Jakub Kohout

    Hi,
    Is there any good man who helps me with pagination via skype. I am struggling with this couple days but I can’t figure it out. If you want so pls send me your skype on email jakub.kohout11@gmail.com
    thx

    • Jakub Kohout

      Who would help :D

  • http://twitter.com/MichealKennedy Mike Kennedy

    How can I remove the Prev link (‘prev_text’ => ‘Prev’,)?

  • http://none Hirantha

    Thank you. very much. It was clear and easy. thank you again. and keep up the good work..

  • http://beatsforthemind.com Eric

    What will happen when there is a large number of posts and the number of pages reaches over a few hundred? Is the a way to truncate the number of pages that are displayed so that the page nav appears as <> ?

  • http://beatsforthemind.com Eric

    The end of my comment got lost with the carrots. I meant to ask how to get the page links to appear as:
    Prev 1 2 3 ….. 201 202 203 Next

  • http://www.tmfwebdesign.com Tim

    Thanks Ross! I was spending longer then I should getting pagination to work on a project.

  • Tony

    Hello,

    The code works well in category/archive page, but in search, the code above results to 404 :(

    Please help me.

  • Pingback: Tutorial – Week 6 – Breaking Out of the Blog | Musings of a 21st Century Renaissance Man

  • Greg

    Hi,

    First of all, excellent primer, just what I was looking for!

    Is there any way to customise the output of the following code (under ‘A Better Solution’) ? I would like to return an unordered list of numbers, instead of a div for each number:

    global $wp_query;
    $total_pages = $wp_query->max_num_pages;
    if ($total_pages > 1){
    $current_page = max(1, get_query_var(‘paged’));
    echo ”;
    echo paginate_links(array(
    ‘base’ => get_pagenum_link(1) . ‘%_%’,
    ‘format’ => ‘/page/%#%’,
    ‘current’ => $current_page,
    ‘total’ => $total_pages,
    ‘prev_text’ => ‘Prev’,
    ‘next_text’ => ‘Next’
    ));
    echo ”;
    }

    Any help would be much appreciated.

    • http://www.sutanaryan.com/ Ryan S

      Hi, you need to add type => ‘list’ paramter

  • Loso

    Hmm i can’t figure this out. For some reason when using this or any pagination links with the numbers, i get nothing on the other pages. example, i click on page 2 and nothing is there. but the first three posts, as set, are on page one.

    any ideas on whats going on? thanks in advance

  • Radu

    Nice tutorial, thanks ;)

  • peter

    Hi, nice tutorial, but am I the only one who receives “Error 404 Page not Found” when using the above code in the “A Better Solution” part?

    • Xiao kougi

      use this one for your search.php

      str_replace( $big, ‘%#%’, get_pagenum_link( $big ) ),
      ‘format’ => ‘?paged=%#%’,
      ‘current’ => max( 1, get_query_var(‘paged’) ),
      ‘total’ => $wp_query->max_num_pages
      ) );
      ?>

      hope that help you

    • Rajeev Kumar

      hi I am facing same problem when I am click on any number then it giving me page not found any help ll be appreciate

  • http://twitter.com/Pecadosblog Pecado’s Blog

    I used the better solution which is apart boxes. So everyting is nice but when I cilck the numbers I can’t get the other pages. Example; second page link is …/page/2 and comes with current page. How do I get the other pages with older posts?

    Thanks in advance.

  • Mohit

    thnx very nice :)

  • Pawan Sharma

    Thanks