Last week I published two articles using custom loops. The first was about how to create a custom loop. The second was how to retrieve posts based on custom fields. In both articles, several readers commented that they would like to see paging and have it explained.
I’d like to thank Aaron Harun from Anthology of Ideas for supplying the code used in this post.
Paging, and why it doesn’t work with WP_Query
The paging magic happens in a file called ‘link-template.php‘ in the ‘wp-includes‘ folder.
Most themes have basic paging built in, with the help of two functions: next_posts_link and previous_posts_link.
These functions, as well as several others, make use of a global variable called $wp_query. This variable is actually an instance of the WP_Query object. However, when we create our own instantiation of WP_Query, we don’t have this global variable $wp_query, which is why paging will not work.
How to make paging work with a custom loop
As Aaron mentioned, the paging functions rely on a global variable called $wp_query. The “fix” is to trick WordPress into using the global $wp_query variable when using our own custom loops.
In the example below, I’ll show how to display the last five recent articles with our own custom loop with paging intact.
<h3>Recent Articles</h3> <ul> <?php $temp = $wp_query; $wp_query= null; $wp_query = new WP_Query(); $wp_query->query('showposts=5'.'&paged='.$paged); ?>
The first thing the code does (shown above) is create a temporary variable to hold a reference to global variable $wp_query. The wp_query variable is set to null, and we instantiate a new WP_Query object.
Notice in the query above that we have these parameters:
$wp_query->query('showposts=5'.'&paged='.$paged);
The paged portion of the query is critical in order to have paging.
From there, we can now do our own query and begin our custom loop.
<?php while ($wp_query->have_posts()) : $wp_query->the_post(); ?> <li><a href="<?php the_permalink() ?>" rel="bookmark"><?php the_title(); ?></a></li> <?php endwhile; ?> </ul>
Notice in the above code that the loop is initiated using the $wp_query variable. Since we are using $wp_query, paging should work.
Now it’s time to create our navigation links for paging:
<div class="navigation"> <div class="alignleft"><?php previous_posts_link('« Previous') ?></div> <div class="alignright"><?php next_posts_link('More »') ?></div> </div>
And finally, we assign the variable $wp_query back its original value using the $temp variable we set earlier.
<?php $wp_query = null; $wp_query = $temp;?>
The Full Code
<h3>Recent Articles</h3> <ul> <?php $temp = $wp_query; $wp_query= null; $wp_query = new WP_Query(); $wp_query->query('showposts=5'.'&paged='.$paged); ?> <?php while ($wp_query->have_posts()) : $wp_query->the_post(); ?> <li><a href="<?php the_permalink() ?>" rel="bookmark"><?php the_title(); ?></a></li> <?php endwhile; ?> </ul> <div class="navigation"> <div class="alignleft"><?php previous_posts_link('« Previous') ?></div> <div class="alignright"><?php next_posts_link('More »') ?></div> </div> <?php $wp_query = null; $wp_query = $temp;?>
Additional Applications
The above technique can allow paging for custom loops. All you have to do to modify this is to use your own query parameters, and change the code within the custom loop.
Recent Articles Example
The above example is live at raproject.com under Recent Articles.
Conclusion
Paging is a powerful WordPress feature, and fortunately you can use it when defining your own custom loops.
The example I demonstrated was rather generic, but hopefully you’ll be able to apply it to your own custom loops where paging is necessary.
Please feel free to share your own examples or problem code in the comments. If you use code, please use something like pastebin since some code isn’t allowed in the comment section.
My blog has nothing with pages in the loop but its a good example of the category/gallery function that has become available via 2.5. An example of this can also be seen on Matt’s page…
I’m not as familiar with php (and WordPress) as with c++, but why not just use a different name for your new $wp_query instance, say $my_query, and leave the existing one as is?
@Carson – That’s what I’ve done in the past. I don’t really understand why you would need to use $wp_query, when you can use a different name. But it seems that everyone has a different way of doing it. 🙂
@Carson and Darryl,
Certain functions specifically call the $wp_query directly and don’t allow you to change the variable name. You can use $my_query, but for those functions that call $wp_query, they won’t work or, even worse, they will refer to the original $wp_query.
@Aaron: I see. I understand that “the loop” is supposed to be a convenience for template builders. But for me it has been more like a millstone around my neck. Then I discovered that some (maybe all?) of the functions that only work in the loop have non-loop versions. I’m sure there is a reason for all this but I’ve found that when work-arounds abound there is usually an underlying design flaw. Let me add though that in my career as a coder I never had to satisfy millions of users — at most dozens.
This was helpful, I have a bunch of static pages in the loop (I added WP on top of a mostly static site).
@Carson,
Yes, the loop functions typically use global variables and also call other non-loop functions. The issue here is paging, and using something other than wp_query (a global variable) will break paging.
The other article I wrote (mentioned at the very beginning) covers custom loops that don’t require paging.
@Ronald: Your “how to” posts have been quite helpful. I have them all bookmarked. Thank you.
@Carson,
Thanks a lot! I hope they can help you out. If there’s anything else you’d like to know, please let me know. This post was written as a direct result of reader questions.
Nice post(s) on loops.
You can take this a step further and add a category tag to the query to loop category based posts into section to make widgets such as asides or side blogs.
In 2.3 and up you can use:
$wp_query->query('cat=X&showposts=5'.'&paged='.$paged);
Where “X” is the number of the category of interest.
@hso,
Yes, there are a very wide variety of applications. Using the query_posts parameters, and even filters, the possibilities seem endless.
Thanks for sharing your technique.
I implemented your example code on my locally hosted test blog and found that it worked well except for one thing. When I click the More link it advances the actual recently posted articles as well as the new list of recently posted article titles. I looked at your implementation at raproject and saw that it doesn’t do this. Any idea why mine behaves that way?
Great stuff, just what I needed for a WordPress project.
How would you use this with an offset? For example ‘&offset=1’, so it doesn’t show the most recent 1 post. I tried usuing it as usual and it broke the navigation control
@John,
That’s odd. I haven’t tried an offset, but I know what you mean. Let me play around a bit and see if I can figure out what’s wrong.
Thanks Ronald, I look forward to seeing what you can come up with!
Thanks! I have been googling around for quite some time now looking for a way to do this! I’m surprised this information was so difficult to come by.
This is that I really looking for, thanks to make it Possible 😉
Thanks for the code tip.
However, if
$wp_query->query('cat=X&showposts=5'.'&paged='.$paged)
will get me everything from category X, how do I modify it to get posts that are in both category X and category Y?You, sir, are a genius. I’d been trying to wrap my noob programmer head around multiple loops for a bit with code pulled from multiple templates; your solution pretty much fixed my problems. Thank you!
thanks. this worked for me. however, is there a way to have page numbers inserted in between the “<>” tags? much like what is done here: http://www.inquirer.net/specia.....rchive.php ?
I’m working on a three loop theme, and I’m trying my hardest to get the next_posts_link to rotate all three loops. It’s driving me mad, because I can get it to work for two out of three, but not the last loop.
Any ideas?
The code:
http://wordpress.pastebin.ca/1094042
@Dan,
I’m afraid not. I’ve never gotten paging to work on more than one loop since they all use the same global variable.
I got this to work with:
wp_reset_query(); // reset to make pagination work for later …
You can use it when you want to use multiple loops! 🙂
I’m trying a lot of similar stuff to your more recent comments. I have a page I’m breaiking into two columns (using divs). One column shows the first 5 posts from a category, the other shows the next 5 (using offset). I wanted to know if this method of pagination will allow the next page to “pick up where I left off” and continue the two column format.
Otherwise… great code. It really helped in another situation.
You sir, are awesome! Thanks for the post!
Heh. This works – but *only* if you’re using the default permalinks. I’ve been trying to figure this out since 2.1.x. I’ve just upgraded to 2.5.1, and I’m still having issues. I can do this – but only if I have “pretty permalinks” shut off.
Got any ideas why? (But thanks for the tut – I’m one step further than i was when I started!)
It seems easier to just use the query_post call outside the loop while passing in the parameters including the paged. Seems to work just fine for me.
array(5,1), // fileter out categories
‘showposts’ => 3, // limit post per page
‘paged’ => $paged, // allow for paging
‘year’=> $current_year,
‘monthnum’=>$current_month,
‘order’=>’DESC’, // sort by newest first
));
?>
Dude! just what i needed
I feel really dumb right now… What is supposed to be defined in “$paged”? In my site it seems to be a blank variable.
Adam
Hey there, this worked really well to resolve some basic pagination behavior – posts are now getting paginated properly… sort-of:
Pagination works once (eg. going from mydomain.com/news/ -to- mydomain.com/news/page/2). Going to page/3 however, results in a 404.
I tried to correct this in a number of ways by messing around with the query, but a bit of searching revealed that I’m not the only one experiencing this issue, and that no-one’s seemed to find a functional solution. The problem seems to arise when the blog uses a custom permalink structure, uses a static front-page, and has a custom wp_query in which showposts doesn’t agree with the default post display settings in ‘read’. Unfortunately, my entire reason for needing a custom query is to deal with paginated post lists of differing lengths on separate pages.
Any ideas? I’m tearing my hair out over this one 🙁
Thank you a lot Ronald!
I spend a lot time trying to get some sort of third type of terms worked into a wordpress installation (in addition to tags and categories) with custom fields. I would never have got it without your articles.
thanks for this, been looking for a solution to a multi loop setup and this works flawlessly…
Perfect!!!
thanks so much for this blog post. The paging now works for my query. 🙂
This code is a god send, i cannot believe this is readily available, i have literally been searching months for something like this, i even explorer incorperating ajax just to get something like this. Maybe thats just my dumbness when it comes to PHP and wordpress.
One thing i will ask for is if i wanted to do two different instances of this then how would i achieve that, ive tried changing every possibly parameter to stop the second instance controlling the first one. Is this even possible or am i just being unrealistiic.
Any hints towards on how i would do this would be greatfully appreciated. My email address is craigy(dot)pearson at gmail (dot) com. Ill keep checking back.
Thank you once again… you have saved many people from certain death by letting me have this code!
Calling naked “wp_query->” stuff doesn’t make any difference. You can have much cleaner code by simply calling query_posts() function.
If you use a permalink structure of “%category%/%postname%” your pagination will break in WP anyway, all the way until 2.7 too — this issue, looking at the forums, has still not been fixed.
Try your own code with the permalink structure set to the above and you’ll see.
This hack works!!! I can’t believe it’s 2.7 and it’s not fixed =(..
Also, I’ve used some plugin to generate a pagination with number list. The plugin seems to not be able to generate the paged number list, which I think require the original loop + hook.
Your comment/insight on this Ronald?
Tnx, saved me a lot of php-hacking. 🙂
This is a great script, but I seem to have found a snag.
Working with Pagenavi… I get a blank page on the end because in my query I’m omitted category=3, yet, I think the pagination is still assuming they are there and creating a blank page.
anyone else getting this?
aaand nevermind… I forgot to declare the wp_query null again AFTER the pagination.
thanks!
I am so grateful for this post, it solved my problem with pagination on archive pages I had set up to only show selected category posts. I spent hours trawling the internet for solutions etc. and came across your site. It worked immediately. Thank you so much. I am sure there are loads of people having this prob when they start using wp_query to only show selected categories. BIG THANK YOU
I have the problem with pagination an custom query, but I’m using a ‘raw’ mysql custom query
$querystr = “SELECT * FROM $wpdb->posts ….
….
$pageposts = $wpdb->get_results($wp_query->request, OBJECT);
if ($pageposts) {foreach ($pageposts as $post) …..
Any idea on how to get to the same result ? I just can’t figure out how to “to trick WordPress into using the global $wp_query variable” or even if it can be done. Any help will be apreciated.
Thanks
Still true, this method not works with custom permalinks. Any ideas how to solve it?
hi!
Im was happy reading but suddenly when I tried to add a category filter to my wp_query, mi page didn’t show anything, that sounds like a problem out of my hands! anyone could help me to resolve the pagination drama?
http://hoolian.pastebay.com/12723
Does this work from within a normal “Page Template”?
Essentially, I’m looking to at a Portfolio “Page” which would pulls posts from the Portfolio category. However, I would like these paginated.
I’ve seen these types of loops used in index.php, but how about page.php?
Any help would be appreciated.
i cant make it work in a page that shows two columns posts , the pagination will only work for one row, any thoughts?
thanks
I think I found a bug on this. When you have no. of posts in the WP admin set to 10 and you run a query to showposts=5, it only shows paging upto the number of pages calculated by no.of posts in admin area and not the showposts.
For example, if the total posts show 4 pages (using default 10 posts per page) and you run a query to show 5 posts, it will only work till page 4. Page 5 will render a 404.
Is there any solution to this? Can’t find it anywhere..
Thanks.
Anyone have thoughts on how this method of paging might be extended to page through categories? Here’s the situation…
Categories/Subcategories/Posts:
items-by-week
Week 1
Post 1, Post 2, Post 3
Week 2
Post 1, Post 2, Post 3
My custom loop is built to find all children of “items-by-week”, then for each child (week), shows the posts for that week.
Goal is to have weeks 1-5 (for instance) on the first page, 6-10 on the second, etc.
Any possibility that this strategy could be extended to accomplish this?
Thx!! holling
thanks alot for this, i was stuggling with WP_query not paginating, and as i use it constantly for multiple loops this will be very very helpful…
Thanks for sharing this. Works Perfect!
Thank you for the tip; I’ve been wondering why my inside blog pages won’t paginate properly.
You just made my day – thanks for this, it saved me big time!
I had /blog set as a custom page template showing the latest posts, but whenever I clicked Previous Entries, the same posts appeared, even though the URL was /blog/page/2.
This did the trick!
Thanks.
Thank you SOOOO much, this really made my day!! I’ve been trying to find a good solution for displaying the previous posts in my category based pages for weeks now and this really fixed it all!
Just out of curiosity… why all the extra lines? I do this frequently, but all I need to do is this:
<?php $postquery = new WP_Query(‘showposts=4&paged=’ . $paged);
if ($postquery->have_posts()) : while ($postquery->have_posts()) : $postquery->the_post(); ?>
layout here
<?php endwhile; endif; ?>
That’s all there is to it. The “new WP_Query()” starts a whole new wp_query instance – there’s no need to clone it or set it as null and then reset it – it’s all done within that single call for you.
Hey Shelly, I think the reason the query object is stored in the temp variable is just in case an another loop needs to be made with the original query – however, in the context of this example you’re right, its useless code.
Anywho, i think im in the same position as you. This simply doesn’t work with custom permalinks, and i have tried everything. Its says so in the wordpress codex (next and previous buttons will not work with single pages or pretty permalinks). How have you got on? Any luck?
*This is open to everyone with the same problem*
hello!
this post finally ended 3 hours of paging frustration.
I finally landed on this post and boom! problem solved.
In my case, I am using wordpress as a backend and using CodeIgniter as my frontend. so the loop that I have (bootstrapping WordPress into CodeIgniter’s index.php) mostly works the same. But I had the same problem when it came time to paging.
My code:
global $paged;
global $wp_query;
$temp = $wp_query;
$wp_query= null;
$wp_query = new WP_Query();
$wp_query->query(‘&paged=’.$paged);
query_posts(‘offset=’.$offset);
I’m not sure what sort of problems some of you are having with custom permalinks, In my case, it’s all custom because I’m not using wordpress’ theme system, passing $offset and $paged got my pagination working.
I’m hoping this helps out some of you out there.
Thank you so much for this tutorial. I’ve been searching all night for a solution, and yours was the only one that could make sense of the whole mess. You rock!
I just used $wp_query->query(‘cat=24,34&showposts=’.get_option(‘posts_per_page’).’&paged=’.$paged);
then the
have_posts()) : while ($wp_query->have_posts()) : $wp_query->the_post(); ?>
etc and it works fine.. am i missing something :s
Thank you so much! This solved hours of frustration, and all I had to do was change the variable name to wp_query.
LOL. it's amazing to see that this post is still so useful after all this time. You just saved my bacon!
-colin
How would this work with the “WP Pages” plugin? The plugin requires replacing the custom loops with the function below:
I tried this on http://www.thebudgetbagista.com, and as you can see, paging is not working. The plugin created a custom page navigation menu at the very bottom of the last homepage post. When you click on page “2”, it displays the same posts that appear on page “1”.
Can anyone help with this?
THANK YOUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU!!!!!!!!!!!!!!!!!!!!!!!!!!
Thanks a lot.. exactly wat i was looking for.. u made my day .. God bless
Thank you! Thank you! Thank you! I can’t thank you enough! I have been searching everywhere for the solution to the problem I was having, and this worked perfectly!
You saved me day! Awesome 🙂
It’s so obvious that I didn’t see it. Thank you very much for sharing this tip. 🙂
There’s no need for that trick if the “query_posts” function is used and the config parameter “paged” is used and set to “get_query_var( ‘paged’ )”.
Read the codex, all info is there.
This method works for permalink URLs too, I’ve never had any problem.
Thank you thank you thank you!!! I’ve been googling for a while trying to figure out why my nav links weren’t showing up, and yours was the only site I found with an (awesome, easily understandable) explanation. Thanks so much! Subscribed to your RSS feed =)
This is great! I am having one issue. I am trying to make it work with categories and subcategories. I found this great code that works the way I want but it does not have the pagination like yours. I am a beginner at PHP. So any tips would be great! Here is the code that functions properly but I am not sure how to add the pagination like you did above:
cat_ID&showposts=-1&order=name&orderby=name&showposts=22″.’&paged=’.$paged ); ?>
cat_ID); ?>
<a href="” rel=”bookmark” title=”Permanent Link to
“>
Please help!
Chaning:
$query = new WP_Query( array( ‘post__not_in’ => $duplicate_ids ) );
To:
$query = new WP_Query(“post__not_in$duplicate_ids,&paged=$paged”);
Worked for me, thanks 😉
Legend!
That makes total sense and worked first time. Thankyou!
Such an old post!
but still very useful & informative, helped me out anyway, cheers
Great, you’ve solved a problem in an inbelievable simple way! Thank you very much! 😉
Thanks! works like a charm after hours of pulling my hair out!!
——–
Fatal error: Call to a member function have_posts() on a non-object in /home/www/mysite.com/wp-content/themes/themename/home.php on line 171
——–
this was in my case,
– I am using the {Custom Post Type with front end post & WP post} to display in home page.
– The WP post with two query not to duplicate the first post.
and when I tried your codes in my CPT, I had this error.
Thanks for your effort.
Is it possible to show the list only? So that the last article in the list doesn’t show in full?
Thanks
-Andrew.
This. Is. Awesome. Perfect solution!
Thank you so much for this easy solution. I tried so many different things and read up on the forums but nothing worked until I came across your site. Thanks for posting this!
Hi,
Has anyone managed to get this working with 2 colums at all? (offsetting more posts in the second column)? I’m really struggling to get that to work! Any help would be amazing!
Thanks
Ok, I’ve been looking for this answer for the better part of the day. Your post is the only one that has gotten page pagination working for me. Thanks so much!
Tearing my hair out – this doesnt work eventhough a recent response from 2012 says it does. Anyone know if WP has changed in some way? It displays properly but the pagination link results in a page not found.
THANK YOU!! ive been searching for this solution. not even stackoverflow/wordpress official forum was able to help me! this posts is pure genius! thanks!~