How to properly reset a nested WP_Query query

I'm missing something here. What's the proper way to reset a query so that it doesn't interfere with any other queries it may be nested in?

This is the kind of result I'm going for:

Main page

This is the main page content. Now let's display some custom nested queries.

Outer page 1

 Inner post 1
 Inner post 2

Outer page 1 content continued...

Outer page 2

 Inner post 1
 Inner post 2

Outer Page 2 content continued...

...etc.

But I can't get the Outer Page X content continued part working—it always reverts to either the inner query or the main page query.

Here's my page template. It's commented with the behavior I get with each of the reset functions (wp_reset_postdata(), wp_reset_query(), $query-reset_query(), and $query-reset_postdata()).

// BEGIN PAGE TEMPLATE 

while ( have_posts() ) : the_post();

    the_title(); // "Main page"

    /* --------- OUTER QUERY --------- */
    $outer_query = new WP_Query( [ 'post_type' = 'page' ] );

    if ($outer_query-have_posts()) : 
        while ($outer_query-have_posts()) : $outer_query-the_post();
            the_title(); // "Outer page 1", "Outer page 2", etc.

                /* --------- INNER QUERY --------- */
                $inner_query = new WP_Query( [ 'post_type' = 'post', 'posts_per_page' = 2 ] ); 

                if ($inner_query-have_posts()) :
                    while ($inner_query-have_posts()) : $inner_query-the_post();
                        the_title();
                    endwhile;
                endif;

            /**
             * Now I'm done with the inner query.
             * How do I get back to the outer query?
             * 
             * Desired value of the_title(): 
             *   "Outer page 1" on first iteration, "Outer page 2" on second, etc.
             */

            // wp_reset_postdata();            // Nope! Results in "Main page"
            // wp_reset_query();               // Nope! Results in "Main page" 
            // $inner_query-reset_postdata(); // Nope! Results in "Inner post 1"
            // $inner_query-reset_query();    // Nope! Results in "Inner post 2"
            // If no reset is used:            // Nope! Results in "Inner post 2"
            the_title();

        endwhile;
    endif;
    wp_reset_postdata();

    // Now back to the main page
    the_title(); // Works

endwhile;

// END OF PAGE TEMPLATE

What's the proper way to do this? I'm looking for a generalizable answer that doesn't rely on knowing how many levels deep the query is, or the context in which it's being used. i.e., something that could be extracted into a shortcode.

Topic wp-query Wordpress

Category Web


This touches upon an answer provided here Loop within a loop? except I posted the full code:

$query = new WP_Query($args);

while ($query->have_posts()) :

    // initialization for $inner_args & backup the current global $post
    global $post;
    $backup = $post; 
    $inner_query = new WP_Query($inner_args);

    while ($inner_query->have_posts()) :
        // do something
    endwhile;
    $inner_query->reset_postdata();
    // restore the global $post from the previously created backup
    $post = $backup;

endwhile;
$query->reset_postdata();

The important thing here is you are setting the current post as a backup, because when the inner nested WP_Query postdata is set up, the prior loop's is lost. After the inner query finishes looping, you can set the post back to your backup and continue in the "parent" loop.

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.