I was faced with a problem while creating a WordPress theme the other day. I was grouping posts together using a 2.8 custom taxonomy (which is my new favorite thing in WordPress), and wanted to display a list of all related posts above the Comments template. Basically wanted a small Loop inside of the main Loop – a loop within a loop.
I found a few pages online which address this, such as WordPress Loop Inside of a Loop and Calling a WordPress Loop from inside a WordPress Loop. The idea is pretty simple, and these techniques work fine most of the time.
Everything looked fine to me, as well, until I hit “Submit Comment” to test it… and the comment appeared on the wrong post.
The problem is that inner loop sets the global $post object to the last item in that loop. The methods the_post() and setup_postdata($post) set up the global variables which are needed by the_permalink(), the_title(), comments_template(), etc. So if you call any of these usual “Loop” methods again AFTER the inner loop, they are operating on the last post in the inner loop instead of the current post in the main loop.
The trick is to save the $post objects before the inner loop and to reset them again after the inner loop. To do this, change the Loop structure to follow this template:
$posts = get_posts($wp_query->query); //get the posts foreach($posts as $post) : // cycle through them in the main loop $currentPost = $post; // save the current "main loop" post setup_postdata($post); // instantiate the global post variables to the main loop post the_title(); // use your usual Loop methods the_content(); $innerposts = get_posts('order=asc&mytaxonomy=mycustomerterm); //get the posts from my custom taxonomy foreach($innerposts as $post) : // cycle through them in the main loop setup_postdata($post); // instantiate the global post variables to the inner loop post the_title(); // the inner loop post's title endforeach; // end of inner loop $post = $currentPost; // reset the post from the main loop $id = $post->ID; // reset the post from the main loop comments_template(); // now, the comments for the post in the main loop endforeach; // end of main loop
Another way to do this might be to NOT set the global variables in the inner loop, thus avoiding this issue with the comments entirely. You would just have to directly access the post variables in the inner loop, i.e. $rel_post→post_title instead of the_title(). It would work for simple things, like the title and slug. Check out custom select querySelectQuery in the WordPress Codex to figure out how to get all of the fields you need from the DB to use this method.