wordpress_pagination

How to build a WordPress Post Pagination without plugin

WordPress only comes bundled with the “next page” and “previous page” links to navigate between different blog overview pages. If you happen to have a blog with a lot of posts or simply want to offer a better user experience I would recommend to remove those links and replace them with a pagination like most people (including me) are using in their templates.

Habitat for example (my latest blog theme) uses it. Just scroll down the front page and you will see those little paginated buttons.

Why should you use them?
Because they are easier to navigate and the user instantly knows how many posts and pages are available. Its simply good user experience :)

Using a plugin for this task may be an overkill since you really only need to add a few lines of php and css to your theme which I will show you now:

The function

If you just want to copy/paste the function into your theme feel free to do so, a more detailed description can be found bellow:

function kriesi_pagination($pages = '', $range = 2)
{  
     $showitems = ($range * 2)+1;  

     global $paged;
     if(empty($paged)) $paged = 1;

     if($pages == '')
     {
         global $wp_query;
         $pages = $wp_query->max_num_pages;
         if(!$pages)
         {
             $pages = 1;
         }
     }   

     if(1 != $pages)
     {
         echo "<div class='pagination'>";
         if($paged > 2 && $paged > $range+1 && $showitems < $pages) echo "<a href='".get_pagenum_link(1)."'>&laquo;</a>";
         if($paged > 1 && $showitems < $pages) echo "<a href='".get_pagenum_link($paged - 1)."'>&lsaquo;</a>";

         for ($i=1; $i <= $pages; $i++)
         {
             if (1 != $pages &&( !($i >= $paged+$range+1 || $i <= $paged-$range-1) || $pages <= $showitems ))
             {
                 echo ($paged == $i)? "<span class='current'>".$i."</span>":"<a href='".get_pagenum_link($i)."' class='inactive' >".$i."</a>";
             }
         }

         if ($paged < $pages && $showitems < $pages) echo "<a href='".get_pagenum_link($paged + 1)."'>&rsaquo;</a>";  
         if ($paged < $pages-1 &&  $paged+$range-1 < $pages && $showitems < $pages) echo "<a href='".get_pagenum_link($pages)."'>&raquo;</a>";
         echo "</div>\n";
     }
}

How to use  & Step by Step description

Displaying the pagination links on a default index page is rather easy. Call

kriesi_pagination();

and you are done.

As you can see we got 2 optional parameters to pass:

function kriesi_pagination($pages = '', $range = 2)

The first one is the number of pages: passing this is only necessary if you are using a custom loop, something I will explain a little bit later.

The second parameter sets the number of links to display. Range tells the script how many links before and after the current page should be displayed before it only shows the small arrows. For example with the default range of 2, if you are currently visiting the first page the script would display the 2 following pages, the next page button and the last page button:

if we would visit page number 4 the script would show page 4 as the current page, would directly link to page 2 and 3 as well to 5 and 6. All other would be hidden:

For easier arithmetic operations afterwards we also store the max number of items to display in a separate variable:

$showitems = ($range * 2)+1;

Next we need access to the global variable $paged. WordPress uses this variable to store which page we are currently viewing. If that variable is empty we set it to 1. Why do we need to know it? The page we are currently at should not be linked, it should be displayed as “active”.

global $paged;
if(empty($paged)) $paged = 1;

Now we know which page we are currently viewing, but we also need to know how many pages we got. We are still asuming that we are not using a custom loop and that the $pages variable (dont mix up with $paged) was not set when we called the script. If thats the case we can once again  make use of a global variable to get that number:

if($pages == '')
{
    global $wp_query;
    $pages = $wp_query->max_num_pages;
    if(!$pages)
    {
        $pages = 1;
    }
}

Now for the “Brainfuck” ;D

As you can see,  appart from a little bit of  logic and arithmetic we only need a single wordpress specific function. Its called get_pagenum_link() and allows us to fetch the url of a wordpress page by passing the number of the page: get_pagenum_link(2) would get the link to blog overview page 2 in my afforementioned Habitat theme.

What is done now is a check based on quite a few if statements that asks which items to display, based on the variables we retrieved and set before. I usually do explain everything in detail but I think it wouldn’t make much sence in this case. if you are really interested in deciphering all of the if statements feel free to do so, you now know which value is stored within each variable so it shouldn’t take all too long :)

The CSS

The CSS Part of our pagination is rather simple. By default we would get an HTML output similar to this:

<div class='pagination'>
 <span class='current'>1</span>
 <a href="http://www.kriesi.at/blog/page/2">2</a>
 <a href="http://www.kriesi.at/blog/page/3">3</a>
 <a href="http://www.kriesi.at/blog/page/2">›</a>
 <a href="http://www.kriesi.at/blog/page/12">»</a>
</div>

We only need a few css rules to style this

.pagination {
clear:both;
padding:20px 0;
position:relative;
font-size:11px;
line-height:13px;
}

.pagination span, .pagination a {
display:block;
float:left;
margin: 2px 2px 2px 0;
padding:6px 9px 5px 9px;
text-decoration:none;
width:auto;
color:#fff;
background: #555;
}

