Show Related Posts with Thumbnails in Genesis

I looked into a lot of related posts plugins for my personal blog, then remembered, I’m a theme developer, I bet I could write a very simple related posts script myself. The code I ended up using only takes 2 things into account, what tag is the post using and what category is it in. I try to take time to use tags that my posts can share to group them. For example, this post is using GenesisWP and QuickTips. If you click on those tag archives you will get posts related to this one. I also use categories as a larger grouping.

genesis related posts

The way my script works is pretty simple. First, it finds the tags a post is assigned to then tries to find other posts using that same tag. If it gets enough posts, it stops. Otherwise it checks the category for more posts to finish out the total number of related posts I’m going to show. The total code overhead is pretty minimal, and because of the way I use tags and categories, it does a very good job of building the related posts.

Interested in trying it? Here are some simple steps to get it up and running on your site.

Add Image Size

Since this code shows images, not just text, you need to add a line of code to your functions.php file to make the image size. I went with 90×70 and my CSS will work with that size, but if you are using different layouts or otherwise need to adjust this image size, do it now. Just put this code in the functions.php with any other add_image_size() functions or after this line, require_once( get_template_directory() . ‘/lib/init.php’ );, if there are no other add_image_size() functions.

add_image_size( 'related', 90, 70, true );

Remember, any time you add or change image sizes, you should run the regenerate thumbnails plugin to rebuild the images with that image size.

PHP Magic: The Related Posts Code

While you have the functions.php file open, you need to add some more code.

Since this is a quick tip, I’m not going to explain all of this line by line. This code does all the magic. On my site I load it on the genesis_after_post_content hook, but you could use any other hook. Since this works via tags and categories, I don’t let it load on pages or in archives, so it only runs if( is_single() ). For my site I don’t add images to certain post formats, so you will also see that it skips the link, status, aside, and quote post formats. All of this can be edited to your particular needs.

//for XHTML themes
add_action( 'genesis_after_post_content', 'child_related_posts' );
//for HTML5 themes
add_action( 'genesis_after_entry_content', 'child_related_posts' );
/**
 * Outputs related posts with thumbnail
 * 
 * @author Nick the Geek
 * @url http://designsbynickthegeek.com/tutorials/related-posts-genesis
 * @global object $post 
 */
function child_related_posts() {
    
    if ( is_single ( ) ) {
        
        global $post;

        $count = 0;
        $postIDs = array( $post->ID );
        $related = '';
        $tags = wp_get_post_tags( $post->ID );
        $cats = wp_get_post_categories( $post->ID );
        
        if ( $tags ) {
            
            foreach ( $tags as $tag ) {
                
                $tagID[] = $tag->term_id;
                
            }
            
            $args = array(
                'tag__in'               => $tagID,
                'post__not_in'          => $postIDs,
                'showposts'             => 5,
                'ignore_sticky_posts'   => 1,
                'tax_query'             => array(
                    array(
                                        'taxonomy'  => 'post_format',
                                        'field'     => 'slug',
                                        'terms'     => array( 
                                            'post-format-link', 
                                            'post-format-status', 
                                            'post-format-aside', 
                                            'post-format-quote' 
                                            ),
                                        'operator'  => 'NOT IN'
                    )
                )
            );

            $tag_query = new WP_Query( $args );
            
            if ( $tag_query->have_posts() ) {
                
                while ( $tag_query->have_posts() ) {
                    
                    $tag_query->the_post();

                    $img = genesis_get_image() ? genesis_get_image( array( 'size' => 'related' ) ) : '<img src="' . get_bloginfo( 'stylesheet_directory' ) . '/images/related.png" alt="' . get_the_title() . '" />';

                    $related .= '<li><a href="' . get_permalink() . '" rel="bookmark" title="Permanent Link to' . get_the_title() . '">' . $img . get_the_title() . '</a></li>';
                    
                    $postIDs[] = $post->ID;

                    $count++;
                }
            }
        }

        if ( $count <= 4 ) {
            
            $catIDs = array( );

            foreach ( $cats as $cat ) {
                
                if ( 3 == $cat )
                    continue;
                $catIDs[] = $cat;
                
            }
            
            $showposts = 5 - $count;

            $args = array(
                'category__in'          => $catIDs,
                'post__not_in'          => $postIDs,
                'showposts'             => $showposts,
                'ignore_sticky_posts'   => 1,
                'orderby'               => 'rand',
                'tax_query'             => array(
                                    array(
                                        'taxonomy'  => 'post_format',
                                        'field'     => 'slug',
                                        'terms'     => array( 
                                            'post-format-link', 
                                            'post-format-status', 
                                            'post-format-aside', 
                                            'post-format-quote' ),
                                        'operator' => 'NOT IN'
                                    )
                )
            );

            $cat_query = new WP_Query( $args );
            
            if ( $cat_query->have_posts() ) {
                
                while ( $cat_query->have_posts() ) {
                    
                    $cat_query->the_post();

                    $img = genesis_get_image() ? genesis_get_image( array( 'size' => 'related' ) ) : '<img src="' . get_bloginfo( 'stylesheet_directory' ) . '/images/related.png" alt="' . get_the_title() . '" />';

                    $related .= '<li><a href="' . get_permalink() . '" rel="bookmark" title="Permanent Link to' . get_the_title() . '">' . $img . get_the_title() . '</a></li>';
                }
            }
        }

        if ( $related ) {
            
            printf( '<div class="related-posts"><h3 class="related-title">Related Posts</h3><ul class="related-list">%s</ul></div>', $related );
        
        }
        
        wp_reset_query();
        
    }
}

