close

Day 11: The WordPress Loop

Another post about the WordPress Loop! I can hear the sighs already. But bare with me, just for a few minutes, because my Xmas present to you all this year is a bit of an alternative look at how the Loop works and what is actually going on when we write these simple few lines of code:

if( have_posts() ): while( have_posts() ): the_post();

endwhile; endif;

The meat of the Loop

To get started I’m going to actually ignore most of the code above and look at just 2 part of it:

  • have_posts, and
  • the_post

The rest of ‘the Loop’ is quite simply a straight forward PHP if statement and while loop, things you wouldn’t bat an eyelid at should you see them in any other form, so let’s ignore them for now, and see what is actually going on with the two functions I’ve pulled out.

My favourite part about WordPress is that it is mostly built around straight forward PHP code, none of these custom template tags with their own special syntax. In WordPress an if statement is an if statement and a function is a function. And the majority of things in WordPress theme development that you are going to use, are functions.

have_posts()

have_posts is the first of the two functions in the loop that we’ll look at, and you’ll notice that it comes up twice as well. The function of have_posts is actually pretty self-explanatory, it checks to see whether there are posts available to output and if so, returns true and if not, returns false. Simple.

There is a little more to it though, when it finds that there are no more posts to display it will return false and then call rewind_posts() so that WordPress is ready to set up another loop should it need to.

the_post

This is the function that does all the hard work to be honest, when you call the_post() it goes through the current post data in the posts array (more on that later) and uses it to set up all of the template tags and conditional tags so you can start crafting your templates. It also moves the posts counter on ready to access the next post when the_post is called again (i.e. in the next iteration of the while loop).

Getting data into the Loop

So now you know what the main code of the Loop is doing, lets look at how the Loop gets it’s data. Here’s an overview of the process WordPress goes through when it loads up each page of the site:

Get query parameters

The query parameters are based on two main things: the settings in WordPress, and the page GET/PATHINFO data. The page GET/PATHINFO data is the information passed in via the URL navigated to. The first thing most people do when they set up WordPress is to change the permalinks to ‘pretty permalinks’ which means, instead of this:

example.com?p=hello-world

you get

example.com/hello-world

But if we go back and take a look at the default permalinks you’ll see that the url created is actually the GET parameters needed for the query, we’ll look at these in a bit more depth when we look at editing the Loop with queries.

So once you have the query parameters, let’s look at what’s next:

Decide on template file

After the query parameters have been set, WordPress can then look for what template file to use. The decision is based on what type of query is going to be run and what the available templates are in the current theme. WordPress looks at the available templates and will select the template file based on the template hierarchy, eventually defaulting to the index.php should it not find anything else more appropriate.

Run query

After all this goes on, WordPress finally builds and runs the query on the database. The data retrieved from that goes in to the $wp_query global variable which is then in tern used in the Loop by the have_posts and the_post functions we’ve already spoken about.

Loop

Finally we get to the actual Loop, now WordPress has all the data it needs, the correct template file and the query data we’re ready to go in the template and build the page.

Modifying the query

Now you know how the loop works and how the data is collected, let’s have a look at modifying the query to create custom pages with the data we want. The ability to manipulate the query like this is one of the more powerful parts of WordPress, we can even run multiple queries and Loops on the same page to create pages made up of a variety of different types of content.

There are actually 4 ways we can manipulate the query in WordPress, these are:

  • Modify the default query,
  • query_posts(),
  • WP_Query(), and
  • get_posts()

The default query

First we have the default query. This is the one I’ve been talking about so far in this post, the query that is made up purely from the settings and page URL. But this section is about modifying the query, so how can we do that if it’s being created automatically? Well the query parameters are also stored in a variable in WordPress which you can get at in your template files, the $query_string variable.

global $query_string;
query_posts( $query_string . "&order=ASC" );
if( have_posts() ): while( have_posts() ): the_post();
    // Do stuff
endwhile; endif;

The above code takes the $query_string variable and using query_posts() (more on that in a second) performs a new query on the database to select the posts with the modified query. We can do this because the $query_string quite literally does exactly what it says on the tin, it’s a string containing the current query that will be run on the database. We create the new query by simply concatenating more query parameters to the end of the default string and then pass that as the argument to query_posts.

Note: You always need to remember to start your additional parameters with an & as we are adding to the current query parameters, think of it as ‘query_string’ & ‘new parameters’.

