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.