WP_Query::reset_postdata()
sets the global post variable ($GLOBALS['post'] === $post
) to the current post in the loop of the current WP_Query
instance.
public function reset_postdata() {
if ( ! empty( $this->post ) ) {
$GLOBALS['post'] = $this->post;
$this->setup_postdata( $this->post );
}
}
What that means is that, if you run a custom query on a page, $post
will hold the last post in the loop of that custom query. That you can test yourself by adding
?><pre><?php var_dump($post); ?></pre><?php
directly after the loop of your custom query.
The same is true for the main query after the loop, $post
will hold the last post of the main query and the first post in the loop before the loop.
Here is a simple test to test the $post
global. You can add this into your functions file and load any page on your site
add_action( 'wp_head', function()
{
global $post;
?><pre><?php var_dump($post->ID); ?></pre><?php
}):
add_action( 'wp_footer', function()
{
global $post;
?><pre><?php var_dump($post->ID); ?></pre><?php
$q = new WP_Query( 'posts_per_page=3' );
while ( $q->have_posts() ) {
$q->the_post();
?><pre><?php var_dump($post->ID); ?></pre><?php
the_title();
}
?><pre><?php var_dump($post->ID); ?></pre><?php
wp_reset_postdata();
?><pre><?php var_dump($post->ID); ?></pre><?php
});
So how does it restore the post of the main query loop?
That is done by calling wp_reset_postdata()
which resets the global $post
to the current post in the loop of the main query. This is usually the first of last post depending if you add your custom query before or after the main query loop.
Lets look at how wp_reset_postdata()
does it
function wp_reset_postdata() {
global $wp_query;
if ( isset( $wp_query ) ) {
$wp_query->reset_postdata();
}
}
As you can see, wp_reset_postdata()
is just a wrapper for WP_Query::reset_postdata()
. The important part here is that it is a wrapper for the main query's object method, $wp_query->reset_postdata();
.
Remember, the main query also uses WP_Query
. Here is how the main query object is set
/**
* WordPress Query object
* @global WP_Query $wp_the_query
* @since 2.0.0
*/
$GLOBALS['wp_the_query'] = new WP_Query();
/**
* Holds the reference to @see $wp_the_query
* Use this global for WordPress queries
* @global WP_Query $wp_query
* @since 1.5.0
*/
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
So what wp_reset_postdata()
do is, it takes the current post in the main query object and sets that as the $post
global, and that is how WP_Query::reset_postdata()
sets $post
to the current post of the main query
global $wp_query
doesn't change but theglobal $post
object gets overwritten andwp_reset_postdata()
uses theglobal $wp_query
to reset the original$post
object. Hopefully someone with more knowledge of core can come in and submit a legitimate answer though.$wp_query
never changes, except if you usequery_posts
or if you use$wp_query
as a local variable. As for the rest of your comment, you are nearly spot on