1

I'm working on a page which lists staff members for a large company and trying to minimise the number of times I'm forced to query the database as it gets quite complex and slow.

  • 'person' is a custom post type (there are about 300 people)
  • 'date_accredited' is a date field added via Advanced Custom Fields plugin.

Only accredited staff will have a 'date_accredited'.

I need to list every 'person' BUT, with ALL accredited staff listed first (so about 20 accredited staff come at the top).

At the moment, I am doing a call to WP_Query like:

$args = array(
    'posts_per_page' => -1, 
    'post_type' => 'people', 
    'no_found_rows' => true, 
    'meta_key' => 'date_accredited'
);
$people = new WP_Query($args);

After that I'm doing:

while($people->have_posts()): $people->the_post();      
    $my_post_meta = get_post_meta($post->ID, 'date_accredited', true);
    if (!empty($my_post_meta)) {
        array_push($accredited, $post);
    } else {
        array_push($notAccredited, $post);
    }
endwhile;

Leaving us with two arrays of 'person' objects. My thinking here was that I would be able to do something like the following to get the list I want:

foreach($accredited as $person):
    personTile($person);
endforeach;

foreach($notAccredited as $person):
    personTile($person);
endforeach;

I'm trying to avoid re-querying the database.

The personTile(); function was supposed to output various info and HTML (the_post_thumbnail() and various Advanced Custom Fields fields), but what I'm realising now is that none of this is included in the post objects I get from WP_Query(), so I'm forced to use things like:

  • get_the_post_thumbnail($person->ID)
  • get_permalink($person->ID)
  • get_field('date_accredited', $person->ID)

All of these cost another DB Query (each!), and worse still since they are in a loop each one happens around 300 times.

Is there any way to get the permalink, thumbnail and ACF fields to be included in the original DB Query? Would I need to resort to a custom MySQL Query???

Any other suggestions welcome!

  • Can't really think of an alternative here, execpt making use of transients or putting your results in a cache. You can have a look at a custom SQL query, but you will need to test its effiency. Remember, 100 small effecient db queries can be much faster as one or two ineffecient ones. Download query monitor plugin and test your results and make comparisons. Don't run it on a live site though – Pieter Goosen Jan 28 '15 at 12:22
4

All of these cost another DB Query (each!), and worse still since they are in a loop each one happens around 300 times.

Don't panic! The posts from your query are stored in WordPress' object cache (which is simply memory, unless you have a custom cache system in place).

All functions that operate on posts route through this cache, so in your case there's no extra database hit, even when you're not in "the loop".

You will however want to pop this line in, right after your query:

// http://wpseek.com/function/update_post_thumbnail_cache/
update_post_thumbnail_cache( $people );

This will run two extra queries (posts & post meta), which adds all thumbnails (attachments) for posts in the WP_Query instance to the same cache.

Otherwise you will end up with a lot of queries (two for each post that has a thumbnail).

N.B: There are a few WP_Query arguments that will change the way posts are cached:

  • update_post_meta_cache (almost always yes)
  • update_post_term_cache (if you don't need terms you can save a query here)
  • fields (if not all, nothing is cached and above is ignored)
  • cache_results (if false, nothing is cached and everything above is ignored)
  • Good explanation, I tried adding update_post_thumbnail_cache($people); and it made no performance difference though? To confirm I wasn't going crazy I removed the following from my personTile() function: if(has_post_thumbnail($person->ID)) { echo get_the_post_thumbnail($person->ID, 'person-thumbnail'); } Removing that gave a small performance boost as expected... from what you're saying I was expecting to see about half the same performance boost from using update_post_thumb_cache? – Mike Source Jan 28 '15 at 14:28
  • Where I'm really confused is that my $person object from the query only gives me: ID, post_author, post_date, post_date_gmt, post_content, post_title, post_excerpt, post_status, comment_status, ping_status, post_password, post_name, to_ping, pinged, post_modified, post_modified_gmt, post_content_filtered, post_parent, guid, menu_order, post_type, post_mime_type, comment_count, filter – Mike Source Jan 28 '15 at 14:46
  • This is from examining print_r($people); and I use ACF's get_field() function quite a lot. Is there any way to just examine the object cache and see what's being stored? – Mike Source Jan 28 '15 at 14:47
  • Measuring performance "by eye" isn't really very effective. And yes, your $person_object should only have those properties. All meta is stored in another object (in the cache), linked by post ID. Can you try installing Debug Queries and see what actual queries are firing. – TheDeadMedic Jan 28 '15 at 14:47
  • Quite a lot of queries, none very time consuming: Total query time: 0.04489s for 49 queries. Page generated in 2.31387s, 98.06% PHP, 1.94% MySQL – Mike Source Jan 28 '15 at 15:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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