query_posts

We just took a brief look at query_posts in the previous section but let’s look at it now in a bit more detail. query_posts is a way to manipulate the main query on the current page, this function should only be used for that reason because it overwrites the main $wp_query variable.

Note: you can backup the original query and use query_posts to run a second query on the page but there are better ways of doing multiple queries which we’ll look at in a moment.

So as we’ve seen the query_posts function can take an argument made up of query parameters, it can do it in two ways, with either an array of arguments like this:

$args = array( 
    'cat' => 5, 
    'posts_per_page' => 2, 
    'order' => 'ASC' 
);
query_posts($args);

or in a string as we’ve done before when editing the default query:

$args = "cat=5&posts_per_page=2&order=ASC";
query_posts($args);

A full list of the parameters available can be found in the WordPress codex WP_Query reference.

WP_Query

To create multiple loops on a page separate to the default query your best off using WP_Query, this is the main WordPress class for handling the query and Loop in WordPress. The way to use it to create a new instance of the class in our template and pass the result into a variable for us to use in our new loop. Here’s what this would look like:

$new_query = new WP_Query( $args );

if( $new_query->have_posts() ): while( $new_query->have_posts() ): $new_query->the_post();
    // Do stuff - with normal template tags
endwhile; endif;

wp_reset_query();   
wp_reset_postdata();

Here we create a variable $new_query which receives the instance of the WP_Query class, called with arguments in the same way that we did with query_posts previously. Next we set up our loop but instead of calling have_posts and the_post() functions as normal, we need to call them as methods from the new instance of the class we created $new_query->have_posts(). This then gives us use of the same template and conditional tags we’ve used before in a regular loop.

After we close the loop as normal there’s a little bit of cleaning up we need to do, this is done by calling the functions wp_reset_query and wp_reset_postdata to reset the original query and postdata respectively.

If we wanted to use multiple queries on the same page we could just create new instances of WP_Query within the same template just making sure we call wp_reset_query() and wp_reset_postdata() after each one and we’ll be fine, like so:

$new_query1 = new WP_Query( $args1 );

if( $new_query1->have_posts() ): while( $new_query1->have_posts() ): $new_query1->the_post();
    // Do stuff - with normal template tags
endwhile; endif;

wp_reset_query();   
wp_reset_postdata();

$new_query2 = new WP_Query( $args2 );

if( $new_query2->have_posts() ): while( $new_query2->have_posts() ): $new_query2->the_post();
    // Do stuff - with normal template tags
endwhile; endif;

wp_reset_query();
wp_reset_postdata();

get_posts

The final way of querying in WordPress is by using get_posts. The difference here is that get_posts just returns an array of post objects as the result for you to manipulate. To go through the data this time you need to loop through the result in a slightly different way to the other options:

$new_posts = get_posts( $args );
foreach ( $new_posts as $post ):
    setup_postdata($post);

    // Do stuff - using normal template tags
endforeach;
wp_reset_postdata();

In the above example we’re using a standard foreach loop in PHP to go through the array, the important part is that we use $post as the value argument in the foreach loop. By doing this it allows us to use the setup_postdata function to give us the template tags to use as normal, otherwise we would need to use the raw data returned by the get_posts function like below:

$new_posts = get_posts( $args );
foreach ( $new_posts as $post ):
    echo '<h1>'.$post->post_title.'</h1>';

    echo $post->post_content; // raw
    echo apply_filters('the_content', $post->post_content); // formatted

endforeach;

The raw data is accessed through the post variable itself which is returned from the get_posts query. I’ve also included 2 ways of outputting the content data, the first gets the raw data as you’ve written it into the content editor, so if you leave some of the formatting to WordPress (like p tags etc) then you’ll need to use the apply_filters function to process the content data the same way WordPress does when it sets up the post data as normal.

One more thing to note about get_posts is that although it does take many of the same arguments as the previous 2 query types, there are a few subtle differences. For instance to change the number of posts queried for use numberposts instead of posts_per_page – for a full list of parameters have a look at the codex for get_posts.

Summary

The WordPress Loop is the main way of generating you pages through your template, my hope for this post was to give you a deeper look at how the Loop is working instead of just the regular here’s how to change the loop.

With this knowledge you should be able to gain a better understanding of what WordPress is doing when it builds your page and where the loop sits within that.