A Better Way to Loop in WordPress 3

Posted by: Mike Girouard on 08/23/2010

A core concept of WordPress development is understanding how The Loop works and how to juggle multiple loops on a single page. To make things easier, WordPress ships with several helper functions to access and render components of individual posts; for example the_title() and the_excerpt(). In order for these functions to work, you need to initialize the global variables which these helpers rely by calling setup_postdata() and pass in the post which you are trying to set up.

One of the problems with this approach is that each of these functions rely on several global variables to keep track of everything. When setup_postdata() is called, most of those variables are clobbered in favor of the new post data. If you wish to refer back to the some data in the original post, chances are you’ll simply be pulling in data from the last post rendered on the screen.

The get_posts() codex page offers some sample code which works around this limitation:

<ul>
    <?php
        global $post;
        $tmp_post = $post;
        $myposts = get_posts('numberposts=5&offset=1&category=1');
        foreach($myposts as $post) :
            setup_postdata($post);
    ?>
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
    <?php endforeach; ?>
    <?php $post = $tmp_post; ?>
</ul>

Although it’s an obvious hack, it works. After looping over every other post in $myposts, the original post data is restored so other plugins and core WordPress functions will behave normally.

If you’re a WordPress 3 user (which I seriously hope you are), you don’t need to deal with that mess. Simply call wp_reset_postdata() and call it a day. Just like the code above, wp_reset_postada() simply rewrites the global $post with the original post in $wp_query. You can find the details inside of wp-includes/query.php:

/**
 * After looping through a separate query, this function restores
 * the $post global to the current post in the main query
 *
 * @since 3.0.0
 * @uses $wp_query
 */
function wp_reset_postdata() {
	global $wp_query;
	if ( !empty($wp_query->post) ) {
		$GLOBALS['post'] = $wp_query->post;
		setup_postdata($wp_query->post);
	}
}

Share this post


About Mike Girouard

Mike Girouard

Mike Girouard is a web enthusiast based in NYC. He is a active presenter at conferences and user groups, and leads the development of several open source side projects. When he has time, he enjoys getting outside and doing non-nerdy things. Mike can be found on Twitter at @mgirouard and even keeps an infrequently updated blog at lovemikeg.com.

More About Mike »

NFJS, the Magazine

May Issue Now Available
  • Client-Side MVC with Spine.js, Part 1

    by Craig Walls
  • On Prototypal Inheritance, Part 2

    by Raju Gandhi
  • Making use of Scala Lazy Collections

    by Venkat Subramaniam
  • Integration Testing Web Applications Using Gradle

    by Kenneth Kousen
Learn More »