How To Use WP_Query In WordPress

Click to share! ⬇️

How To Use WP_Query In WordPress

In this WordPress Tutorial, we will have a look at the WP_Query class, which is really the workhorse of fetching post data from your WordPress database. WP_Query gives theme developers complete control over what is sent into “The Loop” as we call it. By mastering WP_Query, one gains the ability to loop over any posts they like and in any theme file where it is deemed needed. With this knowledge, you can create custom home pages that might display posts from one category in a given section of the page and posts from another category in a different section of a page. There are so many options available to you with WP_Query. Let’s take a look now.


A Loop Refresher

Let’s take another look at the skeleton of the WordPress Loop as it really is the meat and potatoes of WordPress Theme Development.

if ( have_posts() ):
	
	while ( have_posts() ): the_post();
    // output of content inside while loop
	endwhile;

else:
	// no posts message or some other fallback here
endif;

In the snippet above we see the WordPress Loop. Basically, it says, if there are posts, loop over them all and if there are no posts, output a message that indicates this. The magic of the loop really happens in that while loop. Anything within the while loop gets repeated once for each post retrieved by the current query. Inside the while loop, you have complete control over how you will output and format the posts. This means you can include any combination of HTML and PHP required to create the effect you are looking for. You choose which parts of the post to include or exclude such as the title, author, the body, and so on. In some cases, maybe you only want to display the title. In others perhaps the title and excerpt will do. Still yet in other scenarios, you may want to display the title and the full content of each post. You have complete control of this inside that while loop.


Which Posts Are Being Looped Through?

So now that we see how to control the format and output of posts in the while loop, the following question arises. How do we as theme developers control which posts are actually getting looped over? Up until now, we have been at the mercy of what WordPress has decided to loop over. We can now learn how to control this aspect of WordPress.


URL Based Queries

Assuming no custom loop logic has been added to your theme, the default method of how WordPress chooses what posts to loop over is based on the currently active URL or permalink. For example, if you visit http://wordpresstutorial.dev/category/php/, then the posts with a category of PHP are fed into the loop. Therefore, only posts that have a category of PHP should be seen on the page. If we test this out, this is exactly what we see.
wp_query by category

It stands to reason then, that if we visit http://wordpresstutorial.dev/category/javascript/ then the category of JavaScript will be fed into the loop and we should only be working with posts that have a category of JavaScript at that point. Once again, we can visit this url and see that this is in fact the case.
wp_query by category via url

So we can see that WordPress does a great job of using the URL to determine which posts to loop over. We only looked at an example of visiting various category URL’s but this also works for archive pages, author pages, tags, and many more. At some point, however, you will likely want to be able to specify exactly which posts are being looped over in your theme files by controlling the loop yourself, and not relying on which particular URL is currently active. You can certainly do that, and we will look at how now.


A Custom Homepage

A nice way to demonstrate this technique is to set up a custom homepage where we can choose which posts to display. As we know, by default, WordPress is simply going to display the latest posts on our homepage, regardless of any other aspect about that post. It does not matter the category, tag, or author, WordPress just looks for the most recent posts and displays them as such. Now, we have a tutorial-based example blog that has a few categories. It might be nice to display one column with a couple of recent posts from one category, and another with posts from a different category.


Some Initial Legwork

We first need to tell WordPress that we want to use a static page as the homepage. If this is the case, where will we see all of our posts? We can create a new page, which will act as the main index of blog posts. So we will create a page with the name of ‘Homepage’ and another with the name of ‘All Posts’.

Creating the homepage in the WordPress Dashboard.
creating a custom homepage

Creating a page to display all blog posts.
adding a blog listing page to show all posts

Setting the homepage and all posts page in Settings.
wordpress settings reading

Adding a link to All Post in the main menu.
add a link to all posts in main menu

Ok! We have the legwork out of the way. At this point, we should have the custom text we specified for the homepage when we visit the base URL of http://wordpresstutorial.dev/ and it looks like this is working correctly.
wordpress custom home page

