Use this function to restore the context of the template tags from a secondary query loop back to the main query loop.
Differences between the main query loop and secondary query loops are:
the main query loop is based on the URL request and is initialised before theme templates are processed
secondary query loops are queries (using new WP_Query) in theme template or plugin files
A secondary query loop using $sec_query = new WP_Query() and $sec_query->the_post() affects the global $post variable. The global $post variable is used by template tags by default. wp_reset_postdata() restores the global $post variable to the current post in the main query (contained in the global $wp_query variable as opposed to the $sec_query variable), so that the template tags refer to the main query loop by default again.
Example
<?php
$args = array( 'posts_per_page' => 3 );
// the query
$sec_query = new WP_Query( $args );
?>
<?php if ( $sec_query->have_posts() ) : ?>
<!-- start of the loop. the_post() sets the global $post variable -->
<?php while ( $sec_query->have_posts() ) : $sec_query->the_post(); ?>
<!-- template tags will return values from the post in the $sec_query object
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endwhile; ?><!-- end of the loop -->
<?php else: ?>
<?php _e( 'Sorry, no posts matched your criteria.' ); ?>
<?php endif; ?>
<!-- reset global post variable. After this point, we are back to the Main Query object -->
<?php wp_reset_postdata(); ?>
Note: If you use the_post() with your query, you need to run wp_reset_postdata() afterwards to have template tags use the main query’s current post again.
<?php
// example args
$args = array( 'posts_per_page' => 3 );
// the query
$the_query = new WP_Query( $args );
?>
<?php if ( $the_query->have_posts() ) : ?>
<!-- start of the secondary loop -->
<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
<?php the_title(); ?>
<?php the_excerpt(); ?>
<?php endwhile; ?>
<!-- end of the secondary loop -->
<!-- put pagination functions here -->
<?php else: ?>
<p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p>
<?php endif; ?>
<!-- reset the main query loop -->
<?php wp_reset_postdata(); ?>
WARNING, only reset the post data if the query is successful…
$query = array(
//some post query parameters
);
$post_results = get_posts($query);
if(!empty($post_results)){
//do something with your query results
//invoke post data reset here
wp_reset_postdata();
}
//if you invoke it after the check and the result did not return any posts, it will reset the post data from a previous query
wp_reset_postdata(); // WRONG
This is only true if someone overrides the main `global $wp_query` variable – which I would encourage you NOT to do unless you are really sure of what you are doing in the first place. Use a seporate variable to store your custom queries when you make them.
As I have just learned, there is a long-standing bug (reported 12 years ago) that results in wp_reset_postdata() not working properly in the admin panel.
In my case, metabox values were not saved on a specific page with a custom WP_Query even though I was calling wp_reset_postdata() afterwards. The error message I had (visible through the browser console -> network tab) was: 400: A post ID mismatch has been detected.
I hope that this comment saves someone a few hours digging…
Example of secondary loop and reset
Note: If you use the_post() with your query, you need to run wp_reset_postdata() afterwards to have template tags use the main query’s current post again.
WARNING, only reset the post data if the query is successful…
As I have just learned, there is a long-standing bug (reported 12 years ago) that results in
wp_reset_postdata()
not working properly in the admin panel.In my case, metabox values were not saved on a specific page with a custom
WP_Query
even though I was callingwp_reset_postdata()
afterwards. The error message I had (visible through the browser console -> network tab) was:400: A post ID mismatch has been detected.
I hope that this comment saves someone a few hours digging…
More info & working workaround:
Can’t wp_reset_postdata after custom WP_Query in an admin edit page