1

Continuing my previous question: My post loop produces 2 queries per post:

SELECT * FROM wp_users WHERE ID = '53'
require('wp-blog-header.php'), require_once('wp-includes/template-loader.php'), include('/themes/BT/search.php'), the_post, WP_Query->the_post, WP_Query->setup_postdata, get_userdata, get_user_by, WP_User::get_data_by #20 (0.1ms)
SELECT user_id, meta_key, meta_value FROM wp_usermeta WHERE user_id IN (53) ORDER BY umeta_id ASC
require('wp-blog-header.php'), require_once('wp-includes/template-loader.php'), include('/themes/BT/search.php'), the_post, WP_Query->the_post, WP_Query->setup_postdata, get_userdata, get_user_by, WP_User->init, WP_User->for_blog, WP_User->_init_caps, get_user_meta, get_metadata, update_meta_cache #21 (0.2ms)

This happens even after I've narrowed the template code down to a simple loop:

if ( have_posts() ) : while ( have_posts() ) : the_post();
        echo $post->ID . "<br />";
    endwhile;
endif;
  • Is this expected?
  • Isn't Wordpress supposed to get all user data in a single query?

1 Answer 1

2

Whilst WordPress has gotten pretty good at db caching for loops (thumbnails, post meta, terms), it does not pre-emptively cache users (authors).

So if you have 5 different authors across all the posts in your loop, that's 10 queries (1 for the user object, 1 for the user's meta cache stash). It's thanks to WP_Query::setup_postdata() (which is called by the_post()) - this line:

$authordata = get_userdata($post->post_author);

If the post author is already in the cache, no db hit, which is why you could have 100's of posts in your loop from 5 authors and you'd still only end up with 10 additional queries.

To pre-emptively cache all users in the loop and only ever have 2 queries, no matter how many different authors:

function wpse_203912_the_posts( $posts, $wp_query ) {
    if ( $wp_query->is_main_query() ) { // Remove this condition if you want to cache users whenever anywhere queries posts
        $user_ids = wp_list_pluck( $posts, 'post_author' );
        cache_users( $user_ids );
    }

    return $posts;
}

add_filter( 'the_posts', 'wpse_203912_the_posts', 10, 2 );

The great thing about cache_users() is that it will only hit the db for uncached users, so it's safe to repeatedly call it without worrying if you've already cached the user.

1
  • Works like a charm! My users generally only have 1 post each, so I ended up with lots of user-related queries.
    – Jonathan
    Sep 28, 2015 at 12:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.