Fear not! You can still view all blog posts on your website. All you have to do is visit http://wordpresstutorial.dev/all-posts/ and this is exactly what we see!
all posts via url wordpress

To be fair, our homepage is pretty lacking right now. As it stands now, the page.php file is responsible for rendering the output of our homepage. In fact, we have many pages in this site. Those are About Us, All Posts, Homepage, Services, and WordPress Example Page. All of these are rendered via page.php. We said we want something custom however for the Homepage. How can we do this?


Introducing front-page.php

When you set a specific page to be the home page on your WordPress site as we did in this tutorial, WordPress is going to look for a file in your theme folder named front-page.php to render that particular page. If it is not present, then WordPress simply uses page.php to handle the rendering. So let’s go ahead and create front-page.php in our theme folder now. We’ll just put some simple text in this file to show that it does in fact power the home page.

front-page.php

What's up fool?!  This is the homepage!

front-page-php

So it works! Of course, this is pretty silly and doesn’t add a lot of value, so let’s go ahead and put some markup in the front-page.php file. Our goal will be to simply display the navigation menu and the main content. We don’t really want to display the title of the page since it is simply static content that we are displaying on the homepage.

front-page.php

<?php

get_header();

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

        <article class="page-layout">
            <nav class="child-navigation-menu children-links clearfix">
                <ul>
					<?php $args = [
						'child_of' => get_the_top_ancestor_id(),
						'title_li' => '',
					];
					wp_list_pages( $args ); ?>
                </ul>
            </nav>
			<?php the_content() ?>
        </article>
	
	<?php endwhile;

else :
	echo '<p>There are no pages!</p>';
endif;

get_footer();

?>

Let’s also update the homepage in the WordPress editor so it has some more text using this text: “Hi there! This is the homepage of http://wordpresstutorial.dev! This website is awesome! In the WordPress Dashboard, this is a Page, and it is called ‘Homepage’. Any user can go into this page and edit it with the WordPress Editor to make changes to this static content here. We can provide any information about the site we like, right here on this static homepage. A client may like the ability to edit this text easily with no need to dive into any HTML or PHP to do so. Below this static text, however, we will have dynamically updated data by leveraging WP_Query.”
easily update static content on homepage

Viewing the homepage has a nice effect now, don’t you think? Again, a nontechnical person can now easily update this content with no HTML or PHP editing.
check out that homepage


Introducing WP_Query

Now we need to start the process of fetching custom data from the database using WP_Query(). WP_Query() works by passing in various arguments to it based on what you want to retrieve. Let’s say we want to fetch all posts that are of the category of JavaScript. By reading the Category Parameters for WP_Query() we could do something like this:

<?php
// JavaScript Posts
$javascriptPosts = new WP_Query( [ 'category_name' => 'javascript' ] );

var_dump( $javascriptPosts );

First, we fetch all posts that have a category_name of javascript. Essentially, this is the slug for the JavaScript category. You can also fetch by category ID if you prefer. Next we var_dump out the contents of what is stored in $javascriptPosts so we can examine. Here is that output in our case:

