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 funcyions.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 funcyions.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;
}