To have full control over displaying posts in WordPress we can use WP_Query class and create our own query. According to documentation, if we want to to display posts in random order, we must pass suitable arguments to the query:
$args = array(
'post_type' => 'post',
'orderby' => 'rand',
);
$query = new WP_Query( $args );
But here we have two problems:
1. Pagination problem – on each page are displayed the same posts, instead of new ones, so pagination don’t work.
2. One post can be displayed several times, even on one page!
So, how to paginate posts correctly when they are displayed in random order?
When we take a look at first problem we can notice, that on each page there is displayed the same posts set. We can fix that issue when we indicate WordPress which posts should be displayed on each page. In WP_Query class we search pagination parameters and find out one that we need: ‘paged’. It show the posts that would normally show up just on page X when using the “Older Entries” link.
Now we need to know what is current page number to show WordPress what to display:
$current_page = get_query_var('paged');
$args = array(
'post_type' => 'post',
'orderby' => 'rand',
'paged' => $current_page,
);
$query = new WP_Query( $args );
Success! We can display random posts and retain pagination order.
Ok, first problem fixed, but what with the second one? Still our posts can be repeated several times, we don’t want that.
How to display random posts without duplicating it?
If we want to display each post only once, without repeating it, and in random order on each time, when user gets on page (but keeping posts order in the same session), we must use $_SESSION variable. To open session we must put this code in functions.php:
function prefix_start_session() {
if( !session_id() ) {
session_start();
}
}
add_action( 'init', 'prefix_start_session' );
Then, in our code we can set session value:
function get_random_post() {
if ( !isset( $_SESSION['random'] ) ) {
$_SESSION['random'] = rand();
}
return $_SESSION['random'];
}
Now we can set query with arguments:
$args = array(
'post_type' => 'post',
'orderby' => 'rand(' . get_random_post() . ')',
'paged' => $current_page,
);
$query = new WP_Query( $args );
And display our posts in loop:
if ( $query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
// display posts
endwhile;
else :
// no content
endif;
So that’s it! Now our posts are displayed in random order without duplicates and with correctly working pagination 🙂
Hello, Thank you for this. It would be great if you could note the complete code that can be implemented in functions.php..That would make it easier for non-coders like me :). Thank you
this caused an error:
if ( query->have_posts() ) :
while ( query->have_posts() ) : query->the_post();
// display posts
endwhile;
else :
// no content
endif;
correct code:
if ( $query->have_posts() ) :
while ( $query->have_posts() ) : $query->the_post();
// display posts
endwhile;
else :
// no content
endif;
You’re right, thank you, I fixed it 😉
Thank you, it worked for me you saved my day.
Thank You ! Worked for me
Hi,
Does anyone have the complete code? I’ve tried using the above but keeping getting a critical error code. So I must be entering it wrong somewhere.
Hi,
I can’t seem to get the code to work. I’m sure I’m the one at fault, are you able to please post the code as a whole at the end?
Hi there,
Thanks for the helpful article!
I noted 2 critical issue warnings with WordPress Site Health;
1) An active PHP session was detected
2) The REST API encountered an error
Using session_write_close fixes the issue:
function prefix_start_session() {
if( !session_id() ) {
session_start();
session_write_close(); } }
Hope this helps 🙂
Slight correction.
rand(x) is case sensitive, thus should be RAND(X).
Therefore:
$args = array(
‘post_type’ => ‘post’,
‘orderby’ => ‘RAND(‘ . get_random_post() . ‘)’,
‘paged’ => $current_page,
);
As per the WP docs:
* @since 4.5.0 Introduced `RAND(x)` syntax for `$orderby`, which allows an integer seed value to random sorts.