I wanted to make a random post of the day. In this case, I wanted it to be a random post of one of two custom post types, and I wanted to output it as JSON for a variety of reasons, including future plans. Like tweeting that post.
I’ll get to that later.
Overview
To do this, I have the following moving parts:
- The RESTful routes
- The random post
- The expiration (i.e. each post lasts a day)
I’m going to skip over how to make a REST API route. I talked about that earlier in 2017 when I explained how I made the Bury Your Queers plugin.
What’s important here is actually the random post and spitting out the right content.
Getting a Random Post
This is cool. WordPress can do this out of the box:
$args = array( 'post_type' => 'post_type_characters', 'orderby' => 'rand', 'posts_per_page' =>'1', ); $post = new WP_Query( $args ); while ( $post->have_posts() ) { $post->the_post(); $id = get_the_ID(); } wp_reset_postdata(); $of_the_day_array = array( 'name' => get_the_title( $id ), 'url' => get_permalink( $id ), );
And at that point all you need to do is have the API return the array, and your final output is like this:
{"name":"Van","url":"http:\/\/lezwatchtv.com\/character\/van\/"}
This is a simplified version of my code, since in actuality I’m juggling a couple post types (shows or characters), and outputting more data (like if the character is dead or alive). It’s sufficient to prove this point.
Expirations
Okay. Now here’s the fun part. If you go to your JSON page now, it’ll show you a new character on every page reload, which is absolutely not what we want. We want this to only update once a day, so we can do this via Transients like this:
if ( false === ( $id = get_transient( 'lwtv_otd_character' ) ) ) { // Grab a random post $args = array( 'post_type' => 'post_type_characters', 'orderby' => 'rand', 'posts_per_page' =>'1', ); $post = new WP_Query( $args ); // Do the needful while ( $post->have_posts() ) { $post->the_post(); $id = get_the_ID(); } wp_reset_postdata(); set_transient( 'lwtv_otd_character', $id, DAY_IN_SECONDS ); }
But.
Expirations 2.0
Alright. Let’s do this differently. The server this is on has object caching, and it gets flushed every now and then. While it doesn’t matter if the post is re-randomizes in this case, it’s still not a great practice. So let’s use options!
// Grab the options $default = array ( 'character' => array( 'time' => strtotime( 'midnight tomorrow' ), 'post' => 'none', ), 'show' => array( 'time' => strtotime( 'midnight tomorrow' ), 'post' => 'none', ), ); $options = get_option( 'lwtv_otd', $default ); // If there's no ID or the timestamp has past, we need a new ID if ( $options[ $type ][ 'post' ] == 'none' || time() >= $options[ $type ][ 'time' ] ) { // Grab a random post $args = array( 'post_type' => 'post_type_characters', 'orderby' => 'rand', 'posts_per_page' =>'1', ); $post = new WP_Query( $args ); // Do the needful while ( $post->have_posts() ) { $post->the_post(); $id = get_the_ID(); } wp_reset_postdata(); // Update the options $options[ $type ][ 'post' ] = $id; $options[ $type ][ 'time' ] = strtotime( 'midnight tomorrow' ); update_option( 'lwtv_otd', $options ); }
And now you see my $type
variable and why it matters. There’s more magic involved in the real world, but it’s not relevant.