Home > Article > Backend Development > Mastering WP_Query: Harnessing the Power of the Loop
As I outlined in the introduction to this series, the WP_Query
class has four main elements:
In this tutorial, I'll show you how to use loops with WP_Query
, including the two main ways to build loops and how to use multiple loops.
Without the loop, nothing will be displayed on the page. After WordPress runs a query with the parameters you define, you need to tell it what to output from the data it gets. This is where the loop comes in.
So the loop appears after the query, which uses three labels:
if( $query->have_posts() )
Check if there are any posts. It does this by checking whether the value of the query's post_count
attribute is less than the value of current_post 1
. while( $query->have_posts() ) As long as there are posts to retrieve,
the loop will be repeated for each post. As you can see, this have_posts()
method is the same method we called earlier to check if there are posts. Keep in mind that this method does not increment the post counter. It just lets us know if there are any posts in the loop or if we are at the end of the loop. It also automatically rewinds the loop once it reaches the end. $query->the_post()
Access this specific post. It also performs a few other operations, such as retrieving the next post, and incrementing the post counter. It also sets up global publishing data for our use. The have_posts()
method should not be called when you are inside a loop. This is because have_posts()
will rewind the loop back to the beginning and you will end up in an infinite loop.
Now, this is where the loop is in the WP_Query
class:
<?php $args = array( // Arguments for your query. ); // Custom query. $query = new WP_Query( $args ); // Check that we have query results. if ( $query->have_posts() ) { // Start looping over the query results. while ( $query->have_posts() ) { $query->the_post(); // Contents of the queried post results go here. } } // Restore original post data. wp_reset_postdata(); ?>
After running the loop, all that's left to do is tidy up using wp_reset_postdata()
.
The way the loop is structured depends on the data you want to display from the post. Below is an example loop that outputs the post title, featured image, and excerpt. You can use a loop like this on archive pages.
<?php $args = array( // Arguments for your query. ); // Custom query. $query = new WP_Query( $args ); // Check that we have query results. if ( $query->have_posts() ) { // Start looping over the query results. while ( $query->have_posts() ) { $query->the_post(); ?> <article id="post-<?php the_ID(); ?>" <?php post_class( 'left' ); ?>> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php post_thumbnail( 'thumbnail' );?> </a> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php the_title(); ?> </a> <?php the_excerpt(); ?> </article> <?php } } // Restore original post data. wp_reset_postdata(); ?>
This loop displays exactly what I described above: the featured image, title, and excerpt.
But sometimes you may want to add a title before the list of posts, or you may want to include them all in a containing element. If you just add this before the loop, it will output regardless of whether the query actually returns any data, which means you might have a header with nothing underneath it, or some unnecessary markup.
This problem can be easily solved by putting the enclosing element or title into a if
tag:
<?php $args = array( // Arguments for your query. ); // Custom query. $query = new WP_Query( $args ); // Check that we have query results. if ( $query->have_posts() ) { echo '<section class="clear">'; echo '<h2>' . __( 'Heading', 'tutsplus' ) . '</h2>'; // Start looping over the query results. while ( $query->have_posts() ) { $query->the_post(); ?> <article id="post-<?php the_ID(); ?>" <?php post_class( 'left' ); ?>> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php post_thumbnail( 'thumbnail' );?> </a> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php the_title(); ?> </a> <?php the_excerpt(); ?> </article> <?php } echo '</section>'; } // Restore original post data. wp_reset_postdata(); ?>
Here you can see that I've checked if my query retrieved any posts, and if so, I've opened a containing element and added a title.
This is also useful if you want to output the query results as a list. Let's say I want to create a list of all posts in a given category. The ul
element is not inside my loop because it is not related to a specific post, but I only want to output it if there is a post. So I use this:
<?php $args = array( 'category_name' => 'category-slug', 'post_type' => 'post' ); // Custom query. $query = new WP_Query( $args ); // Check that we have query results. if ( $query->have_posts() ) { echo '<ul class="category posts">'; // Start looping over the query results. while ( $query->have_posts() ) { $query->the_post(); ?> <li <?php post_class( 'left' ); ?>> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php the_title(); ?> </a> </li> <?php } echo '</ul>'; } // Restore original post data. wp_reset_postdata(); ?>
This checks if the query has fetched any posts, and if so, opens the ul
element and then runs the loop.
It is important to note that while you can run multiple loops using WP_Query
, you must reset the post data and start a second instance of WP_Query
in order to do this. This is because each loop will output data based on different parameters.
This example shows an excerpt and featured image from the first article, then only the title of each subsequent article:
<?php // First query arguments. $args1 = array( 'post_type' => 'post', 'posts_per_page' => '1' ); // First custom query. $query1 = new WP_Query( $args1 ); // Check that we have query results. if ( $query1->have_posts() ) { // Start looping over the query results. while ( $query1->have_posts() ) { $query1->the_post(); ?> <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php post_thumbnail( 'thumbnail' );?> </a> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php the_title(); ?> </a> <?php the_excerpt(); ?> </article> <?php } } // Restore original post data. wp_reset_postdata(); // Second query arguments. $args2 = array( 'offset' => '1', 'post_type' => 'post' ); // Second custom query. $query2 = new WP_Query( $args2 ); // Check that we have query results. if ( $query2->have_posts() ) { echo '<ul class="more-posts">'; // Start looping over the query results. while ( $query2->have_posts() ) { $query2->the_post(); ?> <li <?php post_class(); ?>> <a href="<?php the_permalink(); ?>" title="<?php the_title_attribute(); ?>"> <?php the_title(); ?> </a> </li> <?php } echo '</ul>'; } // Restore original post data. wp_reset_postdata(); ?>
I used two key parameters here:
'posts_per_page' => '1'
, used with the first query, only outputs the latest posts. 'offset' = '1'
, used with the second query, skips the first post, ensuring it is not repeated in the list below. As you can see from the above code, the loop for each query is slightly different. The first outputs the featured image, title, and excerpt, while the second checks if the query has posts, and if so, opens the ul
element and wraps each post title in li
Links to elements and their pages.
You will also notice that I used wp_reset_postdata()
after both loops. If I didn't do this, using the template tag outside the secondary loop would give me data about the last post inside the loop. Calling this function resets the publication data to the main query.
You can call a number of functions within a loop to access information about the current post. You've also seen some of them used in this tutorial. In this section, I'll give you a list of some common features that you might use occasionally.
You can use three functions to get the title of a post. They are the_title()
, get_the_title()
and the_title_attribute()
. The get_the_title()
function simply retrieves the post title, while the_title()
will display or retrieve the title along with optional tags based on the arguments passed. When you want to clean the title before displaying it, you should use the_title_attribute()
.
There is a dedicated function called the_excerpt()
to display an excerpt of the current post. It applies multiple filters to the provided excerpt so that it can be displayed correctly to the audience. Not every article will have an excerpt provided by the author. In this case, it generates a condensed version of the full post excerpt before displaying it.
You can use the function the_content()
to display the complete content of the post.
Your WordPress posts will usually have some tags or categories that you assign. You can display a list of these tags and categories in a loop using the the_tags()
and the_category()
functions. Use the the_author()
function to display the author of a post. The post's ID can also be accessed via the function the_ID()
.
There are dedicated functions in WordPress that you can use in a loop to display the date (the_date()
) and time (the_time()
) of a post. Two important points you should remember are that the_time()
can also be used to display only the date a post was published. Additionally, the output of the_date()
is only echoed once for multiple posts published on the same day. This basically means that you almost always want to use the_time()
for greater flexibility and ease of use.
Without the loop, WP_Query
doesn't really do much. This loop is the code you use to display the data that WordPress fetches from the database based on your query parameters.
As I demonstrated, there are some changes to the loop. A simple loop will output all posts in the order you specify in the query parameters (or by date descending by default). If you separate if( $query->have_posts() )
and while( $query->have_posts() )
you can insert extra markup outside the loop, but only if Your query has returned data. Finally, you can use WP_Query
multiple times to create multiple loops on the page by specifying substitution parameters and using wp_reset_postdata()
after each loop.
This article has been updated with a contribution from Nitish Kumar. Nitish is a web developer with experience in creating e-commerce websites on various platforms. He spends his free time working on personal projects to make his daily life easier, or going for walks with friends in the evenings.
The above is the detailed content of Mastering WP_Query: Harnessing the Power of the Loop. For more information, please follow other related articles on the PHP Chinese website!