How to show related posts on WordPress blog (no plugin)

In this article, you will learn how to create related posts under each WP post. I will show you how to write a custom WP query to pull the post titles and featured images. Then we will display them as related articles. All that without installing a plugin. Intrigued? Thought so!

Related posts increase page views

So why would you want to show related posts to your visitors anyway?
Showing related posts at the bottom of the article is an excellent way to keep visitors on your site, decrease bounce rate and increase page views. Depending on your goals, by increasing page views, you will likely get more conversions.
People will get more chances to click your affiliate link, see or click on the ads, sign up for the newsletter and so on. There are plenty of articles out there giving tips to increase page views and showing related posts is often one of them.

Why not use a plugin to display related posts

Using a plugin for displaying related posts on your WordPress blog is not a bad idea in general. There are plenty of plugins out there for that purpose. However, there are always drawbacks of using plugins, and you should try to avoid them when possible.
I already wrote about that when I showed you how to create HTML sitemap for WP without a plugin. Here is the list of potential problems when using a plugin to show related posts:

Extra CSS and Javascript file.
Because related posts are shown on front-end to your visitors, there has to be some styling applied to the final output. This means related posts plugin will likely enqueue new stylesheet and maybe even .js file. Every additional resource is an additional server request. By adding code that shows related posts yourself, you can easily add CSS to the existing CSS file – no new requests to the server necessary.

Poor coding.
You have to realize that plugin authors are humans after all. There could be coding errors that might cause problems to your site. If you install the plugin from WordPress plugin repository, you are reasonably safe. But if the plugin is not maintained regularly or even abandoned by the author, you might get into the problems sometime in the future when WordPress itself changes.

Slow queries.
To show related posts, there has to be a query that fetches all the necessary information from the WordPress database. A custom query that the plugin executes might not be fully optimized and could be slowing down your site as a result. In this tutorial, I will also include some tricks to make our query faster.

Fewer options.
One more problem with the query you “get” within a plugin is the fact you cannot choose between a lot of available WP_query Parameters to fully customize the output you get to your needs.

There are WordPress plugins out there that are indispensable, but showing related posts is a feature we can do on our own. If you don’t mind getting your hands dirty and you are familiar with WordPress file structure and the theme you are using, feel free to use the code below to create your related posts solution.

WP Related posts by tag

The tag is an awesome taxonomy that comes out of the box with WordPress. When used correctly it can help visitors navigate your site and find the information they need. Sometimes it is more useful to show related posts by tag because if you have broad categories, articles within the same category might not be as closely related as the ones tagged with the same tag.

Following is the PHP code you would want to use to fetch and display a couple of posts related to the current one with the same tag.

<?php 
global $post; // data from the current post in the WP loop 
$tags = wp_get_post_tags($post->ID); // list of tags for the current post
$tag_ids = array();
//loop through list of tags and store term_id of each
foreach($tags as $individual_tag) $tag_ids[] = $individual_tag->term_id; 
// build argument list for WP_Query
$args=array(
  'tag__in' => $tag_ids, //use tag ids that are within $tag_ids array
  'post__not_in' => array($post->ID), //don’t retrieve current post
  'post_type' => 'post', //specify post type to retrieve
  'post_status' => 'publish', //retrieve only published posts
  'posts_per_page' => 2, //specify number of related posts to show
  'orderby' => array( 'comment_count' => 'DESC'), //how you want to order your posts
  'no_found_rows' => true, //use for better query performance
  'cache_results' => false //use for better query performance
);
$query_related_posts = new WP_query( $args );?>

Code explained

What does the above code do?

We are using the global $post to retrieve the current post ID so we can fetch its tags. Later on, we are using that same ID to rule out the current post from WP_Query as we don’t want to show current post within related posts.
Within $args array we specify following parameters:
tag__in which is a parameter that specifies which tag ids to use in a query. Obviously, we want to query just the tag ids that has our current post.

post__not_in is a parameter which is used to ignore the array of post ids. In this situation, we only need to rule out current post id. There is a nice example how to gain performance improvements by replacing usage of post__not_in with PHP code but that applies more when you have a bigger array of ids to ignore.

post_type is a parameter we use to improve the performance by ruling out other post_types from WP_Query

post_status is another useful parameter as we only want query over published posts

posts_per_page is a parameter that defines how many posts to pull; you can put any number you like

orderby is an interesting parameter that allows you to specify how to order posts that are queried. In my example, I used comment_count and order in descending order. You might not want to do the same so here is the list of all orderby values you can use.

My idea was to show only the most popular posts to the users. However, using orderby comment_count might not necessary show the most viewed posts. For that purpose, I recommend this useful article that explains how to display popular posts by views.

