2

I know that I can display 4 random posts by doing something like:

get_posts('orderby=rand&numberposts=4');

 

What I'm trying to achieve is starting with a random item, but then showing the next 3 posts that are in chronological order.

I'm thinking something along the lines of this:

$posts = get_posts('orderby=rand&numberposts=1'); 

foreach($posts as $post) { 
    the_title();

    //get next 3 chronological posts and loop
} 

I guess I need to use something like the 'offset' parameter, but with a post id instead of a position?

2
  • So you need a random post, and then three posts that are published before or after this specific random post Oct 26, 2015 at 15:44
  • @PieterGoosen Three posts after the randomly chosen one
    – Adam Lobo
    Oct 26, 2015 at 15:46

2 Answers 2

2

For a random offset we might try:

$ppp    = 4;  
$total  = wp_count_posts()->publish;    

$offset = $total < $ppp ? 0 : rand( 0, $total - $ppp );

$posts = get_posts( [
    'posts_per_page' => $ppp,
    'offset'         => $offset
] );

Example:

Let's take $ppp as 4 and assume $total is 6.

Then are three possibilities for the $offset, namely 0, 1 and 2:

Nr  Offset Selections
1   0      x
2   1      x x
3   2      x x x
4   3      x x x
5   4        x x
6   5          x

so

$offset = $total < $ppp ? 0 : rand( 0, $total - $ppp );

would give:

$offset = rand( 0, 6 - 4 );

or just

$offset = rand( 0, 2 );
8
  • Thanks for the reply. One question though - Would this not just get a random post followed by the first 3 posts, rather than three following on from the random one?
    – Adam Lobo
    Oct 26, 2015 at 16:28
  • oh, guess I misunderstood your question, you want to display 4 posts, with a random offset? Currently I just fetch a random one, and then just the 3 newest, excluding the random one.
    – birgire
    Oct 26, 2015 at 16:29
  • Basically, yes. So essentially, on one page load, you might see posts 5,6,7,8 - Then another you might see 14,15,16,17 - or 9,10,11,12 etc.
    – Adam Lobo
    Oct 26, 2015 at 16:32
  • 1
    Using your update seems to have done the trick! Thanks very much :)
    – Adam Lobo
    Oct 26, 2015 at 17:01
  • 1
    Nice approach with the offset. You can also use a date_query ;-) Oct 26, 2015 at 17:02
2

Here is another approach using a date_query.

  • We will get the one random post

  • We will then use a date_query to get the other 3 posts adjacent to that one random post

Here is the function we will use: (NOTE: I have commented the code to make it easy to follow, and the code requires PHP 5.4+)

function get_random_posts( $args = [], $direction = 'after' )
{
    /**
     * Lets first get our random post, then work from there. We will be using the same 
     * exact arguments for all our queries we need to run. We do however need to modify
     * some a bit. We will save the default args to a another variable and then modify
     * the args to pass to the first query.
     *
     * We will let WP_Query handle the sanitation and validation from the
     * array of arguments.  
     */
    $random_args                   = $args;
    $random_args['orderby']        = 'rand';
    $random_args['posts_per_page'] = 1;

    $random_post = get_posts( $random_args );

    /**
     * We will o get the adjacent posts from the random one. We will be 
     * using the default $args again
     *
     * We will need to sort out the amount of posts to get from the adjacent
     * post query first before  we go along. We need to deduct one from the amount
     * of posts to adjust for the random post
     */
    if ( isset( $args['posts_per_page'] ) ) {
        $args['posts_per_page'] = ( $args['posts_per_page'] - 1 );
    } else {
        $args['posts_per_page'] = ( get_option( 'posts_per_page' ) - 1 );
    }

    // Create our date query to get the adjacent posts  
    $date_query = [
        [
            $direction  => $random_post[0]->post_date,
            'inclusive' => false
        ]
    ];
    $args['date_query'] = $date_query;

    // Set the order parameter according to direction
    if ( $direction === 'after' ) {
        $args['order'] = 'ASC';
    } else {
        $args['order'] = 'DESC';
    }

    $adjacent_query = get_posts( $args );   

    // Merge and return the posts
    return array_merge( $random_post, $adjacent_query );
}

As you can see, the first parameter in the function is $args. This wil be an array of arguments that you would normally pass to WP_Query. The second parameter, $direction will be the direction of the adjacent posts, either before or after according to needs.

You would use the function as follow:

$args = [
    'posts_per_page' => 4 // The amount of posts to get
    // Any other arguments you might need
];
$q = get_random_posts( $args );

foreach ( $q as $post ) {
    setup_postdata( $post );

    the_title();

}
wp_reset_postdata();
4
  • This looks good! Will have a go at implementing tomorrow. This solution may be better suited as I may need to include some metakeys into my query. Thanks :)
    – Adam Lobo
    Oct 26, 2015 at 17:26
  • My pleasure. As always, if you have any issue, feel free to leave me a comment ;-). Enjoy Oct 26, 2015 at 17:29
  • Glad you implemented the idea, nice to see different approaches ;-)
    – birgire
    Oct 26, 2015 at 19:16
  • 1
    @birgire thanks. I was actually busy with this from the word go ;-). But it is as you always say, very nice to see different approches. I really never ever though of your approach. This way we all learn in some way or the other and the community really benefit from answeres like these Oct 26, 2015 at 19:23

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.