preloader

How to Display Related Posts in WordPress Without a Plugin

If you want related posts in WordPress without the overhead of a plugin like Related Posts for WP, you can build a simple version directly in your theme templates. Here is how.

Basic Related Posts by Category

This code goes in single.php (or the relevant template for your theme) after the_content():

<?php
$categories = get_the_category( get_the_ID() );

if ( ! empty( $categories ) ) {
    $category_ids = wp_list_pluck( $categories, 'term_id' );

    $related_args = array(
        'category__in'        => $category_ids,
        'post__not_in'        => array( get_the_ID() ),
        'posts_per_page'      => 3,
        'ignore_sticky_posts' => true,
        'orderby'             => 'rand',
    );

    $related_query = new WP_Query( $related_args );

    if ( $related_query->have_posts() ) :
        echo '<div class="related-posts">';
        echo '<h3>Related Articles</h3>';
        echo '<ul>';
        while ( $related_query->have_posts() ) :
            $related_query->the_post();
            printf(
                '<li><a href="%s">%s</a></li>',
                esc_url( get_permalink() ),
                esc_html( get_the_title() )
            );
        endwhile;
        echo '</ul></div>';
        wp_reset_postdata();
    endif;
}
?>

Related Posts by Tags

Replace the category query with a tag query:

$tags = get_the_tags( get_the_ID() );

if ( ! empty( $tags ) ) {
    $tag_ids = wp_list_pluck( $tags, 'term_id' );

    $related_args = array(
        'tag__in'             => $tag_ids,
        'post__not_in'        => array( get_the_ID() ),
        'posts_per_page'      => 3,
        'ignore_sticky_posts' => true,
    );
    // ... rest of the query
}

Adding Transient Caching

Related post queries run on every single post page load. On high-traffic sites, this adds significant database load. Cache the results using WordPress transients:

<?php
$post_id         = get_the_ID();
$transient_key   = 'related_posts_' . $post_id;
$related_posts   = get_transient( $transient_key );

if ( false === $related_posts ) {
    $categories    = get_the_category( $post_id );
    $category_ids  = wp_list_pluck( $categories, 'term_id' );

    $related_query = new WP_Query( array(
        'category__in'   => $category_ids,
        'post__not_in'   => array( $post_id ),
        'posts_per_page' => 3,
        'fields'         => 'ids', // Only retrieve IDs for caching
    ) );

    $related_posts = $related_query->posts;
    set_transient( $transient_key, $related_posts, DAY_IN_SECONDS );
    wp_reset_postdata();
}

if ( ! empty( $related_posts ) ) {
    echo '<div class="related-posts"><h3>Related Articles</h3><ul>';
    foreach ( $related_posts as $post_id ) {
        printf(
            '<li><a href="%s">%s</a></li>',
            esc_url( get_permalink( $post_id ) ),
            esc_html( get_the_title( $post_id ) )
        );
    }
    echo '</ul></div>';
}
?>

The transient stores related post IDs for 24 hours, so the database query runs at most once per day per post rather than on every page view.

When to Use a Plugin Instead

This manual approach works well for simple related posts by category or tag. Use a dedicated plugin like Related Posts for WP when you need: matching across multiple taxonomies simultaneously, a more sophisticated relevance algorithm, a visual management interface, or RSS feed related posts. The plugin also handles edge cases (no matching posts, recently published posts without taxonomy terms) more gracefully than a basic custom query.

For custom related post implementations using machine learning similarity, custom post type support, or integration with search engines like ElasticSearch, a WordPress developer can build a tailored solution.

Keep Reading

Previous Post Removing and Re-applying Watermarks in WordPress: What Is Possible Next Post Internal Linking Strategy: Getting the Most From Related Posts

Need Help With Your WordPress Site?

If you need help with WordPress fixes, plugin issues, theme customization, or development work, feel free to get in touch.

Get a Free Estimate