-
fcacic
Hi,
I’m using GeneratePress + GenerateBlocks and I’m trying to create a “Post of the Day” section on my homepage.
Goal:
- Display 1 random post
- The selected post should remain the same for 24 hours (from midnight to midnight)
- It should change automatically the next day
- It must not re-randomize on every page refresh
Currently:
- I’m using a GenerateBlocks Query Loop
- Post type: Post
- Posts per page: 1
- Order by: Random
The issue is that it re-randomizes on every page load, which is expected behavior for orderby=rand, but not what I need.
Cheers!
-
George
Hi,
This requires custom PHP since the Query Loop’s
orderby=randwill always re-randomize on each page load.The solution uses a transient to cache the randomly selected post ID until midnight, so it stays fixed for the day:
add_filter( 'generateblocks_query_loop_args', function( $query_args, $attributes ) { $classes = $attributes['className'] ?? ''; if ( strpos( $classes, 'post-of-the-day' ) === false ) { return $query_args; } $transient_key = 'post_of_the_day_id'; $post_id = get_transient( $transient_key ); if ( false === $post_id ) { $random_post = get_posts( array( 'post_type' => $query_args['post_type'] ?? 'post', 'posts_per_page' => 1, 'orderby' => 'rand', 'fields' => 'ids', ) ); if ( ! empty( $random_post ) ) { $post_id = $random_post[0]; // Cache until midnight (based on Settings → General → Timezone) $now = current_time( 'timestamp' ); $midnight = strtotime( 'tomorrow midnight', $now ); set_transient( $transient_key, $post_id, $midnight - $now ); } } if ( $post_id ) { $query_args['post__in'] = array( $post_id ); $query_args['orderby'] = 'post__in'; } return $query_args; }, 99, 2 );Setup:
- Add the code to your child theme’s
functions.phpor a code snippets plugin - On your Query Loop block, add the CSS class
post-of-the-day(Settings -> Additional CSS Class(es)) - Set Posts Per Page to 1
- Remove any
orderby=randsetting from the Query Loop itself
The random selection happens once per day at midnight, and that post is then shown to all visitors until the next midnight. Note that “midnight” is based on the timezone set in Settings -> General -> Timezone.
Note on caching: If you’re using page caching (LiteSpeed, WP Rocket, Cloudflare, etc.), the cached page may continue showing the old post even after midnight until the cache clears. You may need to either:
- Set your page cache TTL to expire around midnight
- Exclude this page from page caching
- Set up a scheduled cache purge at midnight
The transient itself will work correctly — it’s just that visitors may see a cached version of the page until it refreshes.
- Add the code to your child theme’s
-
Hi,
Thanks a lot George, the transient solution works perfectly!
I have a follow-up question:
Is it possible to limit the “Post of the Day” selection to a specific subset of posts, and still keep the same daily-random behavior?
For example:
- Only include posts from a specific category (e.g. “Daily Prayer”)
- Or only include posts with a specific tag
- Or even manually include specific post IDs
Then, among those filtered posts, select 1 random post and cache it until midnight — exactly like the current solution.
Would it be enough to modify the get_posts() arguments inside the transient logic (for example by adding category_name, tag, or post__in)?
Just want to confirm the cleanest way to restrict the pool without breaking the daily caching behavior.
Thanks.
-
George
Hi,
You just need to modify the
get_posts()arguments inside the filter. The caching behavior stays the same.Here are examples for each scenario:
Filter by category:
$random_post = get_posts( array( 'post_type' => 'post', 'posts_per_page' => 1, 'orderby' => 'rand', 'category_name' => 'daily-prayer', // Use the category slug 'fields' => 'ids', ) );Filter by tag:
$random_post = get_posts( array( 'post_type' => 'post', 'posts_per_page' => 1, 'orderby' => 'rand', 'tag' => 'featured', // Use the tag slug 'fields' => 'ids', ) );Filter by specific post IDs:
$allowed_posts = array( 123, 456, 789 ); // Your chosen post IDs $random_post = get_posts( array( 'post_type' => 'post', 'posts_per_page' => 1, 'orderby' => 'rand', 'post__in' => $allowed_posts, 'fields' => 'ids', ) );Combine multiple filters:
$random_post = get_posts( array( 'post_type' => 'post', 'posts_per_page' => 1, 'orderby' => 'rand', 'category_name' => 'daily-prayer', 'tag' => 'featured', 'fields' => 'ids', ) );The transient caching logic remains unchanged — it will just select from your filtered pool instead of all posts.
-
fcacic
Thanks George, you’re awesome!
-
George
You are welcome!
- You must be logged in to reply to this topic.