Where should you reset postdata?

I’ve searched for this in the Q&A but I was unable to find it. When I read answers throughout the site I see wp_reset_postdata() placed in multiple areas with the have_posts() conditional and outside the conditional all together. When I read the documentation on wp_reset_postdata() all it states is:

After looping through a separate query, this function restores the
$post global to the current post in the main query.

with a snippet of:

<?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 -->

    <!-- reset the main query loop -->
    <?php wp_reset_postdata(); ?>

<?php else:  ?>

    <p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p>

<?php endif; ?>

but when I reference other ways, such as “How to fix pagination for custom loops?” it’s after the conditional:

// Output custom query loop
if ( $custom_query->have_posts() ) :
    while ( $custom_query->have_posts() ) :
        $custom_query->the_post();
        // Loop output goes here
    endwhile;
endif;
// Reset postdata
wp_reset_postdata();

Wouldn’t it be appropriate to have it afterwards and not within the have_posts() conditional because if you do use an else statement the arguments aren’t being reset if you do not have posts. So my question is where should wp_reset_postdata() go?

3 s
3

Short version:

As Tom J Nowell said,

You shouldn’t cleanup if there’s nothing to clean

Long version:

However, if you put wp_reset_postdata() after (or outside) the loop, it would still work perfectly fine. I have used the function in various scenarios, including something like this:

dynamic_sidebar( 'main-sidebar' );
wp_reset_postdata();

The reason was that some widget was querying posts without cleaning after itself.

Just keep in mind which query you want to reset. In Tom’s example, no matter if wp_reset_postdata is within the if statement or not, once it gets called, you will have problems because it will directly go back to the main post instead of the parent custom loop.

What the function does is tell a WP_Query object to restore the current post to the global scope. Since it’s a function instead of a method, then there is a single object it works with – the global $wp_query instance of the WP_Query object.

If you have custom loops, where you use a newly generated WP_Query, you should use the reset_postdata method of that query:

$pages = new WP_Query( 'post_type=page' );
while( $pages->have_posts() ) {
    $pages->the_post();

    // Page title
    echo '<h1>'; the_title();  echo '</h1>';

    $books = new WP_Query( 'post_type=book&...' );
    if( $books->have_posts() ) {
        while( $books->have_posts() ) {
            $books->the_post();

            // Book title
            echo '<li>'; the_title(); echo '</li>';
        }

        // Don't go back to the global post, go back to the "page"
        // wp_reset_postdata();
        $pages->reset_postdata();
    }

    // Page content
    the_content();
}

// Finally, reset the main query
wp_reset_postdata();

Hope this sums it up 🙂

Leave a Comment