Introduction to ‘The Loop’

Sooner or later it had to come the moment of talking about the WordPress loop. The Loop is one of the core functions in WordPress, probably the function that makes WordPress so different compared to any other CMS.

The Loop displays posts, pages and custom posts. You simply cannot write code for WordPress if you don’t understand how to use the Loop.

In order to show how a typical Loop looks like I’ve taken the file single.php of my _S theme. This is the simplest version of the Loop that you’ll ever see

<?php while ( have_posts() ) : the_post(); ?>

<?php get_template_part( 'content', 'single' ); ?>

<?php giulio_post_nav(); ?>

<?php
// If comments are open or we have at least one comment, load up the comment template
if ( comments_open() || '0' != get_comments_number() ) :
comments_template();
endif;
?>

<?php endwhile; // end of the loop. ?>

This piece of code is incredibly simple, yet many people struggle to fully understand it. But don’t worry; when we’ll go deeply in analyzing the Loop, it’s going to become much more complicated. I must also say that this is not the entire Loop. In fact, the most important part lies in the template part content-single.php which is called from the line 3 but that will be the subject of another post.

Right now, what is of interest to us is the first line, and here I will concentrate my analysis. That line basically starts a loop (hence the name ‘The Loop’), go through all the posts, and publishes them (the file content-single.php called in the next line takes care of the publishing). Since this is the single post template, it won’t show all the posts but only one post.

Now, what is strange in this loop is that have_posts() is not a variable but a function. However, it must be of course a function that returns some value. Here it is how that function is made. If you want to look at it you can find it in wp-includes/query.php.


/**
* Whether current WordPress query has results to loop over.
*
* @see WP_Query::have_posts()
* @since 1.5.0
* @uses $wp_query
*
* @return bool
*/
function have_posts() {
global $wp_query;

return $wp_query->have_posts();
}

It looks pretty easy. Our have_posts() is a wrapper function that calls another function with the same name which is a method of the object $wp_query. WordPress is full of wrapper functions, they are used everywhere. What they do is just to simplify a more complex call, like have_posts() does.

Another wrapper function is the_post()


/**
* Iterate the post index in the loop.
*
* @see WP_Query::the_post()
* @since 1.5.0
* @uses $wp_query
*/
function the_post() {
global $wp_query;

$wp_query->the_post();
}

At this point, to see what really happens behind the scenes we must look inside the class WP_Query which is defined in the same file as the previous wrapper functions. So, this is WP_Query::have_post()


/**
* Whether there are more posts available in the loop.
*
* Calls action 'loop_end', when the loop is complete.
*
* @since 1.5.0
* @access public
* @uses do_action_ref_array() Calls 'loop_end' if loop is ended
*
* @return bool True if posts are available, false if end of loop.
*/
function have_posts() {
if ( $this->current_post + 1 < $this->post_count ) {
return true;
} elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
do_action_ref_array('loop_end', array(&$this));
// Do some cleaning up after the loop
$this->rewind_posts();
}

$this->in_the_loop = false;
return false;
}

The function’s only scope is to determine if there are still posts, and return a boolean that reflect it. In case there are no more posts the the function returns false to end the loop, and it ‘rewind_posts()’. This beautiful tape metaphor gives exactly the idea of what is going on. Like in the old time when you listened to a tape you had to rewind it to listen to it again, here we rewind the posts so that we can go through them again in some other template inside our theme.

What the function the_post() does is to call the function setup_postdata() which compiles a list of variables. These variables contain the next post and all data related to it, like author, date etc. It’s up to us then to decide which of these data to use and how.


/**
* Sets up the current post.
*
* Retrieves the next post, sets up the post, sets the 'in the loop'
* property to true.
*
* @since 1.5.0
* @access public
* @uses $post
* @uses do_action_ref_array() Calls 'loop_start' if loop has just started
*/
function the_post() {
global $post;
$this->in_the_loop = true;

if ( $this->current_post == -1 ) // loop has just started
do_action_ref_array('loop_start', array(&$this));

$post = $this->next_post();
setup_postdata($post);
}

I’ve just scratched the surface of the Loop. This ‘function that calls another function which again calls another function’ is a pretty common behavior in WordPress. It’s like a set of matrioskas where you have the impression to never get to the end, and it’s pretty confusing for a newbie that wants to understand how it works.

Since this is not a course but just a personal blog I don’t have a plan on what to write next. Maybe another article about the Loop or maybe something else that I find interesting. If you like what I write, stay tuned.


So, what do you think ?