WP_Query: get 3 random posts from 10 latest

Working on a site that has a lot of posts, I need to display 3 posts from a particular category, but all of them need to be from the latest 10 published on the site. I can either grab 3 completely random posts (which tends to pull posts that are very old) or grab 10 posts (but I don’t know how to then randomize the order and only display 3).

So far, I have this query:

$args = array(
    'post_type' => 'post',
    'category_name' => 'mycategory',
    'posts_per_page' => 10,
    'orderby' => 'date',
    'order' => 'DESC',
    'meta_key' => '_thumbnail_id',
    'no_found_rows' => 'true'
);
$query = new WP_Query( $args );

along with this attempt to get 3 random posts from the 10 queried:

$randomPosts = shuffle( $query ); 
$randomPosts = array_slice( $randomPosts, 0, 3 );

But treating the results as an array doesn’t work, since it’s actually an object.
My only other thought is to use 'posts_per_page' = 3 with 'orderby' => 'rand' to grab 3 random posts and add a 'date_query' to restrict it to the past 6 months. That would be close, but it would be preferable to restrict the query to the 10 most recent posts (they may all be published 3 days ago or 5 months ago, they are published together in uneven spurts).

What is the best approach?
Query the 10 latest posts as I’m doing, then convert the object to an array, shuffle, and slice, and convert it back to an object, or is there a simpler, more efficient way to accomplish the goal?

3 s
3

There’s one way with:

$args = [
    'post_type'             => 'post',
    'posts_per_page'        => 10,
    'orderby'               => 'date',
    'order'                 => 'DESC',
    'no_found_rows'         => 'true',
    '_shuffle_and_pick'     => 3 // <-- our custom argument
];

$query = new \WP_Query( $args );

where the custom _shuffle_and_pick attribute is supported by this demo plugin:

<?php
/**
 * Plugin Name: Support for the _shuffle_and_pick WP_Query argument.
 */
add_filter( 'the_posts', function( $posts, \WP_Query $query )
{
    if( $pick = $query->get( '_shuffle_and_pick' ) )
    {
        shuffle( $posts );
        $posts = array_slice( $posts, 0, (int) $pick );
    }
    return $posts;
}, 10, 2 );

Leave a Comment