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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
} | |
?> |
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.
Hi, I have very little knowledge of this, but I’ve seen the example page and change http://publicbeta.co/library/ but after a time and kept fixed the pagination, try adding it to a page I’m developing http://www.vidajarocha.com/orizaba/placecategory/directorio-completo/ paste the code you give and did not see any change, any suggestions? I would greatly appreciate your help. thanks
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?
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
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).
!?
It seems to be sorted out now – could possibly have just been a caching issue on the server. Have a look again and it should be handling things correctly now.
Thank you for this! Saved me a lot of headache.
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 ?
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 addif( is_admin() ) return $orderby;
as the first line of the function – that will make sure it never affects anything in the dashboard.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.
Correction, it works now … i made a typo.. thanks a lot and have a nice day.
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;
}
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!
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.
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.
I did some additional tests. Yes, it’s a caching issue. But the problem is Varnish, not W3 Total Cache. My bad.
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.
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?
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.
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.
Hi Hugh, I saw on a wp.org topic, you mention a change in WP 4.5 (https://wordpress.org/support/topic/random-12/) the allows us to not use the posts_orderby filter. Any chance I could get you to post an updated snippet?
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….
Works well. I tried pre_get_posts but it didn’t work properly even though the method has been posted all over the internet.