Working with WP_Query

wp_query header image

1. WP_Query: Understanding the Basics of Object-Oriented Programming

The WP_Query API uses a programming style called object-oriented programming, or OOP. Every WP_Query is actually a WP_Query Object, meaning an individual instance of the broader WP_Widget Class. If this setup doesn’t make sense to you, you’ll want to quickly learn the basics of object-oriented programming (OOP):

The Concepts of Object-Oriented PHP You Need to Understand for WordPress Development

Key Point: Classes and Objects

A Class is an abstract description of a type of thing. Once you’ve defined a Class, you create actual Objects of that class. The article uses the example of a Chair class:

// Creating the Chair class
class Chair {
    // Here we list important elements that all Chairs have,
    // like "height" and "color"
}

// Creating a Chair object
$mychair = new Chair;

This is the bedrock of what you’ll need to know in OOP to work with WP_Query.

2. The Loop: How WordPress Processes Fetched Post Bundles into Webpages

WP_Query does precisely one thing: it fetches bundles of WordPress posts from the WordPress database. Before you learn WP_Query directly, you’ll need to understand the basic engine of WordPress: the Loop, which takes these bundles of fetched posts, and processes them, one after the other, into the contents of your site’s pages.

Core Concepts of WordPress Themes: Processing Posts with The Loop

Key Point: A Basic Loop

The Loop works on a fetched bundle of posts, and it processes through them one by one. This is what while ( have_posts() ) means: as long as there are posts left in the bundle to be processed, then continue processing them one by one.

The processing is done inside the while loop. This is where most HTML markup goes, as well as template tags that rely on the Loop, like the_title().

A simple, working Loop like you might see on your theme’s index.php looks like this:

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

		<article class="full-article">
			<h2><?php the_title(); ?></h2>
			<?php the_content(); ?>
		</article>

	<?php endwhile;
endif;

The Loop is how WordPress processes post bundles into webpages. The next articles, on WP_Query and related topics, cover how to fetch and work with these post bundles.

3. The Basic Use of WP_Query

This article covers the standard use of WP_Query: writing custom queries by creating new WP_Query objects with custom $args, and then looping through those custom queries to create the desired page output.

Getting to Know WP_Query

Key Point: Creating a WP_Query with Custom $args

The power of creating a WP_Query object is in the custom arguments you pass into the creation process. These arguments are best written as an associative array, which is often given the standard name $args.

The following code defines three arguments that will be used to create a new WP_Query. This query will retrieve:

  1. The first 10 posts,
  2. Whose author is the user fred,
  3. Whose post type is post.
$args = array(
    'posts_per_page' => 10,
    'author_name' => 'fred',
    'post_type' => 'post',
);
$query = new WP_Query( $args );

The end result of this process is that the value of the variable $query is now the fetched post bundle: a PHP object with the complete content and metadata of the ten posts that our WP_Query retrieved.

Key Point: Looping through a Custom WP_Query

The process we use to work with the fetched post bundle stored in $query is almost identical to the Loop. The following custom loop will print out the titles of the ten fetched posts, one by one (and then reset the query with wp_reset_postdata() to avoid errors later in processing):

while( $query->have_posts() ) {
	$query->the_post();
	echo '<li>' . get_the_title() . '</li>';
}

// Restore original Post Data
wp_reset_postdata();

4. Using WP_Query Objects Without the Loop

This section explores WP_Query objects not as a mysterious things we can loop through, but as PHP objects with well-defined properties. Being able to work with WP_Query objects directly makes some things possible that you can’t do with standard loops.

Using WP_Query Objects Without the Loop

Key Point: Working with WP_Query Objects Directly

A WP_Query object has a defined structure, and defined properties and methods. For example, for a WP_Query called $query, you can directly access the array of fetched posts with $query->posts, you can get the post title of the first fetched post with $query->posts[0]->post_title, and so on.

Key Point: Using Functional Operations to Modify WP_Query Objects

The example in this article sorts fetched posts alphabetically by post content (not an option with regular custom queries and loops) with sorting methodologies from basic functional programming, including array_map() and usort(). You can learn these functions in the article, and in our introduction to functional PHP for WordPress developers.

5. Modifying Existing WP_Querys with pre_get_posts

pre_get_posts is a filter that makes it possible to alter the parameters of an existing WP_Query, before it fetches its post bundle from the WordPress database—thereby changing the post bundle it ultimately fetches. It is more convenient than writing a custom WP_Query in some situations, and in others it’s virtually the only path to a working solution.

Practical Uses of pre_get_posts

Key Point: How to Modify an Existing Query with pre_get_posts

pre_get_posts is a WordPress filter that fires immediately before a WP_Query object fetches posts from the WordPress database. Using this filter makes it possible to modify the query directly.

The following example changes the post type that will display on a site’s blog index from post to page:

add_filter( 'pre_get_posts', 'wpshout_pages_blogindex' );
function wpshout_pages_blogindex( $query ) {
	if ( is_home() && $query->is_main_query() ) :
		$query->set( 'post_type', 'page' );
	endif;
}

Key Point: Use pre_get_posts to Alter WordPress Default Queries

WordPress’s default queries, like the ones that create your blog index and your archive pages, are difficult to alter without pre_get_posts. Changing these default queries is the primary use case for pre_get_posts.

The following real-world example alters the main queries that run on archive pages. These queries will now fetch posts of a new custom post type, course, alongside the post results they normally return:

add_filter( 'pre_get_posts', 'wpshout_add_custom_post_types_to_query' );
function wpshout_add_custom_post_types_to_query( $query ) {
	if( is_archive() && 
		$query->is_main_query() &&
		empty( $query->query_vars['suppress_filters'] )
	) {
		$query->set( 'post_type', array( 'post', 'course' ) );
	}
}

Now You Understand WP_Query

WP_Query—along with the Loop, which processes its results—is the basic engine of WordPress. You should now understand a lot better how to use the WP_Query API to fetch and process your own post bundles, which gives you a tremendous amount of power.

Thanks for reading, and as always, we’re happy to hear questions and comments below!

Image credit: pixabay


6 Responses

Comments

Pingbacks

Add a comment

(required)

(required)

(optional)