Tutorials

Table of contents
Close

Creating a related post section with HubL

One common feature of blog post layouts is a related post section that displays content from posts of the same topic. The following tutorial will walk through the creation of a related post section for your HubSpot blog. The end result of this tutorial is a HubL related post section that retrieves a set of posts of a shared topic. You can modify the markup, the CSS, and the included blog variables to meet your particular needs.

At the end of this tutorial, there is a more advanced example that combines multiple topics into the related posts section. 

Edit your blog post layout

In order to build a related posts section, you will need to edit the template layout or coded file that you are using for your blog post template. If you are using a template layout, add a HubL template module to the section of the template, where you would like to add the related posts section.

Check for topics

Within your HubL template module or coded template file, write an if statement to check whether or not the post has a topic_list (content.topic_list). Below is the if statement that when true will render a related post heading.


{% if content.topic_list %}
<h3>Related posts</h3>
{% endif %}

Select topic from topic_list

Since the topics for a given post are stored in a sequence, you must iterate through content.topic_list to select the topic to use to fetch related posts. This tutorial selects the first topic assigned to a post by using loop.first

The code below iterates through the topic_list and prints the first topic slug (a hyphenated version of the topic name).


{% if content.topic_list %}
<h3>Related posts</h3>
    {% for topic in content.topic_list %}
        {% if loop.first %}
            {{ topic.slug }}
        {% endif %}
    {% endfor %}
{% endif %}    

Use blog_recent_topic_posts function

Now that you have selected the topic to use, you will now use the blog_recent_topic_posts function to generate a sequence of a set number of posts of that topic. Rather than printing the first topic.slug, as you did in the previous example, topic.slug is used for the second parameter of the function to get posts by that particular topic. This tutorial uses the first parameter to select the default blog and the third parameter to render up to 5 posts.


{% if content.topic_list %}
<h3>Related posts</h3>
    {% for topic in content.topic_list %}
        {% if loop.first %}
            {{ blog_recent_topic_posts('default', topic.slug, 5 ) }}
        {% endif %}
    {% endfor %}
{% endif %}    

Store function in a variable and iterate through it

Rather than printing the sequence of related posts, you will want to store the results of that function in a variable and iterate through it using a for loop. Within the for loop, you can use any blog variables, as long as you use the name of the individual loop item rather than "content." For example, in the code below where "post" is used in the for loop declaration, post.name is used to print the name of posts in the sequence.


{% if content.topic_list %}
<h3>Related posts</h3>
    {% for topic in content.topic_list %}
        {% if loop.first %}
            {% set related_posts = blog_recent_topic_posts('default', topic.slug, 5 ) %}
            {% for post in related_posts %}
                {{ post.name }}
            {% endfor %}
        {% endif %}
    {% endfor %}
{% endif %}    

Exclude current post

Since you are retrieving recent posts of a particular topic, it is possible that the current post may display in the related post listing. To avoid this, you would want to use an if or unless statement to check whether or not an item in the loop shares a property with the current post. In the example code below, an unless statement is used to check whether or not the absoulte URL of the current post matches an item in the related post listing.


{% if content.topic_list %}
<h3>Related posts</h3>
    {% for topic in content.topic_list %}
        {% if loop.first %}
            {% set related_posts = blog_recent_topic_posts('default', topic.slug, 5 ) %}
            {% for post in related_posts %}
                {% unless content.absolute_url == post.absolute_url %}
                    {{ post.name }}
                {% endunless %}
            {% endfor %}
        {% endif %}
    {% endfor %}
{% endif %}    

Customize markup and variables to include

At this point, you have the logic of the related posts section worked out, and now it is time to edit the markup and add variables to render with each related post item. Keep in mind that you will want to customize the markup and add whatever variables you want to render. This example generates the title, link, and featured image of the post, but you could additionally add post body content or other variables


{% if content.topic_list %}
<h3>Related posts</h3>
    {% for topic in content.topic_list %}
        {% if loop.first %}
            {% set related_posts = blog_recent_topic_posts('default', topic.slug, 5 ) %}
            {% for post in related_posts %}
                {% unless content.absolute_url == post.absolute_url %}
                    <div class="related-post-item">
                        <div class="related-title"><a href="{{post.absolute_url}}">{{ post.name}}</a></div>
                        <div class="related-image"><img src="{{ post.featured_image }}" alt="{{ post.name }}"></div>
                    </div>
                {% endunless %}
            {% endfor %}
        {% endif %}
    {% endfor %}
{% endif %}    

