How does reset_postdata restore the post of the main query loop?

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

Leave a Comment