Make a Default Image

My personal site was on blogger ages ago. Shhh, don’t tell anyone. There have also been a few issues that came up with a server move and a hack I had to recover from. Also, I used a theme that inserted the thumbnail using a custom field. All of this means that several of my posts don’t have an image attached/set as featured. When I get bored I use a special page template that shows me what posts still need an image, but in the interim I have a custom default image that gets shown in my related posts when the post doesn’t have an image.

To use the default image, make an image in the same size as the add_image_size for the related posts. If you aren’t editing my code it will be 90×70. Save the file as related.png and upload it to the child theme images directory.

Oh, and if you just want to use the default image I’m using on my site, you can save the image on the left.

Style it

If you just add this code as is without any CSS, well you are going to get a rather interesting looking list of images. You need to apply CSS rules to change it into a row of images with even spacing. If your site isn’t using Tapestry, or if you have made big changes to Tapestry, you will need to edit this for sure. If you are using a different image size, you will need to edit it. This CSS is for my site, so don’t blindly copy code, use this as a template for your own custom related posts.

Now that you’ve read my disclaimer and turned your brain on. Open your style sheet and add this, the bottom of the file usually works fine unless there is an error in your CSS

/************ Related Posts *************/
.related-posts {
    overflow: hidden;
    margin: 0 0 10px;
}

.related-list li {
  float: left;
  list-style-type: none;
  margin: 0 10px 0 0;
  text-align: center;
  width: 105px;
}

.related-list img {
  background: none repeat scroll 0 0 #6FA1B1;
  border: 2px solid #2B5D6C;
  display: block;
  margin: 0 auto;
  padding: 5px;
}

Why use code I have to edit for my site?

In the beginning of this post I mentioned that I looked at several Related Post type plugins. Some work similarly to this code, and quite frankly some probably are much much easier to setup. They might have a way to upload a default image or work with custom fields for those old posts still using custom fields. They might use other methods of finding related posts, and you may not have to do any CSS edits. Most importantly, you don’t have to do any custom coding.

Those are all good reasons to use a plugin, and I used the Yet Another Related Posts plugin for ages for those same reasons. Then I wanted images, and the plugin didn’t support images. The ones I started testing were good, but all those options mean extra code overhead. Hard coding the default image, CSS, and using a really simple set of queries to get the related posts means a lot less code every time my page loads.

That’s the thing about programing. The easier something is to use, that more work it takes.

This code isn’t for everyone. If you looked at my statement “I’m not going to explain every single line” and thought about closing the page, this approach probably isn’t for you. If you want to make a ton of changes to the code but the CSS seems really complex, this probably isn’t for you. If you are willing to break things, then figure out why it broke as you get it working exactly like you want on your site, then use this code as a base for your own custom solution.

