[EDIT: See my comment below, I may have been fooled by Chrome caching an earlier version of this code. It now seems to run quite quickly. Leaving the question up in case anyone sees a better way but don't worry too much about it if not - I'll close this out in a couple of days.]

Many people have posted code like this to show 'related posts' in the sidebar, and I've adapted it into a shortcode. It works, but takes 1-2 seconds to load on localhost. I can add in transient caching but given it's a per-post type query that's not going to help a ton (I don't think?). Is there a more efficient way to write this?

// Shows posts in the same sub-category as the current post
// usage: [related_posts posts="5"]
add_shortcode( 'related_posts', 'mkm_related_posts_shortcode' );
function mkm_related_posts_shortcode( $atts ) {

    $current_post_id = get_queried_object_id();

    // define attributes and their defaults
    extract( shortcode_atts( array (
        'type' => 'post',
        'order' => 'asc',
        'orderby' => 'menu_order',
        'posts' => '3',
    ), $atts ) );

    $categories = get_the_category($current_post_id);
    if ($categories) {
        $category_ids = array();

        foreach($categories as $individual_category) {
            // looking only for current sub-categories
            if ( $individual_category->parent !== 0 ) {
                $category_ids[] = $individual_category->term_id;

        $options = array(
            'post_type' => $type,
            'order' => $order,
            'orderby' => $orderby,
            'posts_per_page' => $posts,
            'category__in' => $category_ids,
            'post__not_in' => array($current_post_id),

        $related_query = new WP_Query( $options );

    $output = '';
    // run the loop based on the query
    if ( $related_query->have_posts() ) { 
        $alttext = the_title_attribute('echo=0');
        $output .= '<ul>';
        while ( $related_query->have_posts() ) { 
            $output .= '<li>';
            $output .= '<h5 class="related-title"><a href="' . get_permalink() . '">' . get_the_title() . '</a></h5>';

            if( has_post_thumbnail($related_query->post->ID) ) { 
                $output .= '<a href="' . get_permalink() . '">' . get_the_post_thumbnail($related_query->post->ID, 'tiny-thumb', array( 'alt' =>  $alttext )) . '</a>';

            $output .= '</li>';
        $output .= '</ul>';

    return $output;


  • Where exactly are you using this? – Pieter Goosen Oct 30 '14 at 16:43
  • OK wow! the code was in a "plugin", basically my shortcodes copied into a plugin.php file so they wouldn't be in functions.php. When I saw your question, I tried moving the code into functions.php & it seemed to speed up enormously (Debug Queries still gave same result, but sidebar seems to load instantly now). Moved it back to the plugin, and same - still faster experience. I may have been fooled by Chrome caching an earlier version that was throwing PHP notices?? (If you mean where do I call the shortcode, it's in Black Studio's TinyMCE widget in the sidebar of a single post page.) – Michelle Oct 30 '14 at 17:29
  • 1
    Creating a Widget instead of utilizing a shortcode for this functionality would be beneficial. – Nicolai Oct 30 '14 at 17:41
  • 1
    @ialocin My client isn't sure if they want this in the sidebar or after the post content, thus the shortcode. Out of curiosity, why would a widget be beneficial? would that render faster than a shortcode? – Michelle Oct 30 '14 at 18:11
  • 1
    Ok, I see. Not necessarily, but a widget would render faster than a shortcode in a widget, just because it is immediate without detour via the shortcode API. – Nicolai Oct 30 '14 at 19:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.