At the heart of the WordPress theme template is the venerable WordPress loop. When you’re looking at your
index.php
file, for example, the loop is the part that typically begins withif(have_posts())
and contains all the tags and markup used to generate the page. The default loop works perfectly well for most single-loop themes, but for more advanced designs with stuff like multiple and custom loops, more looping power is needed. Fortunately, WordPress provides plenty of flexibility with four ways to loop:
Each of these looping methods is useful in a variety of situations. They share a lot of the same underlying functionality, and the query parameters are essentially the same. Collectively, these four techniques enable simple loops, multiple loops, and custom loops in your WordPress theme template. A good place to find a default loop, for example, is in your theme’s
index.php
file. Its purpose is to loop through the posts stored in the database and echo their contents to the browser. Using WordPress’ template tags, it’s easy to display post titles, content, meta info, and much more. That said, let’s examine the four ways to loop with WordPress.The Default Loop
The default WordPress loop looks something like this:
<?php if (have_posts()) : while (have_posts()) : the_post(); ?> <div <?php post_class(); ?> id="post-<?php the_ID(); ?>"> <h1></h1> <?php the_content(); ?> </div> <?php endwhile; ?> <div class="navigation"> <div class="next-posts"><?php next_posts_link(); ?></div> <div class="prev-posts"><?php previous_posts_link(); ?></div> </div> <?php else : ?> <div <?php post_class(); ?> id="post-<?php the_ID(); ?>"> <h1>Not Found</h1> </div> <?php endif; ?>So what makes it “default”? Mostly because it uses the default query to loop through post content, making it the loop used like 99% of the time for most themes. It tells WordPress to loop through posts and display the information according to context, and as called by the various template tags (
the_title
,the_content
, et al). There are tags available for just about any type of data stored in the database.Based on the query that is sent, the default loop will display a certain number of posts from a certain category from a certain date, and so on. For example, the number of posts displayed in the first part of the loop is specified in the WP Admin. So if someone requests the second page of your “Awesome” category, that information is sent via the query, along with the number of posts, theme template file, and so on.
So the default loop is perfect if you’re happy with the query that is sent, but it is also possible to customize the query and generate an entirely different set of posts.
Loop with query_posts()
The query_posts function enables us to modify the query and display our desired results. We can either override the entire query or keep it around and just change a few parameters. Here’s an example where
query_posts
is called before the default loop to exclude a specific category:<?php global $query_string; // required $posts = query_posts($query_string.'&cat=-9'); // exclude category 9 <?php // DEFAULT LOOP GOES HERE ?> <?php wp_reset_query(); // reset the query ?>Say you have a default loop in your
index.php
theme template, but you want to change the number of posts, exclude two categories, and display the results in ascending order. Easy. Just add somequery_posts
action before the default loop andwp_reset_query
immediately after, like this:<?php global $query_string; // required $posts = query_posts($query_string.'&posts_per_page=3&cat=-6,-9&order=ASC'); <?php // DEFAULT LOOP GOES HERE ?> <?php wp_reset_query(); // reset the query ?>Here we are keeping the original query around and just overriding a few parameters. There are many parameters available, so customizing any default loop is accomplished quite easily. If we wanted to completely override the original query, we would replace the second line with something like this:
$posts = query_posts('posts_per_page=3&cat=-6,-9&order=ASC');
Notice here that we’ve removed the
$query_string
from thequery_posts
parameters. This essentially erases the default query and replaces it with one that contains only those variables included inquery_posts
. This means no paging information will be available, so remove the original query only if you know what you’re doing.When to use? Use
query_posts
to modify the type of posts that are returned for a single loop. It’s perfect for limiting the number of posts, excluding posts from a certain category or tag, and so on. If more than one loop is required, multiplequery_posts
loops could work, but there is a much better way to do it usingWP_Query
.Loop with WP_Query()
For complete control over the customization of any number of loops, WP_Query is the way to go. When used to modify a default loop, it looks similar to
query_posts
. For example, let’s exclude a specific category usingWP_Query
:<?php $custom_query = new WP_Query('cat=-9'); // exclude category 9 while($custom_query->have_posts()) : $custom_query->the_post(); ?> <div <?php post_class(); ?> id="post-<?php the_ID(); ?>"> <h1></h1> <?php the_content(); ?> </div> <?php endwhile; ?> <?php wp_reset_postdata(); // reset the query ?>It also accepts the same parameters as
query_posts
, so modifying stuff like number of posts, included/excluded categories, and post order looks quite familiar. As seen in the following examples,WP_Query
makes it easy to customize the loop by simply changing the parameter:$custom_query = new WP_Query('cat=-7,-8,-9'); // exclude any categories $custom_query = new WP_Query('posts_per_page=3'); // limit number of posts $custom_query = new WP_Query('order=ASC'); // reverse the post orderAs expected, we can combine parameters with
WP_Query
using the same syntax as bothquery_posts
andget_posts
. Here’s the equivalent of ourquery_posts
example:
$custom_query = new WP_Query('posts_per_page=3&cat=-6,-9&order=ASC');
Notice, however, that with
WP_Query
, we don’t need the$query_string
variable. In addition to usingWP_Query
to customize the default loop, we can also use it to create and customize multiple loops. Here is a basic example:<?php // Loop 1 $first_query = new WP_Query('cat=-1'); // exclude category while($first_query->have_posts()) : $first_query->the_post(); ... endwhile; wp_reset_postdata(); // Loop 2 $second_query = new WP_Query('cat=-2'); // exclude category while($second_query->have_posts()) : $second_query->the_post(); ... endwhile; wp_reset_postdata(); // Loop 3 $third_query = new WP_Query('cat=-3'); // exclude category while($third_query->have_posts()) : $third_query->the_post(); ... endwhile; wp_reset_postdata(); ?>Each of these additional loops may be placed anywhere in your theme template – no need to line them up sequentially. For example, one loop may be placed in your sidebar, another in your footer, and so on. And with the output of each loop easily modified using any of the available parameters, any loop configuration is possible.
When to use? Use
WP_Query
for creating multiple, customized loops. By setting up additional instances ofWP_Query
in your theme, you can create any number of multiple loops, and customize the output of each.Even so, we don’t always need to break out the big guns, sometimes we just need a few additional loops displayed around the page. So let’s put down the bazookas and gather in the garden for some
get_posts
tea ;)Loop with get_posts()
The easiest, safest way to create multiple loops in your theme is to use get_posts(). Anywhere you need to display a quick, static set of posts,
get_posts
is the perfect choice. Think 10 recent posts in the sidebar, or 10 random posts in the footer.get_posts
makes it easy. Here again is a query to exclude a specific category:<?php global $post; // required $args = array('category' => -9); // exclude category 9 $custom_posts = get_posts($args); foreach($custom_posts as $post) : setup_postdata($post); ... endforeach; ?>This code creates a loop of all posts except those in the excluded category. Of course, excluding a category is just one way to customize your additional, static loops. By using any of the same parameters accepted by
WP_Query
andquery_posts
, it’s possible to create loops that display just about anything you want.Notice, however, that
get_posts
requires the use of an array for the parameters. The format for multiple parameters looks like this (using our previous example):
$args = array('numberposts'=>3, 'category'=>-6,-9, 'order'=>'ASC');
Also notice that we’re using
numberposts
instead ofposts_per_page
to limit the number of posts. According to the WP Codex,posts_per_page
should work withget_posts
, but if it doesn’t just go withnumberposts
. There is also ashowposts
parameter that also seems to work fine withget_posts
.When to use? Use the
get_posts()
function to easily create additional, static loops anywhere in your theme.get_posts
accepts the same parameters asquery_posts
, and is perfect for adding static, custom loops to your sidebar, footer, or anywhere else.30-Second Summary
The bottom line for customizing default loops and creating multiple loops:
- To modify the default loop, use
query_posts()
- To modify loops and/or create multiple loops, use
WP_Query()
- To create static, additional loops, use
get_posts()
If you’re working with WordPress loops and want to learn more about using them to customize your theme, we cover the topic extensively in our book, Digging into WordPress, which is current with WordPress 3.1 :)
Possibly Related Posts
Working with the Wordpress "Loop"