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="https://kriesi.at/blog/page/2">2</a>
 <a href="https://kriesi.at/blog/page/3">3</a>
 <a href="https://kriesi.at/blog/page/2">›</a>
 <a href="https://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
« Older Comments
  1. 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! :)

  2. 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!

  3. Kevin Leary
    Kevin Leary says:

    This function is great thanks for sharing it!

    I’ve replaced WP-PageNavi in a site I’m currently working on, and plan to add this to my personal base starter theme.

  4. Cory Logan
    Cory Logan says:

    Works like a charm. I’m currently using it on my site. Thanks so much for sharing. Put your function in my functions.php, and called it at the end of my index. Made a couple of subtle modifications, but again, super easy install. Thanks so much! My content is no longer disappearing as I add more :)

  5. Mark
    Mark says:

    Hi, I have one problem, and can’t figure it out. It everything seems ok, but pagination links doesn’t work, I click to page 2 link and it goes to mysite.com/page/2 but it still shows first page.

    It’s home.php, custom home template, it’s set to show posts from one category. Permalinks are set “/%category%/%postname%/”, also tried only with “/%postname%/”

    This is the code:

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

    <a href="” rel=”bookmark”>

    <?php the_content('Read more’); ?>

    max_num_pages); ?>

    Thanks in advance for help.

    • Mark
      Mark says:

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

      <a href="" rel="bookmark">

      <?php the_content('Read more'); ?>

      max_num_pages); ?>

      I didn’t put code tags..

  6. Jon
    Jon says:

    I’d like to include this into a theme template for sale. What is the license for this? Can you post it for download?

Trackbacks & Pingbacks

  1. Ardèche says:

    […] Kriesi pagination code […]

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

  3. […] Kriesi pagination script and walker menu […]

  4. […] 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 […]

  5. […] 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 […]

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

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

« Older Comments

Comments are closed.