Back to Top

Reset Post Data

Previous Post:

Reset Post Data

Querying for posts is made very easy in WordPress, so easy that no one seems to be happy with the main query. The main query can be understood as an invisible query that WordPress uses to set up default post data for a particular page.

For example, when you are on http://example.com/category/book/, WordPress will automatically query for posts in category ‘book’, conveniently set up the post data, cache some and then make it available for The Loop (just like what Mark Jaquith posts on his blog: “WordPress puts food on my table.”)

Some people think the food tastes good but some don’t and they try to cook something else using:

  1. query_posts(array('post_type' => 'fish'));
  2. // or
  3. $my_query = new WP_Query(array('post_type' => 'fish'));
query_posts(array('post_type' => 'fish'));
// or
$my_query = new WP_Query(array('post_type' => 'fish'));

and then serve the food to their customers using:

  1. if ($my_query->have_posts()) :
  2.     while ($my_query->have_posts()) : $my_query->the_post();
  3.      // the_title(); the_content(); ...
  4.     endwhile;
  5. endif;
if ($my_query->have_posts()) :
	while ($my_query->have_posts()) : $my_query->the_post();
	 // the_title(); the_content(); ...
	endwhile;
endif;

However they choose to cook their pages, there is one ingredient that must be used: the $post variable – a global variable that is used almost everywhere in the loop above, yet doesn’t even want to show its face.

Being a global variable, the contents of $post are modified every time you use the_post(), or similar functions. $post is first set up by the main query, and by using those custom queries like above, you are effectively replacing post data created by the internal process of WordPress.

Now this might not be a problem at all if you are customizing your homepage, because such replacement is exactly what you would expect for an index page. Unexpected behaviours should only occur on singular pages where the $post variable is used from the start of the header to the end of the footer.

In page.php, try putting this before get_sidebar():

  1. $my_query = new WP_Query('posts_per_page=1');
  2. if ($my_query->have_posts()) :
  3.     while ($my_query->have_posts()) : $my_query->the_post();
  4.         // the_title(); the_content(); ...
  5.     endwhile;
  6. endif;
$my_query = new WP_Query('posts_per_page=1');
if ($my_query->have_posts()) :
	while ($my_query->have_posts()) : $my_query->the_post();
		// the_title(); the_content(); ...
	endwhile;
endif;

and in your sidebar.php, put this in:

  1. global $post;
  2. echo $post->post_title;
  3. // or
  4. the_title();
global $post;
echo $post->post_title;
// or
the_title();

Now if you refresh a page you should see some text in your sidebar, which is expected to be the current page’s title. However, the text you would see is your newest post’s title instead.

As you might have guessed, the $post variable has been modified by your custom query in page.php and it no longer contains the current page’s data, which in turn makes WordPress show unexpected output for the rest of your website/blog.

There’s two easy ways to fix this:

1. Temporary store the $post variable and then assign its contents back:

So, before you do this: $my_query = new WP_Query('posts_per_page=1');, add this line:

  1. $temp = $post; // $temp = clone $post for PHP4
$temp = $post; // $temp = clone $post for PHP4

and after you finish the loop for the custom query, add this:

  1. $post = $temp; // $post = clone $temp for PHP4
$post = $temp; // $post = clone $temp for PHP4

The current page’s data is now back!

2. Use wp_reset_postdata():

A simpler approach you can use is this:

  1. $my_query = new WP_Query('posts_per_page=1');
  2. if ($my_query->have_posts()) :
  3.     while ($my_query->have_posts()) : $my_query->the_post();
  4.         // the_title(); the_content(); ...
  5.     endwhile;
  6.     wp_reset_postdata();
  7. endif;
$my_query = new WP_Query('posts_per_page=1');
if ($my_query->have_posts()) :
	while ($my_query->have_posts()) : $my_query->the_post();
		// the_title(); the_content(); ...
	endwhile;
	wp_reset_postdata();
endif;

wp_reset_postdata() should effectively revert your $post to its original contents, thus allowing you to work with multiple queries on one page.

Please note that wp_reset_postdata() will not help in the situation when you have one custom query nested in one another and you would like to revert back to the first custom query after finishing the second. You will have to use the first approach for that.

Print Article Trackback Trackback to this Article   Subscribe to Comments RSS Subscribe to Comments RSS
 Sponsor   Themes by Elegant Themes - Unlimited access to all themes for $39!

3 Opinions for Reset Post Data

  1. User's Gravatar
    1
    Johan August 29, 2012 at 10:18 am – Permalink

    Terrific! $temp = $post was a GREAT help.

  2. User's Gravatar
    2
    Ray November 21, 2012 at 2:26 pm – Permalink

    I think you just saved me several hours more of frustration. I’ve being trying to reset a nested loop using wp_reset_postdata(), to no avail. Thank you!

  3. User's Gravatar
    3
    Gareth January 11, 2013 at 4:33 pm – Permalink

    It never ceases to amaze me that whatever the issue, or how baffling code bugs can sometimes be, someone somewhere in the world has had the same problem…thank god for the internet, and people like you Khang… for sharing this info and explaining clearly…awesome…problem fixed …a great start to my day…many thanks.

Speak Up Your Mind!

An asterisk (*) indicates a required field and must be filled.




  • Web page and e-mail addresses turn into links automatically.
  • Wrap codes in: <code lang=""></code> or <pre lang="" extra="">
  • Lines and paragraphs break automatically.

Next Post: