I have a shortcode that queries some custom posts and also has pagination added. Everything works, but I want to randomize the order. However when I set order to ‘rand’ in my args, every page in my pagination is totally random – meaning, the same post can show up multiple times on different pages. How can I randomize the order of all my posts but not on a per-page level? Here’s my code:
function slaProductsArchive( $atts ){
global $paged;
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$numposts = intval($atts['num']);
$cat = $atts['cat'];
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => $numposts,
'orderby' => 'rand',
'product-category' => $cat,
'paged' => $paged,
);
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
// Display my posts
endwhile;
$output .= '</div>';
$output .= '<div class="slaPagination"><span class="prev-posts-links">' . get_previous_posts_link('<i class="fas fa-arrow-left"></i> Previous') . '</span> ';
$output .= '<span class="next-posts-links">' . get_next_posts_link('Next <i class="fas fa-arrow-right"></i>', $loop->max_num_pages) . '</span></div>';
wp_reset_postdata();
return $output;
}
add_shortcode('slaProductsArchive', 'slaProductsArchive');
2
Answers
There are a few things you can do, based on how you’d like to handle it. A few ideas:
random
order with something that changesThere are other ways of course, and numbers 2 and 3 aren’t particularly graceful outside of very specific uses. So let’s focus on number 1, seeding the
random
.The
posts_orderby
filter is the one you’re looking for. It allows you to, well… filter what the posts are ordered by.Figured out what the define
$seed
as is really up to you, and how often you want the random order to change.How it works is that if you
RAND(1)
– it will seed the random with 1, so as long as the posts are unchanged, they’ll always be in that order.RAND(2)
will produce an entirely different order thanRAND(1)
– but every time you useRAND(2)
it’s the same. For instance:What I use for one of my WP sites is seed in the day:
$seed = date('M d, Y')
. That way, the posts always "randomize" at midnight every night, but page 1, page 2, page 3, etc will always be in order. For example:If that doesn’t work for your usecase, you can use PHP sessions and store a random number in there, or you can store a random number in a cookie – and refresh that every time the user visits "page 1" so page 1 is always random, but page 2, 3, 4 always pull from that cookied-seed, etc.
Just figure out how often you want the seed to change, and then drop that in the
posts_orderby
filter, and you’ll be good to go.Just make sure that you use the
add_filter
before you callnew WP_Query()
, and thenremove_filter
afterwards if you don’t want it to apply anywhere else!For this, I used the WC-Session, since you’re using products, I’m assuming you are using WooCommerce. Each page stores in a session variable, so if you go back to a previous page, it’s the same as before. It also writes a separate array of posts that were done so you can use
post__not_in
.So while this generates a random order, once a page is created, it’s that order on refresh.
I also updated your usage of the
shortcode_atts
and made a condition in case there is no product category set.Alternate Method Without WooCommerce
In this method, I initialize a PHP Session, and use the cookie of the session ID to store a transient, since all of the rest is being done after headers are sent. So the session is only for a session ID. You could also simply set a cookie with whatever name you want and use it for a made up session, purely for using transients as this session.