/home/vagrant/Code/wordpresstutorial/wordpress/wp-content/themes/customtheme/front-page.php:6:
object(WP_Query)[538]
  public 'query' => 
    array (size=1)
      'category_name' => string 'javascript' (length=10)
  public 'query_vars' => 
    array (size=64)
      'category_name' => string 'javascript' (length=10)
      'error' => string '' (length=0)
      'm' => string '' (length=0)
      'p' => int 0
      'post_parent' => string '' (length=0)
      'subpost' => string '' (length=0)
      'subpost_id' => string '' (length=0)
      'attachment' => string '' (length=0)
      'attachment_id' => int 0
      'name' => string '' (length=0)
      'static' => string '' (length=0)
      'pagename' => string '' (length=0)
      'page_id' => int 0
      'second' => string '' (length=0)
      'minute' => string '' (length=0)
      'hour' => string '' (length=0)
      'day' => int 0
      'monthnum' => int 0
      'year' => int 0
      'w' => int 0
      'tag' => string '' (length=0)
      'cat' => int 4
      'tag_id' => string '' (length=0)
      'author' => string '' (length=0)
      'author_name' => string '' (length=0)
      'feed' => string '' (length=0)
      'tb' => string '' (length=0)
      'paged' => int 0
      'meta_key' => string '' (length=0)
      'meta_value' => string '' (length=0)
      'preview' => string '' (length=0)
      's' => string '' (length=0)
      'sentence' => string '' (length=0)
      'title' => string '' (length=0)
      'fields' => string '' (length=0)
      'menu_order' => string '' (length=0)
      'embed' => string '' (length=0)
      'category__in' => 
        array (size=0)
          empty
      'category__not_in' => 
        array (size=0)
          empty
      'category__and' => 
        array (size=0)
          empty
      'post__in' => 
        array (size=0)
          empty
      'post__not_in' => 
        array (size=0)
          empty
      'post_name__in' => 
        array (size=0)
          empty
      'tag__in' => 
        array (size=0)
          empty
      'tag__not_in' => 
        array (size=0)
          empty
      'tag__and' => 
        array (size=0)
          empty
      'tag_slug__in' => 
        array (size=0)
          empty
      'tag_slug__and' => 
        array (size=0)
          empty
      'post_parent__in' => 
        array (size=0)
          empty
      'post_parent__not_in' => 
        array (size=0)
          empty
      'author__in' => 
        array (size=0)
          empty
      'author__not_in' => 
        array (size=0)
          empty
      'ignore_sticky_posts' => boolean false
      'suppress_filters' => boolean false
      'cache_results' => boolean true
      'update_post_term_cache' => boolean true
      'lazy_load_term_meta' => boolean true
      'update_post_meta_cache' => boolean true
      'post_type' => string '' (length=0)
      'posts_per_page' => int 10
      'nopaging' => boolean false
      'comments_per_page' => string '50' (length=2)
      'no_found_rows' => boolean false
      'order' => string 'DESC' (length=4)
  public 'tax_query' => 
    object(WP_Tax_Query)[540]
      public 'queries' => 
        array (size=1)
          0 => 
            array (size=5)
              ...
      public 'relation' => string 'AND' (length=3)
      protected 'table_aliases' => 
        array (size=1)
          0 => string 'wp_term_relationships' (length=21)
      public 'queried_terms' => 
        array (size=1)
          'category' => 
            array (size=2)
              ...
      public 'primary_table' => string 'wp_posts' (length=8)
      public 'primary_id_column' => string 'ID' (length=2)
  public 'meta_query' => 
    object(WP_Meta_Query)[539]
      public 'queries' => 
        array (size=0)
          empty
      public 'relation' => null
      public 'meta_table' => null
      public 'meta_id_column' => null
      public 'primary_table' => null
      public 'primary_id_column' => null
      protected 'table_aliases' => 
        array (size=0)
          empty
      protected 'clauses' => 
        array (size=0)
          empty
      protected 'has_or_relation' => boolean false
  public 'date_query' => boolean false
  public 'request' => string 'SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID FROM wp_posts  LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) WHERE 1=1  AND ( 
  wp_term_relationships.term_taxonomy_id IN (4)
) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10' (length=378)
  public 'posts' => 
    array (size=2)
      0 => 
        object(WP_Post)[322]
          public 'ID' => int 90
          public 'post_author' => string '1' (length=1)
          public 'post_date' => string '2017-07-20 16:07:26' (length=19)
          public 'post_date_gmt' => string '2017-07-20 16:07:26' (length=19)
          public 'post_content' => string 'This is an example JavaScript blog post to add to the various example blog posts in this WordPress Tutorial.  We're learning about WordPress, PHP, and JavaScript during this tutorial where we create a WordPress Theme from scratch.  This means we have started with 0 lines of code, and have worked our way up to having a functional theme for our WordPress Installation.  If you like JavaScript, you'll have a great time customizing behaviors on your WordPress website on the front end and admin dashboard.' (length=504)
          public 'post_title' => string 'How To Learn JavaScript' (length=23)
          public 'post_excerpt' => string '' (length=0)
          public 'post_status' => string 'publish' (length=7)
          public 'comment_status' => string 'open' (length=4)
          public 'ping_status' => string 'open' (length=4)
          public 'post_password' => string '' (length=0)
          public 'post_name' => string 'how-to-learn-javascript' (length=23)
          public 'to_ping' => string '' (length=0)
          public 'pinged' => string '' (length=0)
          public 'post_modified' => string '2017-07-20 16:11:04' (length=19)
          public 'post_modified_gmt' => string '2017-07-20 16:11:04' (length=19)
          public 'post_content_filtered' => string '' (length=0)
          public 'post_parent' => int 0
          public 'guid' => string 'http://wordpresstutorial.dev/?p=90' (length=34)
          public 'menu_order' => int 0
          public 'post_type' => string 'post' (length=4)
          public 'post_mime_type' => string '' (length=0)
          public 'comment_count' => string '0' (length=1)
          public 'filter' => string 'raw' (length=3)
      1 => 
        object(WP_Post)[544]
          public 'ID' => int 9
          public 'post_author' => string '1' (length=1)
          public 'post_date' => string '2017-06-13 15:08:46' (length=19)
          public 'post_date_gmt' => string '2017-06-13 15:08:46' (length=19)
          public 'post_content' => string 'This is an example JavaScript blog post to add to the various example blog posts in this WordPress Tutorial.  We're learning about WordPress, PHP, and JavaScript during this tutorial where we create a WordPress Theme from scratch.  This means we have started with 0 lines of code, and have worked our way up to having a functional theme for our WordPress Installation.  If you like JavaScript, you'll have a great time customizing behaviors on your WordPress website on the front end and admin dashboard.' (length=506)
          public 'post_title' => string 'JavaScript Blog Post' (length=20)
          public 'post_excerpt' => string '' (length=0)
          public 'post_status' => string 'publish' (length=7)
          public 'comment_status' => string 'open' (length=4)
          public 'ping_status' => string 'open' (length=4)
          public 'post_password' => string '' (length=0)
          public 'post_name' => string 'javascript-blog-post' (length=20)
          public 'to_ping' => string '' (length=0)
          public 'pinged' => string '' (length=0)
          public 'post_modified' => string '2017-06-29 17:01:39' (length=19)
          public 'post_modified_gmt' => string '2017-06-29 17:01:39' (length=19)
          public 'post_content_filtered' => string '' (length=0)
          public 'post_parent' => int 0
          public 'guid' => string 'http://wordpresstutorial.dev/?p=9' (length=33)
          public 'menu_order' => int 0
          public 'post_type' => string 'post' (length=4)
          public 'post_mime_type' => string '' (length=0)
          public 'comment_count' => string '0' (length=1)
          public 'filter' => string 'raw' (length=3)
  public 'post_count' => int 2
  public 'current_post' => int -1
  public 'in_the_loop' => boolean false
  public 'post' => 
    object(WP_Post)[322]
      public 'ID' => int 90
      public 'post_author' => string '1' (length=1)
      public 'post_date' => string '2017-07-20 16:07:26' (length=19)
      public 'post_date_gmt' => string '2017-07-20 16:07:26' (length=19)
      public 'post_content' => string 'This is an example JavaScript blog post to add to the various example blog posts in this WordPress Tutorial.  We're learning about WordPress, PHP, and JavaScript during this tutorial where we create a WordPress Theme from scratch.  This means we have started with 0 lines of code, and have worked our way up to having a functional theme for our WordPress Installation.  If you like JavaScript, you'll have a great time customizing behaviors on your WordPress website on the front end and admin dashboard.' (length=504)
      public 'post_title' => string 'How To Learn JavaScript' (length=23)
      public 'post_excerpt' => string '' (length=0)
      public 'post_status' => string 'publish' (length=7)
      public 'comment_status' => string 'open' (length=4)
      public 'ping_status' => string 'open' (length=4)
      public 'post_password' => string '' (length=0)
      public 'post_name' => string 'how-to-learn-javascript' (length=23)
      public 'to_ping' => string '' (length=0)
      public 'pinged' => string '' (length=0)
      public 'post_modified' => string '2017-07-20 16:11:04' (length=19)
      public 'post_modified_gmt' => string '2017-07-20 16:11:04' (length=19)
      public 'post_content_filtered' => string '' (length=0)
      public 'post_parent' => int 0
      public 'guid' => string 'http://wordpresstutorial.dev/?p=90' (length=34)
      public 'menu_order' => int 0
      public 'post_type' => string 'post' (length=4)
      public 'post_mime_type' => string '' (length=0)
      public 'comment_count' => string '0' (length=1)
      public 'filter' => string 'raw' (length=3)
  public 'comment_count' => int 0
  public 'current_comment' => int -1
  public 'found_posts' => string '2' (length=1)
  public 'max_num_pages' => float 1
  public 'max_num_comment_pages' => int 0
  public 'is_single' => boolean false
  public 'is_preview' => boolean false
  public 'is_page' => boolean false
  public 'is_archive' => boolean true
  public 'is_date' => boolean false
  public 'is_year' => boolean false
  public 'is_month' => boolean false
  public 'is_day' => boolean false
  public 'is_time' => boolean false
  public 'is_author' => boolean false
  public 'is_category' => boolean true
  public 'is_tag' => boolean false
  public 'is_tax' => boolean false
  public 'is_search' => boolean false
  public 'is_feed' => boolean false
  public 'is_comment_feed' => boolean false
  public 'is_trackback' => boolean false
  public 'is_home' => boolean false
  public 'is_404' => boolean false
  public 'is_embed' => boolean false
  public 'is_paged' => boolean false
  public 'is_admin' => boolean false
  public 'is_attachment' => boolean false
  public 'is_singular' => boolean false
  public 'is_robots' => boolean false
  public 'is_posts_page' => boolean false
  public 'is_post_type_archive' => boolean false
  private 'query_vars_hash' => string 'c7f2d38df04d2e63027c41e3c1f384ad' (length=32)
  private 'query_vars_changed' => boolean false
  public 'thumbnails_cached' => boolean false
  private 'stopwords' => null
  private 'compat_fields' => 
    array (size=2)
      0 => string 'query_vars_hash' (length=15)
      1 => string 'query_vars_changed' (length=18)
  private 'compat_methods' => 
    array (size=2)
      0 => string 'init_query_flags' (length=16)
      1 => string 'parse_tax_query' (length=15)