One piece of advice is to avoid random ordering as that way the database usually loads all posts into memory and then randomly orders them. Finally, after that returns what you asked. That makes the query slower, and that lag increases with the total number of posts you got. So if you are interested in showing random related posts by tag on each article, you might want to think twice or try to come up with an alternative solution. One that comes to my mind is querying more posts that you intend to show and then pick a couple of them randomly using PHP. If you are interested in that solution, please comment below or contact me.

no_found_rows and cache_results are parameters used for better query performance. We are telling WordPress that we don’t need pagination when we set no_found_rows to true. With cache_results set to false, we are telling WordPress not to cache the results, and it sets both update_post_meta_cache and update_post_term_cache to cache. For more information on why and when to use these parameters, check out this article on that subject.

Related posts from the same category

If you are not using tags as a taxonomy to structure your content, you are definitely using categories. Because WordPress posts have to belong in a category, we can use that fact to serve related posts from the same category to visitors. For this, we need to make some tweaks in the WP_Query arguments we used above. Following is the code to query over posts within the same category as the current post:

<?php global $post; $cat = get_the_category($post->ID);<br?> 
$args=array(
  'category__in' => $cat[0],
  'post__not_in' => array($post->ID),
  'post_type' => 'post',
  'post_status' => 'publish',
  'posts_per_page' => 2,
  'orderby' => array('comment_count' => 'DESC'),
  'no_found_rows' => true,
  'cache_results' => false
);?>

The only difference here is that we use category__in parameter instead of the tag__in. To do that, we had to get the current category first. Using the function get_the_category(); That function returns Array of WP_Term objects, one for each category assigned to the post so I used $cat[0] as that key will exist for sure considering each post has to have at least one category. If you structured your WP posts differently, using multiple categories for your posts or parent-child categories you might want to tweak that further more.

Printing out featured images and titles of related posts
Finally, we need to print out related posts. First, we run the query with arguments we specified above for either related posts by tags or related by category. After that, it’s just a standard loop. While we have related posts we print out the thumbnail (featured image) and the post title. In my example below both are wrapped with anchor tag so the user can click on image or title to get the article. You can play around with this to show some extra information such as excerpt. At the end we use wp_reset_postdata(); as recommended after each custom WP_Query.

<?php $query_related_posts = new WP_query( $args ); 
while( $query_related_posts->have_posts() ) {
  $query_related_posts->the_post();
?>
  <a href="<?php the_permalink()?>">
  <?php the_post_thumbnail(); ?>
  <?php the_title(); ?>
  </a>
<?php
}
wp_reset_postdata(); ?>

Conclusion

That’s it, guys. I showed you how to use PHP with WP functions to create a custom WP_Query to pull related posts based on the tag or category, whichever you prefer. We discussed the reasons why you would want to avoid plugins for that task and how to optimize WP_Query for better performance. You can use that code directly within post template. To keep template files a bit more clean you can use the code within functions.php file or site-specific plugin. But in that case, you would need to use it within a custom function, hook it and fire it when you need it.

12 thoughts on “How to show related posts on WordPress blog (no plugin)”

  1. Hello,
    I’m a beginner in WorldPress.
    I’d like to show Related Posts.
    In the main menu I have Category A, and in Category A – Subcategories A, B and C. The posts are in Category A, but they can also be present in all 3 Subcategories.
    When choosing one of the Related Posts something goes wrong and the posts from the initially chosen Subcategory don’t show correct anymore.

    Reply
    • Hi, can you please give me some more info? Are you following this tutorial or you have your own way of showing the related posts? Maybe via plugin?

      Reply
    • Hello Luigi, sorry for the late reply, yes you can show posts which are within specified time, please check out the WP_Query docs

      Reply
  2. I’m looking for a way to show related posts by tag where the posts aren’t in a certain category.
    For example, if I’m on a page for my podcast, I’d want to show related blog types (category blog) but not posts from the podcast category. If I’m on a page for my blog, I’d want to show related posts in category podcast.

    Hopefully that makes sense.

    Is there an easy way to do that?

    Reply
    • Hello, if I understood correctly, you need to show related posts by the same tag the current post has. That is explained in the article, if you have further questions, please don’t hesitate to ask

      Reply
      • Actually, I meant posts with related tags, yes – but NOT in a certain category.
        So if I’m on a post page, I want to show related podcasts (category) with the same tags, but not more blog posts.
        If I’m on a podcast page, I want to show related blog posts (category) with related tags, but not more podcasts.

        Reply
        • Ah OK then, what you need I believe is to exclude the category of the current post/podcast using ‘category__not_in’

          You can grab the current category ID dynamically by using the get_the_category() function and passing the current post ID to it. If you need some extra help with the implementation, you can send me your contact via contact form.

          Reply
    • Hi Praba, of course it is possible to filter out by a custom post type. You just enter the desired value for the ‘post_type’ key. Hope it helps 😉

      Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.