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 ;)
Thanks man..less plugins the better IMO!
Great ! I’ll try this. Thanks. You can use it on kriesi.at… Have a nice day.
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.
Thanks, didn’t know about that function :) Definitley woth a look!
Hi! I new! Very useful tutorial! Thank you! which file this function is inserted?
I would recommend to put it into your functions.php file. The file is located in your themefolder ;)
Еще раз большое спасибо за урок и за помощь! Все отлично работает!
Thank you again for the lesson and for your help! Everything works fine!
This is great! I’m all for reducing the number of plugins. I use this on my food blog at http://sparklette.net and modified it slightly to include a “Page X of Y” label in front, a link to my Archives etc.
If anyone’s looking, I have put up the modified code at http://design.sparklette.net/teaches/how-to-add-wordpress-pagination-without-a-plugin/
Really nice! Thanks for sharing this modification with us :)
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
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″ />
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″ />
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….
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
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?
Great tutorial . thanks for sharing
Very helpful tutorial. Thanks for sharing.
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.
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 :)
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!
A thousand thanks for your helpful tutorial. It work great!
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
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?
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.
Genau danach habe ich gesucht.. danke! Werde ich sofort ausprobieren….
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
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
Hi @kriesi,
Thanks so much for posting this. Great snippets :)
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
–
sorry –
<a href="" title="">
... <a href="">Read More
-
The most difficult thing is to find a blog with unique and fresh content but your blog is different. Bravo.