WordPress Related Posts in 4 Easy Steps

Adding Related Posts to WordPress is a great way of keeping your users reading your site for a little longer. There are two ways to add a WordPress Related Posts section: installing a plugin or doing it yourself. I would use plugins for a lot of things but adding related posts is so easy that using a plugin feels like overkill. If you know how to tweak WordPress, doing it yourself will give you more control over the displayed posts and layout.

Tagging Posts

WordPress provides all the backbone we need to identify related posts: tags and categories. Tags describe a post in more detail than categories and are the most efficient way to find related posts in WordPress. However, pay attention to using meaningful tags and to write them correctly. Two posts won't be related if one is tagged "car" and the other one is tagged "cars". Tags are case-insensitive, so there is no need to worry about capitilizing. Tags may be several words long but be careful not to be too specific. Normally less than 10 tags per article are enough.

Use one or two-word tags that describe the post in more detail than its category already does. Which of your posts are similar? Why are they similar?

The problem: Related Posts vs Most Related Posts

A WordPress wp_query object allows to query the database for posts meeting certain criteria. In the case of tags, the tag__in parameter retrieves posts tagged with at least one of several provided tags. You do it from within the loop with code like the following:

$orig_post = $post;  
global $post;  
$tags = wp_get_post_tags($post->ID);  

if ($tags):
  $tag_ids = array();  
  foreach($tags as $individual_tag) $tag_ids[] = $individual_tag->term_id;  
  $args=array(  
    'tag__in' => $tag_ids,  
    'post__not_in' => array($post->ID),  
    'posts_per_page'=> 4 //number of posts to display
  );       
  $my_query = new wp_query( $args );
endif;

The problem with the code above is that the retrieved posts may not be that related. The database query using tag__in looks for all the articles with at least one tag in common with the current article, orders them by publish date and then takes the first four. Articles with just one tag in common may be retrieved while other articles with three or four common tags are left out. For example, here are the "related articles" I get for a "CSS Circles" article using tag__in:

WordPress Related Posts using tag__in

Three of the articles have only one tag in common. We don't want related posts, we want the most related posts. What we need is ordering the articles by number of matching tags and then take the first ones. There is no way to do this with wp_query, but the wpdb class allows to directly query the WordPress database using MySQL. With this approach the displayed posts have much better chances of being closely related to the topic. The related articles I get for the same "CSS Circles" article are now much more relevant:

WordPress Related Posts with direct query

WordPress Most Related Posts in 4 Steps

To implement a WordPress Related Posts section that displays the posts with the highest number of common tags follow the next steps:

  1. Choose or declare a thumbnail size. You'll probably want to show thumbnails like the ones above. Those are the posts' featured images. You'll have to add featured images to your posts if they don't already have. You don't want to display them in full size. Loading them will slow down your site and WordPress can do the resizing automatically. You can either use a WordPress default image size or define your own. By default, WordPress resizes every image to 150px x 150px, 300px x 300px max and 640px x 640px max. You can customize the sizes in Settings -> Media but then you'll have to regenerate your thumbnails (see next step).The cropping option is only offered for the 150px x 150px thumbnail (in Settings -> Media). Cropped images are shrinked to fit the shortest dimension and then the sides are cropped. If the image has the same aspect ratio as the thumbnail size, nothing is cropped. If cropping is off, images are always shown complete. However, you'll get shorter or narrower thumbnails for featured images that don't fit the aspect ratio. It will never happen if cropping is enabled.

    You can skip to the next step if you are happy with one of the default sizes and cropping setting. To enable cropping for the 300px x 300px image see Force crop to Medium size.

    If you want to define your own custom size, you can do it by adding the lines:

    add_theme_support( 'post-thumbnails' );
    add_image_size( 'related-thumb',240,240,true );

    to your theme's functions.php file. The first line should already be there if you are using featured images. Change the two numbers to the width and height (respectively) you'd like the thumbnails to have. Change the last parameter to false to turn off cropping.

  2. Regenerate your thumbnails. You'll have to do it unless you are using a default size without changing the cropping setting. When you change thumbnail sizes or declare your own, existing thumbnails are not regenerated. The Regenerate Thumbnails plugin will recreate them for you. The alternative is re-uploading each and every featured image, which is probably not an option.
  3. Add the following code to your themes single.php. Paste it where you want your related posts to appear, within The Loop:
    <!-- Related Posts -->
    <?php $orig_post = $post;  
    global $post;  
    $tags = wp_get_post_tags($post->ID);  
    
    if ($tags):
      $tag_ids = array();  
      foreach($tags as $individual_tag) $tag_ids[] = $individual_tag->term_id;
      $number_of_posts = 4; // number of posts to display
      $query = "
        SELECT ".$wpdb->posts.".*, COUNT(".$wpdb->posts.".ID) as q
        FROM ".$wpdb->posts." INNER JOIN ".$wpdb->term_relationships."
        ON (".$wpdb->posts.".ID = ".$wpdb->term_relationships.".object_id)
        WHERE ".$wpdb->posts.".ID NOT IN (".$post->ID.")
        AND ".$wpdb->term_relationships.".term_taxonomy_id IN (".implode(",",$tag_ids).")
        AND ".$wpdb->posts.".post_type = 'post'
        AND ".$wpdb->posts.".post_status = 'publish'
        GROUP BY ".$wpdb->posts.".ID
        ORDER BY q
        DESC LIMIT ".$number_of_posts."";
      $related_posts = $wpdb->get_results($query, OBJECT); 
      if($related_posts): ?>
        <div class="related-posts">  
          <h3>Related posts</h3> 
          <?php foreach($related_posts as $post): ?>
    	    <?php setup_postdata($post); ?>
            <div class="related-thumb">  
              <a href="<?php the_permalink()?>">
                <?php the_post_thumbnail('medium'); ?><br/>
                <?php the_title(); ?>
              </a>  
            </div>  
          <?php endforeach; ?>
        </div>
      <?php endif;
    endif;
    $post = $orig_post;  
    wp_reset_query(); ?>

    This code retrieves the most related posts by tag, from any category. Use the_post_thumbnail('my-custom-thumbnail-size') instead of the_post_thumbnail('medium') if you defined a custom thumbnail size. You may use 'thumbnail', 'medium', 'large' or 'full' as well. Use loop functions like the_excerpt(), the_author(), the_date() and the_category() to output more details.

    To narrow down and show only posts from the current post's category, you'd have to add a bit of PHP using wp_get_post_categories or wp_get_post_terms to get all the associated terms and add them to the term_taxonomy_id IN clause (categories and tags are roughly the same internally).

  4. Give Related Posts some style. You could start by adding the following CSS to your theme's style.css:
    .related-posts:after { /* clearfix */
       content: " "; 
       visibility: hidden;
       display: block;
       height: 0;
       clear: both;
    }
    .related-thumb {
    	width: 25%;
    	padding: 1%;
    	float: left;
    }
    .related-thumb a {
    	display: block;
    }
    .related-thumb img {
    	width: 100%;
        height: auto;
    }

    This CSS is for an ultra-simple layout like the one in the images above. Add your styles to make your WordPress related posts look great!

If you have any suggestions and/or questions, please leave them in the comments below. I'll be glad to answer and improve the article.

4 comments

Leave a Reply to Simran Maan Cancel reply

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>