Consistent Random Set Of Posts

A recent post on the WP support forum asked how to retrieve posts randomly, but be consistent when paginating.  In other words, the same random set would be shown on page 1 even after switching to a different page and back again.

The answer to this is to use a filter on the query to replace the ‘ORDER BY’ clause.  The MySQL RAND() function allows a seed value to the function.  Every time the same seed is supplied, the same set of rows will be retrieved for a given query.

So, all we need to do is replace the ‘ORDER BY RAND()’ part of the query with a string like ‘ORDER BY RAND(12345)’  and the order of the rows selected will be consistent for each page.

In the example below, I have used the current date as the seed, so the query will return the same values all day.  If you change the seed so that it changes each hour, the same set will be returned for one hour, etc.


<?php

// Retrieve consistent random set of posts with pagination
function mam_posts_query($query) {
   global $mam_posts_query;
   if ($mam_posts_query && strpos($query, 'ORDER BY RAND()') !== false) {
      $query = str_replace('ORDER BY RAND()',$mam_posts_query,$query);
      //print_r("<p>$query</p>");
   }
   return $query;
}
add_filter('query','mam_posts_query');
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$seed = date('Ymd');  // Use date('Ymdh') to get an hourly change
global $mam_posts_query;
$mam_posts_query = " ORDER BY rand($seed) "; // Turn on filter
$args = array(
   'caller_get_posts' => 1,  // Stickies will be repeated if this is not set
   'orderby' => 'rand',      // This MUST be in the query - the filter checks for it
   'paged' => $paged,
);
query_posts($args);
$mam_posts_query = ''; // Turn off filter
// echo "<br />Seed is $seed, Paged is $paged";
if (have_posts()) {
   while (have_posts()) {
      the_post();
      echo "<br />ID: $post->ID " . get_the_title();
   }
}  ?>
<div>
   <div><?php next_posts_link('&laquo; Older Entries') ?></div>
   <div><?php previous_posts_link('Newer Entries &raquo;') ?></div>
</div>

That example will show the same set of posts to all viewers, but change each day. To show a different set for each viewer, set the seed like this:

    $seed = $_SESSION['seed'];
    if (empty($seed)) {
      $seed = rand();
      $_SESSION['seed'] = $seed;
    }

8 Responses to Consistent Random Set Of Posts

  • Nathan says:

    Is there a way to display random paged posts in this manner but to keep the “recent posts” widget functionality?
    I would like to only display random posts on my home page and have them paged on the home page only, is this the best method? It is very important that I am still able to display recent posts while displaying random posts at the same time

  • Mat says:

    Thanks for this, this is almost exactly what I was after! The complication for me is that I am displaying the paged results from a query string. In my case, the user has arrived at the archive view by selecting a category in a drop down list.

    When using the code above, it works but displays ALL posts on the site, not the category from the query string. Any ideas how i can retain this query in your loop?

    Cheers!

    • Mac says:

      I think you can preserve the original query arguments by replacing the query_posts($args); line with this:

      global $wp_query;
      query_posts(
         array_merge(
            $wp_query->query,
            $args
         )
      );
      
  • fredk says:

    Thanks ! Exactly what i was looking for ! Works perfectly.

  • Leon says:

    I’ve posted some code in previous post and it’s not shown…so i appologize for bit unusual comments. Code i’ was talking about is

    query_posts($query_string . ‘&orderby=rand’)

    • Mac says:

      I would need to see the entire template file that you are trying to change in order to know where to insert the code.

      Please put the code into a pastebin, and post a link to it here.

  • Leon says:

    Hello,

    God bless ppl like you for helping us, lame wannabe programes out :)

    Can you please give advice about where to put the code? In which php? I’ve used

    in index.php and pagination didnt work correctly so i would realy like to use your solution.

    Best regards and thank you very much

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>