0

I'm looking for an efficient way to retrieve the most recent post from every term for a given taxonomy type. I found this question, which provides the same solution I came to on my own:

$terms = get_terms( 'my_taxonomy' );

foreach( $terms as $term) {
    $args = array(
        'posts_per_page' => 1,
        'post_type' => 'any',
        'my_taxonomy' => $term -> slug
    );
    $termQuery = new WP_Query( $args );

    while ( $termQuery -> have_posts() ) : $termQuery -> the_post(); ?>
        // display post
    endwhile;
}

Basically, get all the terms, and then for each term, execute a WordPress query to retrieve the most recent post.

I see no reason why this won't work as intended, but I can't shake the feeling that it is painfully inefficient. Is there a better way to do this?

1 Answer 1

1

You are correct that this is ineffecient, and there isn't really much you can do about it. I think the only other way to do this may be is with a very large (also ineffecient ) custom SQL query which unfortuantely I cannot help you with. If you have like 10 or 20 terms, the impact will not be that big, but if you have more, the effect can get very noticeable.

The only real way to make this a bit more effecient is by putting your results in a trancient and then flushing and resetting this transient whenever a new post is posted, deleted or updated ( use transition_post_status hook ). This will really work very good if you are not posting many posts in a short period of time. If you are going to post more that once or twice daily, then unfortunately I wouldn't bother going this route if you only have a few terms as setting transients are more expensive than the actual query itself.

REFERENCES

ADDITIONAL RESOURCES

Here are a few posts that you can check out which I have recently done about transients and using transients with transition_post_status

FEW NOTES ON YOUR CODE

  • You can make your query a bit more effecient by adding 'no_found_rows' => true, to your query arguments. By default, if you ask for one post, WP_Query retrieves that one post, but it also check the complete db for all posts matching the query arguments. This is done for pagination purposes. To avoid this in a query like yours, no_found_rows is used. This will make WP_Query look for the first matching post, and then bail out immediately after finding a matching post

  • You would want to first check if $terms actually have a valid value or not before using it. get_terms returns an array of terms on success, or a WP_Error or empty array on failure. Omitting those checks will lead to php errors and notices if your code fails, this is bugs that you should avoid. You need to remember, if there are any possibility that code might fail (which is almost any code), you need to ensure that that code fails in an expected controlled manner. In this case, you need to check if $terms is not empty or that $terms did not return a WP_Error object.

  • You need to reset every instance of WP_Query. One instance of WP_Query can have unexpected influences on the next instance of WP_Query. Ignoring to reset every query can set you of on a wild goose chase in the event of code failure and bugs. Always makes sure to reset all custom queries. This should be done by adding wp_reset_postdata() just after endwhile but before endif in your loop.

  • You should use a proper tax_query as the {tax} syntax is depreciated according to docs

FINAL THOUGHTS

In order to test the effenciency of code, set yourself up with a test page on your local install as I have described in this post. This will let you see how effecient your code is by returning the amount of db calls and the time taken to make those calls by the specific code. I always test my code this way.

It is also a super idea to install the following plugins on your local install: (Do not install these on a production/live site. Once installed, you will see why)

(CAVEAT: I don't have any affiliation to these plugins :-))

These plugins is a must for developers and will print debug errors to screen, show you page load times, overall amount of queries and time taken and will also break these queries down etc etc.

2
  • thank you for such a detailed response. I ended up abandoning this feature for the project I'm working on as it proved to be unnecessary. I'm intrigued by the Transient API though, and will definitely look into that and the two plugins that you mentioned.
    – Mike
    Apr 20, 2015 at 13:11
  • My pleasure, glad I could be of some assistance. The transient API (and the build in cache system) is really worth looking into, specially for large resource intensive queries like the one in your question. Worth the while getting your hands dirty and playing around with it :-). Good luck on your project and enjoy :-) Apr 20, 2015 at 13:16

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.