.pagination a:hover{
color:#fff;
background: #3279BB;
}

.pagination .current{
padding:6px 9px 5px 9px;
background: #3279BB;
color:#fff;
}

Advanced: Custom Loops

You might probably want to use a so called custom loop anywhere on a page, a loop that is not stored in the default global $wp_query object we used to retrieve the number:

 $pages = $wp_query->max_num_pages;

If thats the case you need to call the kriesi_pagination() function with the first parameter set.

So lets assume you are using a simple custom loop on your site:

<?php $additional_loop = new WP_Query("cat=1,2,3&paged=$paged"); ?>

<?php while ($additional_loop->have_posts()) : $additional_loop->the_post(); ?>
 <!-- Show loop content... -->
<?php endwhile; ?>

You could then call the pagination function that way:

kriesi_pagination($additional_loop->max_num_pages);

Feel free to use this function within any personal or commercial template, any attribution is appreciated but of course not required ;)

63 replies
Newer Comments »
  1. Warren
    Warren says:

    http://codex.wordpress.org/Function_Reference/paginate_links

    That function is what’s leveraged on the admin side for pagination. I wish WordPress would update their theme tutorials to incorporate it. Ironically, most of the plugins I’ve seen don’t leverage this either.

    The default pagination format is a little different: ; however, it is configurable via arguments, but you can’t make it exactly like yours.

    • RomVadik
      RomVadik says:

      Еще раз большое спасибо за урок и за помощь! Все отлично работает!
      Thank you again for the lesson and for your help! Everything works fine!

  2. Philip
    Philip says:

    hi Kriesi,

    thanks a lot for sharing your knowledge with us,

    i try to run your function with posts and custom post types,
    i run this query:
    query_posts(‘post_type=projects&showposts=2&offset=0&orderby=asc&paged=$paged’);

    and i call the pagination function:
    kriesi_pagination($additional_loop->max_num_pages);

    for some reason it working fine in categories, posts but no in taxonomies and custom post types,

    how i can make it work with custom post types?is that possible?

    thanks a lot!!!
    Philip

    • Craig
      Craig says:

      Hi Kriesi

      I also get this when using your function, it works perfect on my blog post but when I use it on a custom post type it shows the links but when I click on 2nd page it just reloads the same posts, I have tried everything but too no avail.. Would appreciate a point in the right direction

      Thanks again and will be following you on twitter.

      Craig

      single-gallery.php

      ‘gallery’, ‘post_parent’ => get_the_ID(), ‘posts_per_page’ => 9, ‘orderby’ => ‘menu_order’, ‘paged’ => $paged));
      ?>


      have_posts()) : while($additional_loop->have_posts()) : $additional_loop->the_post(); ?>

      =3)$count=0;
      $thumb = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID), ‘Gallerythumb’ );
      ?>

      <li class="”>
      <a class="thickbox" href="”>

      max_num_pages); ?>

      No Images for Album
      <img src="/images/404.png” alt=”404 Album Not Found” width=”540″ height=”400″ />

    • Craig
      Craig says:

      Sorry, Something went wrong when I pasted the code in
      ‘gallery’, ‘post_parent’ => get_the_ID(), ‘posts_per_page’ => 9, ‘orderby’ => ‘menu_order’, ‘paged’ => $paged));
      ?>


      have_posts()) : while($additional_loop->have_posts()) : $additional_loop->the_post(); ?>

      =3)$count=0;
      $thumb = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID), ‘Gallerythumb’ );
      ?>

      <li class="”>
      <a class="thickbox" href="”>

      max_num_pages); ?>

      No Images for Album
      <img src="/images/404.png” alt=”404 Album Not Found” width=”540″ height=”400″ />

    • Craig
      Craig says:

      Hi, after struggling with this for days now and trying all the support forum’s suggestion, I eventually got this to work when I set the permalinks back to default from /%category%/%postname%/ then the second page will load from the pagination

      Any clue as to why???

      Great work again and will be following….

  3. Nola
    Nola says:

    I was wondering if this could be used with comments? And if so how could this be modified ? I really love this solution and would rather not use a plugin in to achieve pagination with comments.

    Any help would be much appreciated

  4. education theme
    education theme says:

    Thanks for the information..
    Has this become obsolete by any chance? I tried the multiple pagination option, but it did not seem to work, or error, did I get it wrong obviously? It did cut the page, but nowhere were any page numbers to be seen, let alone click to get to the next page. It just said “This is page 1″ period. Any idea anyone?
    Above function is suitable for this problem or not?

  5. Aradar
    Aradar says:

    Good day, Christian.

    I really liked the idea of withdrawal of pagination not using plug-in, a “few lines of PHP”, but it does not generate output pagination (empty, without errors). Tell me please, why is not the function is executed the page output? Thank you.

  6. Morton Tifft
    Morton Tifft says:

    Hi this was a great post. What gave you the inspiration to write it? I was looking for a way to subscribe but couldn’t see one? Thanks for the post, hope to hear back from you. thanks :)

  7. Tom Conte
    Tom Conte says:

    This solution is exactly what I needed!

    Using the default pagination system, I had to overwrite the wp_query variable that changed my “Page” to a “Category Page”. For SEO purposes, I don’t want my category pages indexed, but because of this default method, I had no choice but to leave it as is.

    This plugin saved the day because I was able to keep my page a “Page” and not have my category pages indexed.

    Thanks!

  8. Erik
    Erik says:

    Thank you very very much, it solved my problems.
    However the range is not working for me! I added the exact function code to functions.php it contains: function kriesi_pagination($pages = ”, $range = 2)

    then I called the function
    kriesi_pagination();
    in home page after my custom loop. I think it is a part of global $wp_query. it is as following:

    function custom_query_posts(array $query = array())
    { global $wp_query;
    wp_reset_query();
    $paged = get_query_var(‘paged’) ? get_query_var(‘paged’) : 1;
    $defaults = array( ‘paged’ => $paged, ‘posts_per_page’ => ER_PAGE_DEFAULT,’cat’ => 8); $query += $defaults;
    $wp_query = new WP_Query($query);
    }

    I called the function with 2 methods, both:
    kriesi_pagination();
    kriesi_pagination($custom_query_posts->max_num_pages);
    but neither one could get the range. May you please kindly tell me how can get the range working?
    Thank you

  9. Matthew Ruddy
    Matthew Ruddy says:

    Hi. I’ve managed to get this pagination working numerically, however it isn’t displaying any arrow next/previous links after the numbers for some strange reason. I’m using the pagination with both query_posts and a custom loop using new WP_Query. I’ve added paged=$paged to the loops also.

    The next/previous links just don’t seem to want to show no matter what I do:

    Before the loop:

    After the loop:

    No dice. Any ideas? Doing anything wrong?

  10. Carol Bellavance
    Carol Bellavance says:

    Hello, im from Dream Treasure Rewards crew. We provide Top Rewards for Filling Out Internet Surveys As well being around for on top of 14 years and having amazing customer support to take care of our members, we are also well understood through internet society for providing brilliant rewards. Not like many reward websites that provide you the world and after that fail miserably, our site is known to provide some of the best rewards existing. Here are just some of the several awesome rewards it is possible to earn when you finish our on-line surveys: iPads, iPhones, Discount cupons, mp3 players and more cool stuff.

  11. Kirby
    Kirby says:

    I use arras theme. I want to know where in the theme to paste this code. I want to get rid of my pagenavi plugin. Please help me.
    Thank you

  12. tctc
    tctc says:

    I ‘ve got this problem:

    function is working fine but if I have a lists of posts belonging to DIFFERENT category (thus a page showing posts coming from different categories), pagination is NOT working!

    Any idea in this problem and how to solve it? (probably in wp_query..)

    thanks

  13. clayton miller
    clayton miller says:

    im working with a custom loop i have. the pagination is showing but doesnt link to the next page of older posts. it just reloads the same page even though is says page 2 in the url when you roll over the 2nd page link. any help would be greatly appreciated! thanks in advance! here is my code:

    <a href="” title=””>
    … <a href="”>Read More


  14. Tom
    Tom says:

    Excellent Post!!!
    I spent the last 3 hours trying to make other tutorials work and this worked in seconds!

    Thanks a lot! :)

  15. Tom
    Tom says:

    Hey I think there’s a little error in there.

    $showitems = ($range * 2)+1;
    should be
    $showitems = $range +1;

    I might be wrong, but this is what worked for me.

    Very nice post tho!

    Thanks a lot!