Final example code

Here is the final example output for a basic realted post listing based upon a single related topic. You can see a styled example of this markup on the sidebar of this blog post


{% if content.topic_list %}
<h3>Related posts</h3>
    {% for topic in content.topic_list %}
        {% if loop.first %}
            {% set related_posts = blog_recent_topic_posts('default', topic.slug, 5 ) %}
            {% for post in related_posts %}
                {% unless content.absolute_url == post.absolute_url %}
                    <div class="related-post-item">
                        <div class="related-title"><a href="{{post.absolute_url}}">{{ post.name}}</a></div>
                        <div class="related-image"><img src="{{ post.featured_image }}" alt="{{ post.name }}"></div>
                    </div>
                {% endunless %}
            {% endfor %}
        {% endif %}
    {% endfor %}
{% endif %}    

Multiple related topics listing

In the previous tutorial steps, you created a related posts section based upon the first topic that a post was tagged with. This implementation will generally be sufficient for blogs that use a single topic or a few topics per post. However, if you want to create a related post section that aggregates posts from multiple related topics and sorts them, check out the code below. 

In this example, if statements based upon loop.index are used to store the current topic sequence as the loop iterates through the topic list. The results of the blog_recent_topic_posts function are stored in a variable for each iteration. You can then use if statements based upon loop.length to determine how many topics were in the the topic_list, and define a variable that combines the various sequences from the iterations. For example, if there were two topics in the content.topic_list for a post, the related_posts variable would be defined as a combination of the blog_recent_topic_posts function for the first and second topic. By applying a sort filter to the combined variable, the sequence is sorted, before you iterate through it using a for loop. You also need to apply a unique filter to remove any duplicate posts.

This example uses a two custom counter variables (max_posts and count) to limit the maximum number of posts that will print. Count is updated based on the number of topics in the topic list, and max_posts is currently set to 4.

This code example supports up to 3 topics, but you could modify it further to support additional topics.


{% if content.topic_list %}
    <h3>Related posts</h3>
    {% set max_posts = 4 %} <!-- Set the max number of related posts to be output to the page here -->
    {% set count = 0 %}
    {% for topic in content.topic_list %}
        {% if loop.index  == 1 %}
            {% set topic_one = blog_recent_topic_posts('default', topic.slug, max_posts + 1 ) %}
            {% if topic_one|length == 1 %}
                <p>There are no related posts</p>
            {% endif %}
        {% elif loop.index == 2 %}
            {% set topic_two = blog_recent_topic_posts('default', topic.slug, max_posts + 1 ) %}
        {% elif loop.index == 3 %}
            {% set topic_three = blog_recent_topic_posts('default', topic.slug, max_posts + 1 ) %}
        {% endif %}
        {% if loop.length >= 3 and loop.index == 3 %}
            {% set related_posts = (topic_one + topic_two + topic_three)|sort(true, false, 'publish_date')|unique('name') %}
            {% set loop_count = 3 %}
        {% elif loop.length == 2 and loop.index == 2 %}
            {% set related_posts = (topic_one + topic_two)|sort(true, false, 'publish_date')|unique('name') %}
            {% set loop_count = 2 %}
        {% elif loop.length == 1 and loop.index == 1 %}
            {% set related_posts = topic_one %}
            {% set loop_count = 1 %}
        {% endif %}
        {% if loop.index == loop_count %}
            {% for post in related_posts %}
                {% if content.absolute_url != post.absolute_url and count < max_posts %}
                    <div class="related-post-item">
                        <div class="related-title"><a href="{{post.absolute_url}}">{{ post.name}}</a></div>
                        <div class="related-image"><img src="{{ post.featured_image }}" alt="{{ post.name }}"></div>
                    </div>
                    {% set count = count + 1 %}
                {% endif %}
            {% endfor %}
        {% endif %}
    {% endfor %}
{% endif %}