WP_Query is the heart of WordPress. It gives you a lot of control over the website content as well as holding important informations for debugging. It makes building complicated queries a lot easier by passing criteria as an associative array. Understanding
WP_Query is a must for theme developers.
Every request made to wordpress goes through the
index.php file which sets up the database connection and load other files needed for wordpress to work. Then wordpress gets the query parameters from the URL, the wordpress itself and plugins. After the query parameters have been set and passed to
WP_Query, WordPress decides which template file to use and this decision based on the query parameters and template files available in the current active theme.
Now wordpress loaded one of our template files and will go through the loop. Let’s explore how the loop appear in the template.
if ( have_posts() ) : // Start the Loop. while ( have_posts() ) : the_post(); /* * Include the post format-specific template for the content. */ get_template_part( 'content', get_post_format() ); endwhile; // add stuff here like post navigation. else : // If no content, include the "No posts found" template. get_template_part( 'content', 'none' ); endif;
As you can see:
have_posts(): Checks if posts found to render.
the_post(): Sets the post data to be accessed later through template tags, the
$postglobal variable and moves to the next post.
get_template_part(): Loads another file in the theme to be used to show the post data.
Sometimes we need to modify the default query to exclude posts, exclude categories…etc. Also we may need to run multiple loops. Sometimes theme developers create another loop to get related posts. anyway to customize the query, you can use the following methods:
This function modifies the main query so use with caution. If you like to set up a new query, use the next methods as they are more efficient. Imagine you like to hard code posts per page and ignore the value that admin placed in dashboard.
$args = array( 'posts_per_page' => '10' ); query_posts($args); if ( have_posts() ) : // Start the Loop. while ( have_posts() ) : the_post(); //do stuff endwhile; // add stuff here like post navigation. else : // No posts found endif;
If you like to explore many query parameters, you can check
wp-includes/query.php to get the complete list.
This function returns an array of posts according to passed query parameters. You can then loop through the result in another way different from normal template tags. Imagine that we need to show some of the posts that belong to current post author. This code should be placed in
single.php file inside the loop.
$cats = get_the_category($post->ID); $cat_ids = array(); //loop through categories and store in an array foreach ($cats as $cat): $cat_ids = $cat->term_id; endforeach; //set up the query parameters $args = array( 'author' => $post->post_author, 'post_type' => 'post', 'category__in' => $cat_ids, 'post__not_in' => array($post->ID), ); //retrieve posts related to author $author_related_posts = get_posts( $args ); if(!empty($author_related_posts)): ?> <div class='author-related-posts'> <ul> <?php foreach ($author_related_posts as $author_related_post): ?> <li><a href="<?php echo esc_url(get_permalink($author_related_post->ID)); ?>"><?php echo $author_related_post->post_title; ?></a></li> <?php endforeach; ?> </ul> </div> <?php endif;
You may noticed that i excluded current post id from retrieved posts.
Another method is to create a new instance of
WP_Query class. It is similar to
get_posts() except that you need to call template tags as methods of the new instance. Also you should reset query to default by using
wp_reset_postdata(). Let’s build the previous query with this method. This code should also be placed in
single.php file inside the loop.
//get categories of current post $cats = get_the_category($post->ID); $cat_ids = array(); //loop through categories and store in an array foreach ($cats as $cat): $cat_ids = $cat->term_id; endforeach; //set up the query parameters $args = array( 'author' => $post->post_author, 'post_type' => 'post', 'category__in' => $cat_ids, 'post__not_in' => array($post->ID), ); $author_related_posts = new WP_Query( $args ); if($author_related_posts->have_posts()): ?> <div class="author-related-posts"> <ul> <?php while ($author_related_posts->have_posts()): $author_related_posts->the_post(); the_title( '<li><a href="' . esc_url( get_permalink() ) . '">', '</a></li>' ); endwhile; ?> </ul> </div> <?php endif; //reset to default post data wp_reset_postdata();