One of the most annoying things about most Wordpress themes, even an advanced one like Thesis, is the navigation system for blog, archive, and search pages. Typically, all you get at the bottom of a blog’s homepage is two links. One is for “newer posts” and one is for “older posts” or something similar. This is not exactly optimal. Fortunately, its possible to replace this native functionality with numbered page navigation.
http://www.vimeo.com/8918165What is Numbered Page Navigation?
Numbered page navigation is simply a list of links to a range of pages within a few pages of the page you are currently viewing. This list appears at the bottom of any area of your blog with multiple posts numbering greater than the amount of posts your blog is set to display on one page (this can be changed under the “Reading” options under the “Settings” tab in your WP admin). Your visitors will then be able to choose to visit any number of pages from one page rather than scrolling through them one at a time to find the desired page.

How Can I Setup Numbered Page Navigation On My Blog?
There are two ways you can do this. If you want to be boring, you can use a plugin called WP Pagenavi. Its actually a really nice plugin and I would recommend it if you don’t want to get your hands dirty.
However, as your blog grows, you’ll find yourself wanting to change things, add new features, etc. As this happens, you’ll find yourself using more and more plugins. The more plugins you use, the slower your blog will be. I don’t know about you, but I’m all about keeping my blog clean and fast, so I make every attempt to avoid plugins when I can.
The code we’ll be using to create our numbered page nav is actually based on the same code that WP Pagenavi utilizes. However, I’ve tailored it to a blogger’s needs and cleaned it up a bit to make this as painless as possible for the coding impaired. I know it looks like a lot to swallow, but don’t worry. I’ll walk you through it.
In order to work properly, we need to write a typical wordpress function. Then, we’ll call that function using a Thesis hook to place it directly below the last post on each page where page navigation is displayed. Finally, we’ll add CSS customizations to make it look good. It will take a bit of coding knowledge to understand what’s going on here, but if you can copy and paste, you can implement this!
The Code
/* NUMBERED NAV MENU */
function numbered_page_nav($prelabel = '', $nxtlabel = '', $pages_to_show = 8, $always_show = false) {
global $request, $posts_per_page, $wpdb, $paged;
$custom_range = round($pages_to_show/2);
if (!is_single()) {
if(!is_category()) {
preg_match('#FROM\s(.*)\sORDER BY#siU', $request, $matches);
}
else {
preg_match('#FROM\s(.*)\sGROUP BY#siU', $request, $matches);
}
$blog_post_count = $matches[1];
$numposts = $wpdb->get_var("SELECT COUNT(DISTINCT ID) FROM $blog_post_count");
$max_page = ceil($numposts /$posts_per_page);
if(empty($paged)) {
$paged = 1;
}
if($max_page > 1 || $always_show) {
echo "<div class='page-nav'><div class='page-nav-intro'>Page $paged of $max_page</div>";
if ($paged >= ($pages_to_show-2)) {
echo '<div class="page-number"><a href="'.get_pagenum_link().'">1</a></div><div class="elipses">...</div> ';
}
for($i = $paged - $custom_range; $i <= $paged + $custom_range; $i++) {
if ($i >= 1 && $i <= $max_page) {
if($i == $paged) {
echo "<div class='current-page-number'>$i</div>";
}
else {
echo ' <div class="page-number"><a href="'.get_pagenum_link($i).'">'.$i.'</a></div> ';
}
}
}
if (($paged+$custom_range) < ($max_page)) {
echo ' <div class="elipses">...</div><div class="page-number"><a href="'.get_pagenum_link($max_page).'">'.$max_page.'</a></div>';
}
echo "</div>";
}
}
}
remove_action('thesis_hook_after_content', 'thesis_post_navigation');
add_action('thesis_hook_after_content', 'numbered_page_nav');
The Breakdown
Worried? Don’t be. Its bark is worse than its bite. Let’s break it down piece by piece.
1. Setting the Parameters
function numbered_page_nav($prelabel = '', $nxtlabel = '', $pages_to_show = 8, $always_show = false) {
global $request, $posts_per_page, $wpdb, $paged;
$custom_range = round($pages_to_show/2);
if (!is_single()) {
if(!is_category()) {
preg_match('#FROM\s(.*)\sORDER BY#siU', $request, $matches);
}
else {
preg_match('#FROM\s(.*)\sGROUP BY#siU', $request, $matches);
}
This section of code establishes the parameters of our function such as what Wordpress elements we need, how many posts will be in our list, and which areas of your blog will need the navigation.
The main thing you need to understand here is that “$pages_to_show = 8″ simply means we’re going to list 8 pages other than the current page we’re on. You can change “8″ to whatever number you please. I’d strongly suggest that you use an even number as that will keep an equal number of pages on either side of the current page in our list.
2. How Big is Your Blog?
$blog_post_count = $matches[1];
$numposts = $wpdb->get_var("SELECT COUNT(DISTINCT ID) FROM $blog_post_count");
$max_page = ceil($numposts /$posts_per_page);
if(empty($paged)) {
$paged = 1;
}
Next, we determine how many posts your blog contains, how many posts you allow on each page, and use those two pieces of information to determine how many pages will be in our display. It also states that nothing will be displayed if the page doesn’t contain enough posts to need multiple pages in order to display all posts.
3. Where are We?
if($max_page > 1 || $always_show) {
echo "<div class='page-nav'><div class='page-nav-intro'>Page $paged of $max_page</div>";
if ($paged >= ($pages_to_show-2)) {
echo '<div class="page-number"><a href="'.get_pagenum_link().'">1</a></div><div class="elipses">...</div> ';
}
The next section contains the code that displays our navigation intro box that tells us which page we’re on and how many total pages there are. It also contains the code that displays the first page link once we move far enough from the first page that its not natively displayed in the list.
4. The Meat
for($i = $paged - $custom_range; $i <= $paged + $custom_range; $i++) {
if ($i >= 1 && $i <= $max_page) {
if($i == $paged) {
echo "<div class='current-page-number'>$i</div>";
}
else {
echo ' <div class="page-number"><a href="'.get_pagenum_link($i).'">'.$i.'</a></div> ';
}
}
}
This section is a bit complicated, but it basically just lists the number of pages that are to be displayed. Remember when we set that up in the parameters? It also sets up a seperate class for the current page. That way you can style it differently if that suits your fancy.
5. The End
if (($paged+$custom_range) < ($max_page)) {
echo ' <div class="elipses">...</div><div class="page-number"><a href="'.get_pagenum_link($max_page).'">'.$max_page.'</a></div>';
}
echo "</div>";
Finally, if the last page does not appear in our list natively, we include a link to it at the end.
6. Thesis Implementation
remove_action('thesis_hook_after_content', 'thesis_post_navigation');
add_action('thesis_hook_after_content', 'numbered_page_nav');
This is the easy part. You just need two lines of code (yep, Thesis rocks!). “thesis_hook_after_content” is the hook we’ll be using. It simply means that the numbered page nav will be placed below the end of the last post on the page. First, we remove the standard Thesis page navigation. Then, we add our custom function. If you wanted to place it below all content (posts and sidebars), but above the footer, you would use the “thesis_hook_after_content_box” hook. “thesis_post_navigation” refers to the standard Thesis page navigation. “numbered_page_nav” just indicates the name of the function we want to place in our chosen location.
And that’s it. Just copy and paste the whole thing into your custom_functions.php file and we’re ready to style!
Styling the Navigation
Just copy and paste this into your custom.css file and you are all done. Of course, you’ll want make stylistic adjustments to match the look of your blog.
/* NUMBERED PAGE NAV */
.page-nav { font-size: 1.35em; font-weight: bold; margin: 1em 0; padding: 0; overflow: hidden; }
.page-nav-intro { float: left; padding: .3em .5em; margin: 0 1em 1em 0; background: #efefef; border: .1em solid #ccc; }
.page-number { float: left; padding: .3em .5em; margin: 0 .2em; background: #fff; border: .1em solid #ccc; }
.current-page-number { float: left; padding: .3em .5em; margin: 0 .2em; background: #efefef; border: .1em solid #ccc; }
.elipses { float: left; padding: .3em .2em; }




{ 1 trackback }
{ 23 comments… read them below or add one }
Interestingly I was just thinking about doing this on my Thesis blog.
This is a good, thorough post but pretty technical. I’m nervous of completely ballsing my blog up if I try this.
I think your blog will attract more readers if you don’t just aim at bloggers who are comfortable with coding. The masses you want to attract aren’t.
At the moment your tagline (which is great) doesn’t line up with your content.
Mary,
Thanks for the keen observation. I will work on getting some more basic content on here. I also sent you an email with regards to what you would like to see. Look forward to connecting.
This is a bit of a technical article, but I wouldn’t worry about messing up your theme.
If you back up your custom_functions.php file before you do anything, you can always just load the backup in the event that something goes wrong :)
I just pasted the code into my blog and it works great. It’ll look even better when I have more than 2 pages!
I do have a question – I’m working on setting up category pages so that certain posts appear on certain pages, according to their primary category (Daily Logs appear on the Daily Log page, etc.). I’m not there yet (still trying to figure that one out!) but was wondering if the page number code will work across all pages or if I have to add it to individual pages to make it work on each individual page/category?
Thanks!
Rich
Rich,
It should work for all category pages.
Adam
Excellent tutorial and the code worked like a charm. Thank you
Awesome tutorial, worked like a charm!
Thanks…now if only I can figure out how to unravel complicated php scripts ;)
There is a PHP script I’m hoping someone can figure out.. I posted it in the classified section of the Thesis forums. The developer was sloppy from what I understand. (I don’t write code) Trying to get a PHP app to be “included” as a custom page. The owner of the software is no help.
I tried this on my site, vannonphotography.com and it worked but I can’t seem to get the colors to change even though I enter custom values for them. Any ideas?
Thanks
Tough to say what the problem is without actually looking at the code on your site. Just try to make sure the css selectors you are using match up to the ones in the code.
Thanks for the tip. I’m using “numbered page nav” code on this site, verbatim, in my custom.css file. I can change the font size but the color just doesn’t want to change. :-(
Looking at your site I’m assuming you are referring to the background colors and not the links/text themselves?
I would like to use this on tag archive pages as well, but every time I add the !is_tag() switch in with the !is_category() line, the nav disappears from the entire site.
Help? TIA.
That line of code doesn’t affect where the code displays. The nav should already display on your tag pages unless you have some sort of code that causes a conflict. It does for me…
Seems logical that may be the case, since my custom_functions.php is admittedly a bit of a mess.
I get the page nav on index and category pages, but nothing on tag pages, as you can see here:
http://www.pitchershiteighth.com/tag/albert-pujols/
Realize it could be anything, but do you have any suggestions on a good place to start looking? :)
Thanks.
BTW, FWIW – I’m not seeing the numbered nav at the bottom of your tag archive pages either…
http://www.artofblog.com/tag/thesis/
I’m having the same problem. It all works fine except on the tag archives. My site relies heavily on tags for navigation, so I’m going to have to remove the nav until someone (hopefully!) figures this out. Bummer.
Mark-
I got it to work on tag archives by changing this line:
if(!is_category()) {
to read this way:
if(!is_category() && !is_tag()) {
YMMV, but hopefully it will work for you too!
Nope, that just made it crash. Dang, I sure wanted to use the page nav. Thanks for your help!
Being code-challenged, I’ve had more than one custom_function tutorial cause my blog to implode… but this one rocks! Thank You!!!
Thanks for this one too! Only took a few minutes to implement.