WordPress Tutorials

Add Related Posts in WordPress Without a Plugin

Every visitor who finishes an article faces the same choice: leave your site or read one more post. A related posts section makes the second choice easy by showing a small set of relevant articles exactly where the reader is most engaged. Most tutorials solve this with a plugin, but plugins add weight, upsell banners, and one more dependency to keep updated. A short code snippet built on WP_Query gives you the same result with full control and zero bloat, and it takes less than fifteen minutes to set up. This guide shows you how to add related posts by category and tag, where to place the code safely, how to style the output, and how to keep it fast, all without installing a plugin.

Why Do Related Posts Matter for Your Site?

Related posts are one of the simplest engagement tools a blog can have. When a reader finishes an article and sees three relevant titles below it, the chance they click through is far higher than the chance they scroll back up or wander to your menu. That second pageview lowers your bounce rate and increases time on site, two signals search engines associate with satisfying content. Related posts also weave your articles together with contextual internal links, which helps crawlers discover newer posts faster. If your posts are not organized consistently yet, our comparison of WordPress categories versus tags will get your taxonomy in shape before you start.

  • Lower bounce rate. Readers who click a related post stay inside your content instead of leaving after one page.
  • Stronger internal linking. Every related posts block adds contextual links between articles that genuinely belong together.
  • Faster discovery. New posts get surfaced next to older popular ones automatically, with no manual linking work.
  • No plugin overhead. A short snippet replaces a plugin that needs updates and may inject ads or tracking into your pages.

Where Should the Code Go?

You have two safe homes for the snippet below. The first is your child theme’s functions.php file, which keeps your changes separate from the parent theme so updates never wipe them out. If you do not have a child theme yet, follow our guide on how to create a WordPress child theme first. The second option is the free Code Snippets plugin, which stores each snippet in the database and runs it independently of any theme, with a simple on and off toggle per snippet. Both options work for everything in this guide. Never paste the code into the parent theme’s functions.php, because the next theme update will delete that file and your related posts section will silently disappear.

How Do I Add Related Posts by Category and Tag? (Method 1)

This is the main method and the one most sites should use. It queries posts that share at least one category or tag with the current post, excludes the current post itself, and prints a small grid after the article content. Paste this into Code Snippets as a PHP snippet set to run everywhere, or into your child theme’s functions.php:

function vut_related_posts( $post_id = 0 ) {
    if ( ! $post_id ) {
        $post_id = get_the_ID();
    }
    $categories = wp_get_post_categories( $post_id );
    $tags       = wp_get_post_tags( $post_id, array( 'fields' => 'ids' ) );
    if ( empty( $categories ) && empty( $tags ) ) {
        return;
    }
    $args = array(
        'post_type'           => 'post',
        'posts_per_page'      => 3,
        'post__not_in'        => array( $post_id ),
        'ignore_sticky_posts' => true,
        'tax_query'           => array(
            'relation' => 'OR',
            array(
                'taxonomy' => 'category',
                'field'    => 'term_id',
                'terms'    => $categories,
            ),
            array(
                'taxonomy' => 'post_tag',
                'field'    => 'term_id',
                'terms'    => $tags,
            ),
        ),
    );
    $related = new WP_Query( $args );
    if ( $related->have_posts() ) {
        echo '<div class="vut-related-posts">';
        echo '<h3>You may also like</h3>';
        echo '<div class="vut-related-grid">';
        while ( $related->have_posts() ) {
            $related->the_post();
            echo '<article class="vut-related-card">';
            if ( has_post_thumbnail() ) {
                echo '<a href="' . esc_url( get_permalink() ) . '">';
                the_post_thumbnail( 'medium' );
                echo '</a>';
            }
            echo '<h4><a href="' . esc_url( get_permalink() ) . '">' . esc_html( get_the_title() ) . '</a></h4>';
            echo '</article>';
        }
        echo '</div></div>';
        wp_reset_postdata();
    }
}
add_filter( 'the_content', 'vut_append_related_posts' );
function vut_append_related_posts( $content ) {
    if ( is_single() && is_main_query() && in_the_loop() ) {
        ob_start();
        vut_related_posts();
        $content .= ob_get_clean();
    }
    return $content;
}

What Does This Code Do, Step by Step?

The function first grabs the current post ID, then collects its categories and tags. If the post has neither, it returns silently so nothing breaks on uncategorized posts. The WP_Query arguments ask for three published posts that share at least one category OR one tag with the current post, exclude the current post from the results, and ignore sticky posts so a pinned announcement does not always win the slot. The loop then prints each related post as a small card with its featured image and title, and wp_reset_postdata() restores the original post data so the rest of the page keeps working normally. Finally, the the_content filter appends the whole section after the article body, but only on single post pages inside the main loop, so archive and home pages stay untouched. The WP_Query documentation lists every parameter you can tweak if you want to fine tune the query later.

