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)."'>«</a>"; if($paged > 1 && $showitems < $pages) echo "<a href='".get_pagenum_link($paged - 1)."'>‹</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)."'>›</a>"; if ($paged < $pages-1 && $paged+$range-1 < $pages && $showitems < $pages) echo "<a href='".get_pagenum_link($pages)."'>»</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 ;)
cool, is awesome. a few lines of code but a great job.
Congratulation and thanks
Excellent Post!!!
I spent the last 3 hours trying to make other tutorials work and this worked in seconds!
Thanks a lot! :)
Do you cut and paste this into functions.php? Just guessing. Thanks for any replies
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!
Hi there,
Kriesi I need a bit of help with your function. How can I remove /page/ from ../page/2 ?
Regards,
Ciprian
Super Funktion! Genau soetwas benutzerfreundliches habe ich gerade gebraucht.
Danke
Servas Kriesi,
schau einmal da: https://gist.github.com/818457
Semantisch korrekt mit Erster/Letzter, Nächster/Voriger Link und Reichweite Attribut.
Dere!
K.
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.
Hi there,
Which PHP file needs the pagination code posting into please?
Thanks,
Kristin
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 :)
This is great code it really help me i am very thankx full to you.
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.
have_posts()) : $additional_loop->the_post(); ?>
<a href="" rel="bookmark">
<?php the_content('Read more'); ?>
max_num_pages); ?>
I didn’t put code tags..
I’d like to include this into a theme template for sale. What is the license for this? Can you post it for download?
Sorry, I just noticed the note for this at the bottom of the write up.