Introduction to WP_Query

WP_Query is a PHP class that allows you to retrieve posts from the database based on various criteria. For example, you can retrieve posts:

  • within a specific time frame;
  • from a specified category, tags;
  • fresh posts, random posts, popular posts;
  • posts with specified custom fields or a set of such fields.

WP_Query is used in WordPress for any post-related queries. For example, during the generation of any WP page, the WP_Query request is stored in the global variable $wp_query, and besides post data, it also contains information about the current page. No generation of a basic WP page is complete without using WP_Query.

When building the standard WordPress loop, data is taken from the global variable $wp_query and displayed on the screen through auxiliary functions: the_permalink(), the_content().

In addition to the list of posts in $wp_query, information about the current request is stored. Based on this information, WP determines which page we are currently on (post, archive, tag, etc.). Information about the current request is only relevant for the global object $wp_query (for objects in subqueries, this information is meaningless). You can view what is in the global object like this:

print_r( $GLOBALS['wp_query'] );

Often, we obtain information without directly working with this class and global variables – all of this is hidden under the hood. We use a set of ready-made functions: conditional tags, template tags related to outputting data within the Loop, and other functions. Almost all conditional tags refer to this class.

Let's look at a simple query:

$query = new WP_Query( [ 'category_name' => 'news' ] );

In this way, WordPress will make a request to the database to retrieve entries from the "news" category.

Now, the variable $query contains an object with the query results. Let's process the result using special methods:

while ( $query->have_posts() ) {
	$query->the_post();

	the_title(); // output the post title
}

wp_reset_postdata(); // IMPORTANT to restore global $post

If the_post() is used in the loop, then it is mandatory to call the function wp_reset_postdata() after the loop.

have_posts() checks if there are posts in the loop (in the $query object). the_post() sets global $post – the next post from the loop is recorded there, and it also sets other global variables – see setup_postdata(). All of this allows using familiar WP functions in the loop without passing parameters: the_title(), the_content(), etc.

For more details on how this works, read about have_posts() and the_post().

How not affect global $post

If we don't need standard functions that work with global $post, we can use $query->next_post() instead of $query->the_post(). In this case, the global variable $post is not affected:

while ( $query->have_posts() ) {
	$my_post = $query->next_post();

	$url = get_permalink( $my_post );
}

WP_Query via foreach

If no parameters are passed, no request will be made, and just a WP_Query object will be created.

The loop code may look like this (this is the same as get_posts(), but without pre-set parameters):

// create an instance
$my_posts = new WP_Query;

// make a request
$myposts = $my_posts->query( [
	'post_type' => 'page'
] );

// process the result
foreach( $myposts as $pst ){
	echo esc_html( $pst->post_title );
}

For a better understanding and visual perception of the query functions, study the image:

Credit: Andrey Savchenko (rarst.net) / CC-By-SA.

This Note embeded into: WP_Query{}