How Do I Show Related Posts by Tag Only? (Method 2)

Matching by category and tag works well for most blogs, but on sites where categories are broad, like a Tutorials category holding hundreds of posts, category matches can feel loosely related. Matching by tag only gives tighter, more topical recommendations because tags describe the specific subject of each post. Swap the query arguments for this simpler version:

$tags = wp_get_post_tags( $post_id, array( 'fields' => 'ids' ) );
if ( empty( $tags ) ) {
    return;
}
$args = array(
    'post_type'      => 'post',
    'posts_per_page' => 4,
    'post__not_in'   => array( $post_id ),
    'tag__in'        => $tags,
);

Replace the $args block in Method 1 with this and keep everything else the same, including the output loop and the the_content filter. Four posts work better here because tag matches tend to be more relevant, so showing one extra card rarely feels like filler. If your tags are thin or inconsistent, stick with Method 1, since it falls back to category matches when tags are missing.

How Do I Place Related Posts Manually?

The filter in Method 1 appends related posts to the end of the post content automatically, which is the best spot for engagement. If you would rather control the exact position, remove the add_filter block at the bottom of the snippet and call the function directly in your single.php template where you want the section to appear:

<?php
if ( function_exists( 'vut_related_posts' ) ) {
    vut_related_posts();
}
?>

Place the call after the content output and before the comments template for the classic below the article layout. Wrapping the call in function_exists() keeps your theme safe if the snippet is ever deactivated.

How Do I Style the Related Posts Section?

Without styling, the output is a plain list of linked titles. This CSS turns it into a clean three column card grid that matches most modern themes. Add it under Appearance, then Customize, then Additional CSS. If you have never added CSS this way, our guide on adding custom CSS in WordPress walks through the options:

.vut-related-posts {
    margin: 3rem 0;
    padding-top: 2rem;
    border-top: 1px solid #eee;
}
.vut-related-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
}
.vut-related-card {
    background: #fff;
    border: 1px solid #eee;
    border-radius: 12px;
    overflow: hidden;
}
.vut-related-card img {
    width: 100%;
    height: auto;
    display: block;
}
.vut-related-card h4 {
    font-size: 1rem;
    margin: 1rem;
}
@media (max-width: 768px) {
    .vut-related-grid {
        grid-template-columns: 1fr;
    }
}

The cards collapse to a single column on phones, the featured images scale to the card width, and the top border visually separates the section from the article. Adjust the border radius, gap, and heading size to match your theme, and consider adding a subtle hover effect on the card titles if your theme supports it.

Will Related Posts Slow Down My Site?

A single query for three posts is cheap and adds only a few milliseconds on most sites. Two things could make it expensive: running it on archive pages, which our snippet avoids by checking is_single(), and running it on very large sites where taxonomy queries scan thousands of posts. For larger sites, cache the result with a transient so the query runs once and the rendered HTML is reused for hours:

$cache_key = 'vut_related_' . $post_id;
$output = get_transient( $cache_key );
if ( false === $output ) {
    ob_start();
    vut_related_posts( $post_id );
    $output = ob_get_clean();
    set_transient( $cache_key, $output, 12 * HOUR_IN_SECONDS );
}
echo $output;

Pair this with a small hook that deletes the transient whenever a post is saved, so updated titles and thumbnails appear promptly. In practice, related posts are rarely the reason a site feels slow. If your pages are sluggish overall, the bottleneck is usually the server or an overloaded theme, so read our guide on why a WordPress site gets slow to find the real cause, and check our web hosting guide to make sure your plan has enough headroom for a growing blog.

Frequently Asked Questions

Do I need a child theme for this related posts code?

No. The Code Snippets plugin is the easiest option because it stores the code in the database and survives theme updates, and each snippet has its own on and off toggle. Use a child theme if you already maintain one and prefer keeping all customizations in files.

How many related posts should I show?

Three or four is the sweet spot. Fewer than three looks empty, and more than four pushes the section far down the page where fewer readers scroll. Quality matters more than quantity: three genuinely relevant posts outperform six loosely related ones.

Can I exclude a specific category from related posts?

Yes. Add a category__not_in parameter to the query arguments with the IDs of the categories you want to skip, for example announcements or sponsored posts. The excluded posts simply never appear in the results.

Will this work with custom post types?

Yes. Change post_type in the arguments to your custom post type slug, and make sure that post type supports the taxonomies you match against. For WooCommerce products, you would match against the product_cat taxonomy instead of the default categories.

Last updated: October 2026.

Hostinger - Get 20% OFF

Habib ur Rehman

Hello! I'm the founder of VU Tech Geek. As a BSCS graduate and experienced WordPress professional, I'm passionate about technology and education. My Virtual University journey has given me valuable insights and knowledge, which I love to share with fellow students.… More »

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button

Adblock Detected

Please consider supporting us by disabling your ad blocker