Comments

  1. Nice Nick! Now turn it into a configurable plugin ;) He He.

    • It’s on my list. Not high on the list because there are a lot of good plugins out there for this already, so it may never happen, but Genesis Related Posts is on my list :D

  2. What about if i want to show related posts using category only?

    • The simple solution is to remove the tags query

      if ( $tags ) {
       
                  foreach ( $tags as $tag ) {
       
                      $tagID[] = $tag->term_id;
       
                  }
       
                  $args = array(
                      'tag__in'               => $tagID,
                      'post__not_in'          => $postIDs,
                      'showposts'             => 5,
                      'ignore_sticky_posts'   => 1,
                      'tax_query'             => array(
                          array(
                                              'taxonomy'  => 'post_format',
                                              'field'     => 'slug',
                                              'terms'     => array(
                                                  'post-format-link',
                                                  'post-format-status',
                                                  'post-format-aside',
                                                  'post-format-quote'
                                                  ),
                                              'operator'  => 'NOT IN'
                          )
                      )
                  );
       
                  $tag_query = new WP_Query( $args );
       
                  if ( $tag_query->have_posts() ) {
       
                      while ( $tag_query->have_posts() ) {
       
                          $tag_query->the_post();
       
                          $img = genesis_get_image() ? genesis_get_image( array( 'size' => 'related' ) ) : '<img src="' . get_bloginfo( 'stylesheet_directory' ) . '/images/related.png" alt="' . get_the_title() . '" />';
       
                          $related .= '<li><a href="' . get_permalink() . '" rel="bookmark" title="Permanent Link to' . get_the_title() . '">' . $img . get_the_title() . '</a></li>';
       
                          $postIDs[] = $post->ID;
       
                          $count++;
                      }
                  }
              }
      

      Technically you can clean up the code a bit more, but that should make it run on just categories

  3. Thanks..that would be of great help..looking forward for more tutorials..:)

  4. Hi Nick!
    Thanx for this! I am begging and searching for such a functionality in Genesis for a long time!
    I’ve tested this code within a theme (functions.php) and worked like a charm – but put into a plugin it gets not loaded.

    I would be the most happy if you could make this into a little plugin real soon – or just tell me what I have to do to make your code plugin-able.

    THANX!
    -Dave :)

    • Like I said to Jennifer, it is on my list, I’ll probably package it with the previous/next post navigation I’m using and maybe a simple “related posts” widget. First, I’ll be updating all of my plugins then working on some other projects. Theoretically the code should be pretty much plugin ready now though, it just needs to have an options page built and the options added.

  5. I subscribed to your email list a few days or so ago and it’s great getting these little tips in my inbox. I’m learning PHP and WordPress/Genesis development simultaneously and these clear, simple solutions to what I sometimes think is going to be a complex problem are a tremendous learning assist. Keep up the great work.

  6. Hi Nick! I’m working on a test site and just set this up. Everything is great. The only problem I’m having is styling the link titles. I tried using this code and nothing happens.

    .related-posts a,
    .related-posts a:link,
    .related-posts a:visited, {
    color:#666;
    }
    

    Any suggestions?

    Thank you,
    -Angela

    • The issue is going to be the existing CSS overriding what you are doing. First, move your code to the end of the file if it isn’t already. If the CSS rules have the same specificity, the code that loads last takes precedence. If that doesn’t fix it (make sure you do a hard refresh to see the rules updated. Reload your page with ctrl+f5) then you need to make your rule more specific. The short cut is to add #content to your rules like #content .related-posts a, …. Do another hard refresh and if it still isn’t working you need to get more specific again. Though at this point, you should probably use FireBug to find out why the color isn’t changing. The other rule is either too specific, or is using !important. In either case it should be fixed.

  7. Thank you :) works perfectly/

  8. Wonderful! Thanks so much ! Ive read that related posts plugins can really slow down a site- this is just what I needed

  9. Is it better to use the related posts code with Simple Hooks plugin or by editing functions.php file directly? Or there is no difference?

  10. Hi Nick,
    Great Tut! Really love it!
    With a simple change you can make it even better. Getting related posts at random! This will give more variation in the output (otherwise old posts will never pop up).
    To get related posts ad random, just add this to the $args array:

    'orderby'		=> rand,

    Like this.

    $args = array(
                    'tag__in'               => $tagID,
                    'post__not_in'          => $postIDs,
                    'showposts'             => 5,
                    'ignore_sticky_posts'   => 1,
    		'orderby'		=> rand,
                    'tax_query'             => array(
                        array(
                                            'taxonomy'  => 'post_format',
                                            'field'     => 'slug',
                                            'terms'     => array(
                                                'post-format-link',
                                                'post-format-status',
                                                'post-format-aside',
                                                'post-format-quote'
                                                ),
                                            'operator'  => 'NOT IN'
                        )
                    )
                );
    
  11. Hi
    i loved your widget.
    how can i add this in my blogger blog. please help
    i shall be thankful
    regards

  12. Check my site please… I have placed the code correctly but its not working for me…

  13. Hi,

    If somebody has successfully added custom post type support to this snippet I would highly appreciate a heads up!

    Many thanks in advance!
    Thomas

    • Honestly, it would require some important changes, not just the post type. This works with tags, so either the post type would need to support tags, or you would need another taxonomy change too.

  14. Thank you!
    Works very good :D

  15. thanks for the code works well just a few adjustments the css and up and running. thanks again for your coding efforts.

  16. Hello
    this is awesome, i am using this in one of my genesis theme, please tell the method of Next and Previous Post Links with images

  17. Hello, Thanks for the codes. It works Great.

  18. Great, I am a newbie to genesis framework and this code help me a lot.

    Thanks for this code.

  19. vajrasar says:

    Nick, Great Work ! It would be a great help, if you can tell me how to integrate navigation to it. I mean like buttons of left and right side for more related posts.

    Thanks.

  20. I tried the code and it worked well.
    I’d like to remove the post title from under the image and use it as the image title.
    That way, you only see the thumbnail but when you hover over the image you then get the post title. I’ve messed around with it a bunch but I can’t seem to figure it out.

    • This line shows up twice and is what builds the actual image links

       $related .= '<li><a href="' . get_permalink() . '" rel="bookmark" title="Permanent Link to' . get_the_title() . '">' . $img . get_the_title() . '</a></li>';
      

      You can make this edit

       $related .= '<li><a href="' . get_permalink() . '" rel="bookmark" title="Permanent Link to' . get_the_title() . '">' . $img .  '</a></li>';
      

      You might want to remove the “Permanent Link to” portion as well.

      • Thanks, that removed the title below but I’m still having trouble changing the image title. I want the title attribute of the image to be the post title, not the image file name.
        That way, when you hover over the image, you know what the post title is for that image.

        • set your title attr to ” like this

                              $img = genesis_get_image() ? genesis_get_image( array( 'size' => 'related', 'attr' => array( 'title' => '' ) ) ) : '<img src="' . get_bloginfo( 'stylesheet_directory' ) . '/images/related.png" alt="' . get_the_title() . '" />';
          

          This code already sets the title for the <a> tag, so if you clear the title attr for the image you are done.

          • Thank you so much. I like not having to use plugins for everything. You rock.

          • Hi! I tried this above and it doesn’t work. The post title will only appear over the posts that show a default image (no actual image in the post). When I mouse over the posts that have a featured image it shows absolutely nothing. If I remove the code above and set it back to the original actions, when I mouse over the posts that have a featured image, it shows the title of the image – not the title of the post.

  21. I forgot to post a link.
    You can see it in action at my test site here:

    http://photographaker.com/chocolate-dipped-shortbread/

    Thanks

  22. Works wonderful Nick, thanks.
    With what codes can ‘orderby’ be changed or how can I exclude some categories?

  23. Sabine Visser says:

    Hi Nick, thanks for the code! It works fine, that is to say, the related posts are shown very well but it also causes the actual post to show up twice. Already tried switching off some plugins and commenting out some functions that deal with the_content but the double content only disappears when I comment out the add_action to your function.

    • Sabine,

      There is no reason by itself this code would cause the content to show twice. It is an exact copy of the code I use on this site, which you can see isn’t causing a problem here. Did you edit the code? If not it is almost certainly a plugin doing something weird.

      • Sabine Visser says:

        Thanks for the reply Nick. It turned out that WPML was causing the double content :-(.

  24. As always, you saved the day Nick! For the life of me, I couldn’t get LinkWithin working.. and this is even better. Thank you once again for a great tutorial that exceeds my expectations.

  25. Christopher Meinck says:

    I love the idea, but having an issue with posts that do not have an image. The box collapses. Is there a way to show a default image, if no image is available. Is there an easy way to remove all images?

    • Christopher, I probably didn’t make it clear in teh instructions, but if you make a “related.png” image and put it in the child theme images folder that will be used as a default.

  26. Nick, what controls how many posts will display? I’d like to edit the code slightly to only show 3 posts instead of 5, and I thought I had it, some posts it will show 3, then others will show more than that. I changed the instances where it says ‘showposts’ to ‘3’. Is that correct or is there another step to take?

    • you would also need to edit this line

      if ( $count <= 4 )
      
      • Hi, I’ve tried all kinds of things to get it showing only 4 posts instead of 5 but either it shows 5 or 5+ posts. I tried also modify the above line, but doesn’t work. What do I need to do to get only the most related 4 posts to show?

        Stefan

  27. Hmm, still not fixing it. See what I mean here.

  28. Thanks for your useful code.
    I have used your code on my website (http://www.navigatorsinsurance.ca), whis is using Associate child theme and on every blog post I have all 5 related posts.
    It works without any issue.
    The only thing is we have to add an image for non featured image posts.

  29. I like my show relate like you. I had add css in style.css but it not working. Pls help me. thí my site : http://www.travelingtrips.com/listings/pilgrimage-village-hue-boutique-resort-spa

  30. Can’t display relate listing??. http://www.travelingtrips.com/listings/the-vedana-lagoon-resort-spa-offers-pure-luxury-in-a-vietnamese-paradise . How to way display listing relate. Thanks

    • This code is designed to work with posts and tags, you would need to update it with the post_type and a different taxonomy for listings.

  31. Working for me.Code is error free and easy to use.Thank you very much!!

  32. bustersmom says:

    This is a great tip. I am really enjoying reading your posts. I would like to add a border at the top and bottom to show how it separates from the main content and the comment box. How can I add that? Say a border that might be purple or say a html color #F8EDF8?

  33. Nick, you are my favorite new guy, lol. This tutorial couldn’t be any easier.

    Did this in like 5 minutes. Had to add an extra line of code to change the font size, but other than that, pure awesomeness ;-)

    Thanks brotha…

  34. Hi Nick,
    Thanks! This is a great tip. :)

    I tried to implement it on my website and was successful.

    But I noticed that it is loading the full image from the related posts and is displaying it using CSS to 90px X 70px. This is causing performance issues. To see if I’m the only one facing the issue, I opened up Ole’s website from the comments above. I saw even in her website the images are actually full size but displayed in 90×70 pixels using CSS.

    I checked your site and found that the thumbnails are actually of 90×70 pixels size. I wanted to know how you are doing it, so that I can also implement it and improve performance.

    P.S. At this moment, I have temporarily removed it.

    • Sounds like you need to run the Regenerate Thumbnails plugin. If you add or change the image size the thumbnails need to be built in the new size which it what that plugin does.

      • Thanks Nick! I have now installed the plugin and have started regenerating the thumbnails. It will take time… so many images… :)

  35. Thanks for writing such an useful code to display related posts. I have just added this to my blog and its working fine.

  36. Thank you … You made my day! Within a couple of minutes I had related posts up and running. Gotta ♥ Nick the Geek!

  37. Great code snippet and tutorial Nick! Thank you so much for sharing!

  38. Very nice and easy to implement !! thanks

  39. Hi,

    This is a great tutorial. Every solution that gets rid of plugins are very much welcome! I really need to truncate the related post title to maximum number of characters. How can I achieve that?

    Your help would be very appreciated.

    Stefan

  40. Hi Nick

    Thanks a lot for this tutorial.
    I’m having some problems though. I pasted the really long code into the functions.php file and when I went to save it it gave me an error message. So I copied it to my DW and that gives me an error as well. Something to do with syntax error. It’s the first line, starting with what triggers it on DreamWeaver, and also the last line is in red as well. Could you help me out with it please?

    Thanks a lot

    • I’m not sure why you are getting an error unless the code was incomplete or unless some junk characters were copied over. Please start a thread in the forums

  41. Excellent work. Thanks for sharing this.

  42. Seems a little heavy to be running on every page load. What about adding some level of caching to it?

  43. thanks for sharing such an useful tutorial, I just need to get my hands dirty with css and the php code works pretty perfect and in the way like I need…

  44. Working great on my site… thanks for sharing … :)

  45. Nick the Geek you rock. This coding is simple and works perfectly. Just had to do a few minor adjustments to make it suit my site, then use the regenerate thumbnails plugin so the image sizes worked. It looks great, thanks for taking the time to share!

  46. Great tutorial!!
    How do I exclude a specific tag from being used to calculate related posts?
    Thanks!

    • Anyone who knows how to exclude a specific tag from being used to calculate related posts? I really really need this and would appreciate an answer. Thanks!

  47. Hi Nick, is this article still valid? I’ve seen you wrote it quite long time back. Will we have an update for Genesis 2.0?

    • I’m still using this exact code on my site. This is with Genesis 2.0 RC1 and HTML5 enabled. Everything seems to be working for me still so I don’t think it needs any update.

  48. Hi Nick, I try this and work for me. But a I want (if is possible) to do something different. It would be possible to show one related post inside the text of the article? Maybe something like Gizmodo: https://docs.google.com/file/d/0B86oq1tx7ZPAajJibDhwT05MQ0E/edit?usp=sharing, http://gizmodo.com/new-nexus-7-now-on-amazon-923138791

  49. Hey there Nick. I’ve tried it on my blog with Genesis 2.0 and the new Sixteen Nine Pro theme, but it doesn.t work. Any ideas.

  50. I think my last comment is confused with spam, maybe because included links?

    Thanks :)

  51. Great work …..
    Tried this code. and its working fine for free…
    Great piece of work and easy to implement

  52. That worked as well for our wordpress blog at blog.boatstogo.com

  53. It has been working fine at my blog :)