techweb24.dev
README.md

Related Posts Widget for Blogger with Thumbnails (No jQuery, 2026)

A related posts section under each article keeps readers on your blog: they finish one post and immediately see three more on the same topic. Old Blogger widgets for this loaded scripts from sites that no longer exist (LinkWithin, outbrain, googlecode). This tutorial gives you a modern, dependency-free related posts widget written in plain JavaScript. It uses your blog's own feed, works on blogspot.com and custom domains, and you can add it as a gadget without editing your theme.

Updated for 2026. This replaces the 2014 version of this tutorial, whose script host has shut down. If you used that code, remove it and use this one.

How it works

  1. On a post page, the script reads the post's labels from the label links (rel="tag") that every Blogger theme outputs.
  2. It asks Blogger's JSON feed for recent posts with those labels: /feeds/posts/summary/-/LABEL?alt=json.
  3. It removes the current post, scores the rest by how many labels they share, and shows the top results with thumbnails under the post.

No jQuery, no external servers, no tracking. Everything is loaded from your own blog.

Step 1: Add an HTML/JavaScript gadget

  1. In Blogger, open Layout.
  2. In the sidebar (or any section), click Add a Gadget → HTML/JavaScript.
  3. Leave the title empty and paste the full code from Step 2 into the content box.
  4. Click Save, then Save on the Layout page if your theme asks.

The gadget itself stays invisible. On post pages it inserts the related posts box right after the article.

Step 2: The code

<style>
.rp-box{margin:32px 0 8px;padding-top:20px;border-top:1px solid rgba(127,127,127,.25);font-family:inherit}
.rp-box h3{margin:0 0 14px;font-size:20px}
.rp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:16px}
.rp-card{display:block;text-decoration:none;color:inherit;border-radius:10px;overflow:hidden;
  border:1px solid rgba(127,127,127,.25);transition:transform .15s}
.rp-card:hover{transform:translateY(-2px)}
.rp-card img{display:block;width:100%;aspect-ratio:16/9;object-fit:cover;background:#e5e7eb}
.rp-card span{display:block;padding:10px 12px;font-weight:600;font-size:15px;line-height:1.35}
</style>
<script>
(function () {
  var MAX_POSTS   = 4;            // how many related posts to show
  var TITLE       = 'You might also like';
  var NO_IMAGE    = 'https://placehold.co/640x360/png?text=No+image';
  var FEED_LIMIT  = 20;           // posts fetched per label

  // only run on single post pages
  var labelLinks = document.querySelectorAll('a[rel="tag"]');
  var body = document.querySelector('.post-body, .entry-content, article .post');
  if (!labelLinks.length || !body || !/\/\d{4}\/\d{2}\//.test(location.pathname)) return;

  var labels = Array.prototype.map.call(labelLinks, function (a) { return a.textContent.trim(); })
    .filter(function (l, i, arr) { return l && arr.indexOf(l) === i; }).slice(0, 3);
  var here = location.pathname;
  var scores = {};

  function thumb(entry) {
    if (!entry.media$thumbnail) return NO_IMAGE;
    // ask Blogger for a larger thumbnail than the default 72px
    return entry.media$thumbnail.url.replace(/\/s72(-c)?\//, '/w640-h360-c/').replace(/=s72(-c)?$/, '=w640-h360-c');
  }

  Promise.all(labels.map(function (label) {
    var url = '/feeds/posts/summary/-/' + encodeURIComponent(label) + '?alt=json&max-results=' + FEED_LIMIT;
    return fetch(url).then(function (r) { return r.ok ? r.json() : { feed: {} }; }).catch(function () { return { feed: {} }; });
  })).then(function (results) {
    results.forEach(function (data) {
      (data.feed.entry || []).forEach(function (e) {
        var link = e.link.filter(function (l) { return l.rel === 'alternate'; })[0];
        if (!link || new URL(link.href).pathname === here) return;
        var item = scores[link.href] || (scores[link.href] = { url: link.href, title: e.title.$t, img: thumb(e), score: 0 });
        item.score++;                                   // shares one more label with this post
      });
    });

    var items = Object.keys(scores).map(function (k) { return scores[k]; })
      .sort(function (a, b) { return b.score - a.score; })
      .slice(0, MAX_POSTS);
    if (!items.length) return;

    var box = document.createElement('section');
    box.className = 'rp-box';
    var h = document.createElement('h3'); h.textContent = TITLE; box.appendChild(h);
    var grid = document.createElement('div'); grid.className = 'rp-grid'; box.appendChild(grid);

    items.forEach(function (p) {
      var a = document.createElement('a'); a.className = 'rp-card'; a.href = p.url;
      var img = document.createElement('img'); img.src = p.img; img.alt = ''; img.loading = 'lazy';
      var t = document.createElement('span'); t.textContent = p.title;
      a.appendChild(img); a.appendChild(t); grid.appendChild(a);
    });
    body.parentNode.insertBefore(box, body.nextSibling);
  });
})();
</script>

Customizing it

SettingWhat it changes
MAX_POSTSNumber of related posts shown (4 works well in a grid; use 3 for narrow themes).
TITLEThe heading above the box.
NO_IMAGEImage used for posts without a picture. Upload your own placeholder to Blogger and paste its URL here.
.rp-grid CSSminmax(180px,1fr) controls card width. The grid automatically becomes one column on phones.

The CSS uses semi-transparent borders and inherits your theme's fonts and colours, so it fits both light and dark themes.

Prefer to put it in the theme?

If your theme hides gadgets or you want full control, paste the same code in Theme → ▾ → Edit HTML just before </body>. Inside a Blogger theme, wrap the script content in CDATA so the XML stays valid:

<script>
//<![CDATA[
  ... the JavaScript from Step 2 ...
//]]>
</script>

Troubleshooting

  • Nothing appears: the post needs at least one label, and other posts must share that label. Open the browser console (F12) and check for errors.
  • Box appears in the wrong place: your theme uses a different class for the article body. Change '.post-body, .entry-content, article .post' to match it (right-click the post text → Inspect to see the class).
  • Blurry thumbnails: the image was uploaded at a small size. Re-upload it at least 640px wide.
  • Private blog: the feed is only public when Settings → Site feed is enabled and the blog is public.

Scroll down this page to see a related posts section in action. Questions or a theme where it doesn't fit? Ask in the comments.

Zubaer Ahammed

Full-stack & Android developer from Bangladesh. Builds web platforms and apps and writes practical tutorials here. zubaer.com

Comments

  1. Your method of telling all in this piece of writing
    is really pleasant, all be capable of without difficulty understand
    it, Thanks a lot.

    Also visit my weblog :: Garden Route Photographer
    ()

    ReplyDelete
  2. There's certainly a great deal to know about this issue. I really like all the points you made.

    Here is my website vinyl floors denver CA

    ReplyDelete
    Replies
    1. I am really glad to help you. You are always welcome to my blog.

      Delete
  3. I got this web page from my pal who shared with me on the topic of this site and at the moment this time I am visiting this web page and reading very informative posts at this place.


    Here is my web-site ... interntaional travel

    ReplyDelete
  4. Are you already doing shopping for Christmas? Gifts?

    ReplyDelete

Post a Comment