If you’re quite familiar with PHP, this output makes perfect sense to you. If PHP is not your specialty, this output might look a little bit foreign to you. Not to worry. Basically, what we see here is that we have an Object of type WP_Query. In other words, we instantiated an instance of the WP_Class() and stored it in $javascriptPosts. If this is new to you, be sure to check out our Object Oriented Programming tutorials. We named the variable this way simply to remind us that the posts that are contained in this object have a category of JavaScript. You can name this variable however you like. So let’s see how we might make use of this in our theme files.


So how do we get these custom queries into the Loop?

I’m glad you asked, we will do so right now. Basically, the custom Loops will work the same as the default loop with a few small exceptions. When you make a call to have_posts() and the_post(), you need to do so off of the new object that you have created. So we created a new object in $javascriptPosts, therefore our code would include those calls like so:

// Custom Loop using WP_Query to fetch JavaScript Posts
$javascriptPosts = new WP_Query( [ 'category_name' => 'javascript' ] );
if ( $javascriptPosts->have_posts() ):
	
	while ( $javascriptPosts->have_posts() ): $javascriptPosts->the_post(); ?>
        <h2><?php the_title(); ?></h2>
        <p><?php the_excerpt(); ?></p>
	<?php endwhile;

else:
	// no posts message or some other fallback here
