like a pro


$wp_query like a pro

Understand WP's load process

 * Loads the WordPress environment and template.
 * @package WordPress

if ( !isset($wp_did_header) ) {

	$wp_did_header = true;

	// Load the WordPress library.
	require_once( dirname(__FILE__) . '/wp-load.php' );

	// Set up the WordPress query.

	// Load the theme template.
	require_once( ABSPATH . WPINC . '/template-loader.php' );



$wp_query like a pro

$wp_query like a pro

The main query

if (have_posts()) : while (have_posts()) : the_post();
    // Do stuff

endwhile; endif;

Always use the main query!

$wp_query like a pro

Altering the main query

// Don't do this in place of the main query
$query = new WP_Query( array(
    'post_type'        => 'post',
    'category__not_in' => array(42)
if ($query->have_posts()) : while ($query->have_posts()) : $query->the_post();

    // Posts, excluding category 42
endwhile; endif; wp_reset_postdata();

Do not use WP_Query in place of the main query!

The main query runs regardless, so you're just making WordPress do extra laps to the database.


$wp_query like a pro

Altering the main query

if (have_posts()) : while (have_posts()) : the_post();
    // Posts, excluding category 42

endwhile; endif;
function exclude_category($query) {
    if (!is_admin() && $query->is_main_query() && is_archive()) {
        $query->set('category__not_in', '42');

add_action('pre_get_posts', 'exclude_category');



pre_get_posts runs before the main query, resulting in no performance hit

$wp_query like a pro

Using WP_Query

Use WP_Query for secondary loops only.

$wp_query like a pro

What about get_posts()?

  • Was added in WordPress 1.2 before WP_Query existed.
  • Used the wpdb class to make its query until WP_Query was added in WordPress 1.5.
  • get_posts() is a WP_Query with these arguments:
    • suppress_filters => true (disables several filter hooks)
    • ignore_sticky_posts => true
    • no_found_rows => true (disables pagination)
  • no_found_rows saves 1 query by skipping calculation of pagination, but the argument can be added to WP_Query for the same effect.

$wp_query like a pro

Custom queries

Always use the wpdb class for the best efficiency and security if you need custom SQL queries.

global $wpdb;

// Echo the title of the most commented post
$posts = $wpdb->get_row("SELECT ID, post_title 
                         FROM " . $wpdb->prefix . "posts 
                         WHERE post_status = 'publish'
                         AND post_type = 'post' 
                         ORDER BY comment_count DESC
                         LIMIT 0,1");

echo $posts->post_title;

WordPress doesn't cache wpdb, so you should use the Transients API

$wp_query like a pro

Must-read Handbook content

WordPress Queries


Optimizing WordPress Queries

Query Monitor

Optimizing WordPress Queries

Transients API

  • Caches your data in the options table in the database.
  • If persistent caching is enabled (via a plugin), it will use the WP Object Cache instead.
$data = get_transient('name_your_transient');

if ($data === false) {

    // If transient doesn't exist or has expired, query data and set transient

    $data = 'Expensive query';
    set_transient('name_your_transient', $data, EXPIRATION_TIME);


echo $data;

Optimizing WordPress Queries


Dev Meeting 10-11-2016

By Adam Walter

Dev Meeting 10-11-2016

  • 1,148