Working with Wordpress and coding themes is fairly easy to me. However, as is with every project, there comes a time in the process where you eventually pull your hair out. Such was the case when developing some simple if logic for the sidebar.
My goal was simple — suppress the Blogroll and Meta sections in the sidebar for any page except the Home Page. Logically, I thought, just surround the sections with the conditional tag is_home() should accomplish this simple feat. The Wordpress Codex even has a dynamic sidebar example for the use, pretty straight forward.
Take the following snippet of sidebar code for example. I am displaying a list of recent posts, immediately followed by the conditional blogroll.
<ul class="sidebar_list">
<li class="widget">
<h3>Latest Blog Entries</h3>
<ul>
<?php query_posts('showposts=10'); ?>
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<li><a href="<?php the_permalink() ?>"><?php the_title() ?></a></li>
<?php endwhile; endif; ?>
</ul>
</li>
<?php if(is_home() && !is_paged()): ?>
<li class="widget">
<h3>Blogroll</h3>
<ul>
<?php wp_list_bookmarks('title_li=&categorize=0'); ?>
</ul>
</li>
<?php endif; ?>
</ul>
The above code returns true for is_home() on each and every non-home page or post. Why is that? This is where I lost quite a bit of hair, mostly from the left side of my head and therefore most of the insulation to the thinking part of the brain. Good thing the heat works around here.
It took quite a lot of searching. This is not an easy thing to Google for, but eventually came across some answers.
The culprit in the code was the use of query_posts() in the recent posts widget. If I swapped the positions of the two widgets, is_home() functioned correctly. The query_posts() function has an obscure little bug if you do not destroy it properly with a call to wp_reset_query().
There isn’t any documentation on wp_reset_query() in the Codex, so I will cite the comment heading from the Wordpress core file, query.php, which this function is from:
wp_reset_query() destroys the previous query and setup a new query. This should be used after query_posts() and before another query_posts(). This will remove obscure bugs that occur when the previous wp_query object is not destroyed properly before another is setup.
So I added that function immediately following the endwhile in the recent comments widget, and bam, everything was right in the universe again.
....
<?php query_posts('showposts=10'); ?>
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<li><a href="<?php the_permalink() ?>"><?php the_title() ?></a></li>
<?php endwhile; endif; ?>
<?php wp_reset_query(); ?>
....
Searching for references to wp_reset_query() in the Wordpress core files reveals only one instance of usage. That instance, oddly enough, is in the widget.php function for displaying the recent entries widget. Imagine that!
Reviewing the code, however, I made another discovery. Instead of using query_posts(), they create a new WP_query object to cycle through the posts and generate the recent entry list items. They use the new object in order to preserve the original query in the main loop, the loop that displays your posts on page. More importantly, the new object preserves the values of is_home() and other conditional tags — the use of wp_reset_query is really not needed here. Seems to be a left over from a previous version and not edited out of the core code.
In order to do this the wordpress-ian way, I recoded my sidebar widget for recent posts (sans wp_reset_query):
<li class="widget">
<h3>Latest Blog Entries</h3>
<ul>
<?php $r = new WP_Query(array('showposts' => '10', 'what_to_show' => 'posts',
'nopaging' => 0, 'post_status' => 'publish', 'caller_get_posts' => 1)); ?>
<?php if ($r->have_posts()) : while ($r->have_posts()) : $r->the_post(); ?>
<li><a href="<?php the_permalink() ?>"><?php the_title() ?></a></li>
<?php endwhile; endif; ?>
</ul>
</li>
If you follow my logic in tracking down this little bugger, you will notice that my first resource to check was the conditional tag documentation in the Codex. Sadly, there is no mention of the consequences you will encounter by using query_posts() which alters the original page loop.
The WP support forum is filled with questions of ‘why is this not working’. Some go unanswered, some they fix and leave no reason how, some get the ‘review the conditonal tags documentation’ buddy, and so on. It took a lot of searching to get a whiff of what I needed to do to correct the situation.
My suggestion is to at least insert a caveat into the documentation for conditional tags warning of what will happen to those tags if another query_posts() is called. This is the first place people will actually look for help after all. And it would probably save a lot of people’s time in the long run, not only the people seeking it, but the people offering a solution as well.
UPDATE: The discussion for the creation of wp_reset_query() function can be found at http://trac.wordpress.org/ticket/4741 if you are interested. Thanks to Stephen’s post Automated Indexes and wp_reset_query() at Nerdaphernalia for pointing this out.








Thanks a lot! This definitely solved my problem as I use a lot of query_posts in my custom themes. And I’m no PHP-developer.
Plus, you’re damn right about the Wordpress support. I couldn’t get any answers from the Codex nor the forums.
Thanks again for this.
great, I’ll use it on my theme
Great insight. I have been having some similar issues, but have found that even when I use the new WP_Query() call instead of query_posts(), my loops are still not resetting.
I execute a couple of embedded WP_Query() calls in a nav.php custom menu, attempting to retrieve a nested category, sub-category and post title multi-tiered menu. It works absolutely perfectly, displays correctly and links to where it should, except that the last post to be included in that menu carries its id over to the single.php page when it is called, meaning that no matter what post is selected, the same post keeps appearing. (the URL is correct for each individual post, it is just the post title and content that is stuck.
If you could shed any light on this nightmare for me I would greatly appreciate it
I have searched for hours and have tried many “hit and miss” fixes, but no matter what I try the loops don’t seem to be resetting once they are done.
Supposedly, you can use wp_reset_query() ‘before’ your call to query posts. Use that before your query for custom nav call and NOT after.
Currently on vacation and out of town (limited connectivity). If you are still having problems next week, give me a shout. Will have time to review in more detail then.
Great tip, thanks
Greetings
Tks a lot for this post. I was struggling with my sidebar.php to hide admin form when not in home about a couple of weeks.
Best regards
Thank you…so much. Was always having trouble with a custom query in a lefthand sidebar. Without the reset_query function, the right-hand content would always be the last page or post retrieved in the sidebar’s custom query. A great tip.
So useful, thanks for sharing this..
There is now a reference to this function in the codex. Search wp_reset_query.
There is also an ongoing discussion on the forums. Search for “query_posts codex correct or not?” in the forums. Thanks for posting about this issue. The more the word gets out the more stability folks will have with their blogs and themes.