Trackbacks & Pingbacks

  1. Ardèche says:

    [...] Kriesi pagination code [...]

  2. [...] [http://www.kriesi.at/archives/how-to-build-a-wordpress-post-pagination-without-plugin ] [...]

  3. [...] the famous PageNavi plugin, however, I much prefer adding pagination manually (original code by Kriesi) to my themes so people don’t have to go searching for a plugin. It also helps keep the site [...]

  4. [...] tweak and implement. WordPress & jQuery Contact Form without a Plugin →View the Demo →WordPress Post Pagination without a Plugin Using a plugin for post pagination may be a little bit of overkill since you really only need to [...]

  5. [...] Si quieres más info puedes visitar la página del autor del código aquí. [...]

  6. [...] method only using litle bit functions and we can use it easely. Original Source code by Kriesi. Thanks for creating wonderful [...]

  7. [...] Setelah browsing akhirnya saya temukan sumbernya disini dan juga disini. [...]

  8. [...] ich aber nicht die ganzen Einstellungsmöglichkeiten des Plugins brauche und es auch eine saubere pluginfreie Lösung gibt, ist das Ding rausgeflogen. Mittlerweile habe ich sogar entdeckt, dass WordPress Pagination [...]

  9. [...] не большой любитель использовать плагины WP и поэтому статья от  Christian “Kriesi” Budschedl  попалась мне на глаза [...]

  10. [...] code is provided by Kriesi and you can get his code and instructions. The pagination looks like this: [...]

Comments are closed.