endif;
wp_reset_postdata();

Also note that we make use of wp_reset_postdata() as a best practice. It seems trivial, but it is in fact pretty important. The documentation tells us the following:

Use this function to restore the global $post variable of the main query loop after a secondary query loop using new WP_Query. It restores the $post variable to the current post in the main query.

Differences between the main query loop and secondary query loops are:

the main loop is based on the URL request and is processed before templates are loaded
secondary loops are queries (using new WP_Query) in theme template or plugin files

In other words, use this function so that you don’t screw up the default WordPress queries when trying to create custom queries via WP_Query().

What if we wanted to fetch posts in the PHP category? The following query should work quite well:

// Custom Loop using WP_Query to fetch PHP Posts
$phpPosts = new WP_Query( [ 'category_name' => 'php' ] );
if ( $phpPosts->have_posts() ):
	
	while ( $phpPosts->have_posts() ): $phpPosts->the_post(); ?>
        <h2><?php the_title(); ?></h2>
        <p><?php the_excerpt(); ?></p>
	<?php endwhile;

else:
	// no posts message or some other fallback here
endif;
wp_reset_postdata();

Putting It All Together

Let’s now clean up our front-page.php file so that we have had our static content at the top, and then our new dynamic content side by side below the static content. We’ll have the main loop at the top of the file which outputs the homepage, then we will make use of our two new custom queries that use WP_Query() to fetch all JavaScript posts and also all PHP posts. We will display them in two columns side by side. Also note that we make use of that get_template_part() function which is so helpful!

