Tuesday, October 6, 2020

Show Related Posts on Blogger Post

 Do you host a blog at blogger and want to show related posts without using a plugin? This post demonstrates how to show related posts on a blogger single post page.

Related Posts on Blogger Post

Ok let's break it into steps to see how are we going to show related posts on single post page. 

  • We will loop through all the labels of current post in view.
  • We will then call blogger API to get posts against those labels.
  • Then we will prepare html of related post box and exclude the post in view.

The below code snippet will check if the current page is an item (post) then it loops through all the labels of current post. It then hits the blogger's feed url to return json formatted posts of current label in loop. We also set the maximum number of posts to 6 so it returns no more than 6 posts for each label and then we pass a callback function which prepares a related post list. 

After loop we declare two variables current_post_link and max_related_posts, The current_post_link will be used to exclude the current post from related posts list so we don't show the same post in view in related posts. Whereas max_related_posts is the number of related posts we want to show. Place the below code snippet where you want the related posts section to appear.

<b:if cond='data:blog.pageType == "item"'>
<div class='related-posts'/>
<b:loop values='data:post.labels' var='label'>
<script defer='defer' expr:src='"/feeds/posts/default/-/" + data:label.name + "?alt=json-in-script&callback=prepare_related_posts_list&max-results=6"' type='text/javascript'/>
</b:loop>
<script type='text/javascript'>
var current_post_link = '<data:post.url/>';
var max_related_posts = 4;
</script>
</b:if>

Now for the callback function which prepares related posts list, We first set the returned json list of posts in a variable, we then loop through all the posts and prepare the related posts list. Before we prepare a list we first declare two variables related_posts and related_filled. The related_posts will hold the list of related post while related_filled will be used to filter out duplicates. The reason we used another variable related_filled is that it will contain only titles as unique identifiers for conditional check. 

The callback function uses other two functions get_single_post_link which is used to prepare the link of post and print_related_posts which is used to print the related post in list after the document has been loaded.

<script type='text/javascript'>
//<![CDATA[
var related_posts = [];
var related_filled = [];
function prepare_related_posts_list( json ){
var posts = json.feed.entry;
posts.forEach(function(p, v){
        //-- Prepare the link of related post
    let p_link = get_single_post_link(p);
let related_post = {
    title: p.title.$t,
link: p_link,
image: {
el: "",
src: ""
}
};
        
        //-- Get the html content of post that will be used to retrieve post image
        let content_html = new DOMParser().parseFromString(p.content.$t, 'text/html');
let image = content_html.querySelector("img");
        //-- If image is found set the image src
if (image instanceof HTMLImageElement) {
related_post.image.el = image;
related_post.image.src = image.src;
}
        //-- If post link is not equal to current link and not already filled then add to list
if (p_link != current_post_link && !related_filled.includes(p.title.$t)) {
related_posts.push(related_post);
related_filled.push(p.title.$t);
}
});
    //-- Finally print the related posts on after document has loaded
window.addEventListener("load", function () {
print_related_posts();
});
}
//-- Function to prepare the post link in loop
function get_single_post_link(p) {
var link = "javascript:void(0)";
if ("link" in p) {
for (let i = 0; i < p.link.length; i++) {
if (p.link[i].type == "text/html" && p.link[i].rel == "alternate") {
link = p.link[i].href;
break;
}
}
}

return link;
}
//-- Function to print related post after document load
function print_related_posts() {
if (related_posts.length) {
var html = "";
html += '<h3>Related Posts:</h3>';
html += '<div class="row">';
        //-- If related posts list has reached the number of posts we need, break the loop
for (let i = 0; i < related_posts.length; i++) {
if (i >= max_related_posts)
break;

html += '<div class="col-xs-6">' +
'<div class="related-post">' +
'<div class="related-post-image">' +
'<a href="' + related_posts[i].link + '">' +
related_posts[i].image.el.outerHTML +
'</a>' +
'</div>' +
'<div class="related-post-title">' +
'<a href="' + related_posts[i].link + '">' + related_posts[i].title + '</a>' +
'</div>' +
'</div>' +
'</div>';
}
html += '</div>';
document.querySelector(".related-posts").innerHTML = html;
}
}
//]]>
</script>

The demo of the code above can be seen below this post under related posts section.