WordPress: Random post order with correct pagination

Randomising the order of the returned posts in a WordPress query is easy – simply add  'orderby' => 'rand' to the arguments and you’re good to go – this is great, until you need to paginate the results. As soon as you navigate to the second page of the results, the posts are returned randomly once again and you get an entirely different set of posts that may or may not contain posts that you have already viewed – if you’ve experienced this before then you’ll know exactly how frustrating it can be. After having this problem numerous times myself I decided to find a way around it.

The first thing we need to do is make sure our PHP session is initiated. You will see the reason for this in the function itself, which is where the magic happens – here we will use MySQL’s RAND() function and supply it with a seed value so it uses the same random order on every subsequent page load. To do this we will store a random string as a PHP session variable so it can be used by MySQL as a reference for the order to use for each page. All we need to do is add this snippet to our theme’s functions.php file:


<?php
session_start();
add_filter( 'posts_orderby', 'randomise_with_pagination' );
function randomise_with_pagination( $orderby ) {
if( is_front_page() ) {
// Reset seed on load of initial archive page
if( ! get_query_var( 'paged' ) || get_query_var( 'paged' ) == 0 || get_query_var( 'paged' ) == 1 ) {
if( isset( $_SESSION['seed'] ) ) {
unset( $_SESSION['seed'] );
}
}
// Get seed from session variable if it exists
$seed = false;
if( isset( $_SESSION['seed'] ) ) {
$seed = $_SESSION['seed'];
}
// Set new seed if none exists
if ( ! $seed ) {
$seed = rand();
$_SESSION['seed'] = $seed;
}
// Update ORDER BY clause to use seed
$orderby = 'RAND(' . $seed . ')';
}
return $orderby;
}
?>

view raw

function.php

hosted with ❤ by GitHub

You will notice one extra operation on line 7 of this snippet – we also reset the seed value every time the first page of the posts are loaded. This means that as long as someone stays on the paginated pages they will see a consistent set of results, but once they go back to the first page the randomisation will reset and they will see the posts in a completely different order.

Note that in this example I have limited the ordering to the front page only (that is, the home page of the site when the front page is set to show your latest posts), but you can change the conditional to target any page or post type archive that you like.

25 Thoughts

    1. We’re trying to implement this on the same WordPress theme that Francisco is using. One thing to note about Francisco’s link is that it points to a custom post type. Is there something we need to do to your code in order to make it work for custom post types?

      1. All you need to do is change the is_front_page() conditional and this will work on any pages you specify. What would be best for your use case would be to change it something like is_post_type_archive( ‘post_type_name’ ) – that should handle all the archive pages for the given post type. Basically, when you’re using the posts_orderby or pre_get_posts filters you can do almost anything to modify the query based on any conditional you like. This page should help you understand all the conditional tags that you can use: http://codex.wordpress.org/Conditional_Tags

  1. Hi man, thanks for your code but on the “library” demo I see the GET PAST THAT BRICK WALL AND START BUILDING YOUR FIRST WEB APP same on the first page (2nd position) and on the second page (at first position).
    !?

  2. Hi thanks for the snippet which work’s perfectyl on front end for me. I only have a problem in backend. Now the post list in the admin also display randomly.. any idea why ?

    1. That depends what conditions you replaced is_front_page() with. That conditional should make sure it only affects the correct pages. The best bet to make sure you only ever affect the frontend would be to add if( is_admin() ) return $orderby; as the first line of the function – that will make sure it never affects anything in the dashboard.

      1. Hi thanks,
        I’ve put is_archive condition. it seems to work partially now with the is_admin code added. the strange thing is that affects only one CPT list in admin, not the regular post.

        1. Correction, it works now … i made a typo.. thanks a lot and have a nice day.

  3. Hi thanks for the snippet!!! I have read the code and I’m trying to do with woo commerce. I’m using this code but the pagination problem appears… if I change the condition is_front_page por is_woocommerce_default_catalog works on the sorting function?

    thanks in advance
    /* sorting */
    add_filter( ‘woocommerce_get_catalog_ordering_args’, ‘custom_woocommerce_get_catalog_ordering_args’ );

    function custom_woocommerce_get_catalog_ordering_args( $args ) {
    $orderby_value = isset( $_GET[‘orderby’] ) ? woocommerce_clean( $_GET[‘orderby’] ) : apply_filters( ‘woocommerce_default_catalog_orderby’, get_option( ‘woocommerce_default_catalog_orderby’ ) );

    if ( ‘random_list’ == $orderby_value ) {
    $args[‘orderby’] = ‘rand’;
    $args[‘order’] = ‘desc’;
    $args[‘meta_key’] = ”;
    }

    return $args;
    }

    add_filter( ‘woocommerce_default_catalog_orderby_options’, ‘custom_woocommerce_catalog_orderby’ );
    add_filter( ‘woocommerce_catalog_orderby’, ‘custom_woocommerce_catalog_orderby’ );

    function custom_woocommerce_catalog_orderby( $sortby ) {
    $sortby[‘random_list’] = ‘Random’;
    return $sortby;
    }

  4. Can this be used on woocommerce? i would like my products showing random with the pagination, actualy there is no plugin that do this… thanks!

  5. Thank you for this great snippet. I’ve been using it for a few months.

    But now it stopped working, I don’t know why. The posts are still displayed in a random order, but the pagination doesn’t work anymore — pages 2, 3 etc. will often show repeated posts.

    I’d be glad if you could update the snippet (if it’s possible to correct this behaviour with an update, that is).

    Thanks again.

    1. Actually, it seems the issue is with caching. I tested the snippet with W3 Total Cache disabled, and it worked perfectly. Once I enabled W3 Total Cache, the pagination stopped working properly.

  6. Brilliant and works well. I have a custom field (Featured) that I’d like to come first in a randomised order… then everything else random. Any ideas how to do this? Many thanks for any pointers.

  7. I have pasted your code in functions.php and it doesn’t work for me. The only change I made is I commented out the line if( is_front_page() ) { and line 31 }. Do we need to put in a condtional statement for it to work?
    I’m using the ‘search and filter’ plugin together with relevanssi. Would these plugins cause conflict with the code?

    1. With the code:
      session_start();
      add_filter(‘posts_orderby’, ‘randomise_with_pagination’);
      function randomise_with_pagination( $orderby ) {
      if( !is_admin() ) {
      $seed = $_SESSION[‘seed’];
      if (empty($seed)) {
      $seed = rand();
      $_SESSION[‘seed’] = $seed;
      } $orderby_statement = ‘RAND(‘.$seed.’)’; }
      return orderby;
      }
      there is no longer a repeat on the pagination page but if I go to the first page again and reload it doesn’t randomise the first page again.

  8. Safari will often pre-fetch pages. If one of these pages is the front page, this prefetching will cause the session seed to be invalidated. So do not clear the session seed when hitting the front page. If you need to clear the seed, either expire it or find a more opportune moment to do it.

  9. My Problem is that randomize not only the first page where the different publication are showing, that’s great, but also the widgets that are installed…. for exemple “Last post” and that should not happen….

Leave a Reply