front-page.php

<?php

get_header();

// The Main Loop
if ( have_posts() ) :
	while ( have_posts() ) : the_post(); ?>

        <article class="page-layout">
            <nav class="child-navigation-menu children-links clearfix">
                <ul>
					<?php $args = [
						'child_of' => get_the_top_ancestor_id(),
						'title_li' => '',
					];
					wp_list_pages( $args ); ?>
                </ul>
            </nav>
			<?php the_content() ?>
        </article>
	
	<?php endwhile;

else :
	echo '<p>There are no pages!</p>';
endif; ?>
    <!-- home-columns -->
    <div class="home-columns clearfix">
        <div class="home-left">
            <h3>Recent JavaScript Articles</h3>
			<?php // Custom Loop using WP_Query to fetch JavaScript Posts
			$javascriptPosts = new WP_Query( [ 'category_name' => 'javascript' ] );
			if ( $javascriptPosts->have_posts() ):
				
				while ( $javascriptPosts->have_posts() ): $javascriptPosts->the_post();
					get_template_part( 'theposts', get_post_format() );
				endwhile;
			
			else:
				// no posts message or some other fallback here
			endif;
			wp_reset_postdata(); ?>
        </div>
        <div class="home-right">
            <h3>Recent PHP Articles</h3>
			<?php // Custom Loop using WP_Query to fetch PHP Posts
			$phpPosts = new WP_Query( [ 'category_name' => 'php' ] );
			if ( $phpPosts->have_posts() ):
				
				while ( $phpPosts->have_posts() ): $phpPosts->the_post();
					get_template_part( 'theposts', get_post_format() );
				endwhile;
			
			else:
				// no posts message or some other fallback here
			endif;
			wp_reset_postdata();
			?>
        </div>
    </div><!-- /home-columns -->

<?php get_footer();

?>

style.css

.home-columns {
    overflow: auto;
}

.home-left {
    width: 45%;
    float: left;
}

.home-right {
    width: 45%;
    float: right;
}

The results look pretty cool! We now have a static homepage at the top, that anyone can easily update by simply going into the WordPress Dashboard and editing that page. Below that, we now also have our two sections which display recent posts from two different categories in a magazine-like layout. Very cool!
static homepage and custom dynamic content


How To Use WP_Query In WordPress Summary

In this tutorial we learned a lot about WP_Query() and how to use it to fetch custom data that meets our requirements. For our purposes we used WP_Query() to set up a custom magazine-like layout on our homepage by fetching posts from one category in a custom WP_Query(), then fetching another set of posts from a different category in a second WP_Query() call. This is literally just the tip of the proverbial iceberg! WP_Query() can accept many more arguments which we will look at in future tutorials. For now, I hope you feel much more comfortable making use of WP_Query() than when we first started.

Click to share! ⬇️