How does reset_postdata works? The docs say:

restore the global $post variable of the main query loop after a secondary query loop using new WP_Query

But in the class, it takes the "current" post of the current WP_Query instance, and set it as the global $post. So how does it restore the post of the main query loop?

The WP_Query class.

  • 1
    It seems like the global $wp_query doesn't change but the global $post object gets overwritten and wp_reset_postdata() uses the global $wp_query to reset the original $post object. Hopefully someone with more knowledge of core can come in and submit a legitimate answer though.
    – Howdy_McGee
    Jan 30 '16 at 1:55
  • 2
    @Howdy_McGee the global $wp_query never changes, except if you use query_posts or if you use $wp_query as a local variable. As for the rest of your comment, you are nearly spot on Jan 30 '16 at 7:23

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() ) {

        ?><pre><?php var_dump($post->ID); ?></pre><?php 


    ?><pre><?php var_dump($post->ID); ?></pre><?php 
    ?><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 ) ) {

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

  • Thanks, ok, I thought wp_query was reused by our second query, but wp_query is not changed. I get it now, thanks.
    – Paul
    Jan 30 '16 at 15:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.