Sebastian Smith
Sebastian Smith

Reputation: 86

Select a random post without repeat

I need to show only 1 random post from about 300 posts on my Wordpress frontpage. When I press refresh, sometimes same post appears twice or very soon after other refresh. Could I achieve something like iTunes shuffle mode? I'm using this code at the moment:

<?php
$args = array( 'numberposts' => 1, 'orderby' => 'rand' );
$rand_posts = get_posts( $args );
foreach( $rand_posts as $post ) : 
?>
<?php the_title(); ?>
<?php endforeach; ?>

Upvotes: 2

Views: 1004

Answers (1)

brasofilo
brasofilo

Reputation: 26075

This is just a proof of concept but should put you in the right track. Important notes:

  • setting a cookie must happen before any HTML output happens
  • I used the cookie as an array, maybe it can be a comma separated list and use explode to create the array for post__not_in
  • the code uses PHP 5.3+ anonymous functions, you must change it if running a lower version
  • you'll have to fine tune for when no cookie is set, much probably, what we need to do is run get_posts again without the not_in filter
add_action( 'template_redirect', function()
{
    # Not the front page, bail out
    if( !is_front_page() || !is_home() )
        return;

    # Used in the_content
    global $mypost;

    # Set initial array and check cookie    
    $not_in = array();
    if( isset( $_COOKIE['shuffle_posts'] ) )
        $not_in = array_keys( $_COOKIE['shuffle_posts'] );

    # Get posts
    $args = array( 'numberposts' => 1, 'orderby' => 'rand', 'post__not_in' => $not_in );
    $rand_posts = get_posts( $args );

    # All posts shown, reset cookie
    if( !$rand_posts )
    {
        setcookie( 'shuffle_posts', '', time()-86400 );
        foreach($_COOKIE['shuffle_posts'] as $key => $value)
        {
            setcookie( 'shuffle_posts['.$key.']', '', time()-86400 );
            $id = 0;
        }
    }
    # Increment cookie
    else
    {
        setcookie( 'shuffle_posts['.$rand_posts[0]->ID.']', 'viewed', time()+86400 );
        $id = $rand_posts[0]->ID;
    }
    # Set the global, use at will (adjusting the 'bail out' above)
    $mypost = $id;
    return;

    ## DEBUG ONLY
    #  Debug Results - remove the return above
    echo 'current ID:' . $id . "<br />";
    if( !isset( $_COOKIE['shuffle_posts'] ) )
        echo 'no cookie set';
    else
        var_dump($_COOKIE['shuffle_posts']);

    die();
});

add_filter( 'the_content', function( $content )
{
    global $mypost;
    if( isset( $mypost ) )
        $content = '<h1>Random: ' . $mypost . '</h1>' . $content;
    return $content;
});

The filter the_content is just an example. The global $mypost can be used anywhere in the theme templates (after adjusting the bail out).

And if dealing with registered users, instead of cookies we can store the values in user_meta.

Upvotes: 3

Related Questions