Get random custom-post-type post to display within content

As already pointed out, random ordering and searching is quite expensive operations to run, so lets look at how we are going to sort that issue.

Because you only need one post from your custom post type, we only need one random ID which we can pass to get_post() in order to get the desired post. Instead of getting the post randomly from the db, we will query all custom post types (or at least all the post ID’s), save that into a transient, and then we can just pick a random ID from that option.

Lets look at some code: (This goes into functions.php)

function get_random_id( $post_type="" )
{
    $q = [];

    // Make sure we have a post type set, check if it exists and sanitize
    $post_type = filter_var( $post_type, FILTER_SANITIZE_STRING );

    if ( !$post_type ) 
        return $q;

    if ( !post_type_exists( $post_type ) )
        return $q;

    // The post type exist and is valid, lets continue
    $transient_name="rand_ids_" . md5( $post_type );

    // Get the transient, if we have one already
    if ( false === ( $q = get_transient ( $transient_name ) ) ) {
        $args = [ 
            'post_type'      => $post_type,
            'posts_per_page' => -1,
            'fields'         => 'ids', // get only post ID's
            // Add any additional arguments
        ];
        $q = get_posts( $args );

        // Set the transient
        set_transient( $transient_name, $q, 30*DAY_IN_SECONDS );    
    } // endif get_transient

    return $q;
}       

What we have done, we have now saved all custom post type ids into a transient. This will increase performance by a huge amount. The transient is set for 30 days, so we need to flush and recreate the transient as soon as we publish a new custom post type post.

Lets use the transition_post_status action hook: (This goes into functions.php)

add_action( 'transition_post_status', function ( $new_status, $old_status, $post )
{
    // Make sure we only target our specific post type
    if ( 'advertising' !== $post->post_type )
        return;

    global $wpdb;

    // Delete the transients
    $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient%_rand_ids_%')" );
    $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient_timeout%_rand_ids_%')" );

    // Lets rebuild the transient
    get_random_id( $post->post_type );

}, 10, 3 );

All we are left with is to get a random post ID from our get_random_id() function and pass that to get_post() to get the post object

// Get the array of post ID's
$post_type_posts = get_random_id( 'advertising' );
// Make sure we have posts
if ( $post_type_posts ) {
    // Get the post object of the id first in line
    shuffle( $post_type_posts );
    $single_post = get_post( $post_type_posts[0] );
    // Display the post content
}

This way you save a lot on resources and is much faster than just simply let SQL choose a random post from the DB

Just as example, your advert injector filter can look something like the following

add_filter( 'the_content', 'prefix_insert_post_ads' );
function prefix_insert_post_ads( $content ) {

    // checkbox to show ad, default true
    if ( get_field('show_advertisement') ) {
        if (     is_single() && 
               ! is_admin() 
        ) {
            // Get the array of post ID's
            $post_type_posts = get_random_id( 'advertising' );
            // Make sure we have posts
            if ( $post_type_posts ) {
                // Get the post object of the id first in line
                shuffle( $post_type_posts );
                $random_ad = get_post( $post_type_posts[0] );

                // Display the post content
                $link = addhttp( get_field('advertisement_link', $random_ad->ID));
                $image = get_field('upload_advertisement', $random_ad->ID);
                // get html
                $ad_code="<a href="".$link.'" target="_blank"><img src="'.$image.'" /></a>';
                // show ad after # paragraphs
                $show_after = get_field('advertisement_show_after');
                // return appended $content
                return prefix_insert_after_paragraph( $ad_code, $show_after, $content );

            } 
        }
    } 
    return $content;
}

Leave a Comment