Skip to content

Free tool · Squarespace 7.1 blogs

Give readers a relevant next step.

Match related posts by shared tags, categories, or both. Choose the layout, then generate code for your blog.

Configure your related posts

Start with the native option

A fixed topic list may be all you need.

Squarespace Summary Blocks can show posts from a category or tag you choose. Use this generator when you want recommendations to change with each article.

Compare the native and automatic options

Make it yours

Use the collection path, such as /journal. Do not paste an individual article URL.

Example content, not your live blog

Tags: Typography, Tutorial
Category: Design


Related posts

Fix a crowded mobile heading

Check the native settings before adding a custom rule.

2 shared labels

Choose an image crop

Keep the important part of an image visible on a phone.

2 shared labels

Organize a resource library

Give visitors a clear way to find the next useful answer.

1 shared label

Shared labels determine the order. Equal matches use newest first, then the URL. Results can be fewer than your maximum. The current article is excluded.

Your installation code

View generated HTML, CSS, and JavaScript
<!-- Squarespace Tools Related Posts v2. Replace the older export; paste once in site Footer Code Injection.
Squarespace 7.1 blog posts only. Up to 10 feed pages / 300 posts. A changing Squarespace JSON representation is used, not a supported stable API.
If the collection cannot be read completely within these limits, no recommendations are shown. -->
<style>
.sqt-related{margin:3rem 0;max-width:100%;color:inherit}
.sqt-related *{box-sizing:border-box}
.sqt-related h2{font-size:clamp(1.4rem,3vw,2rem);line-height:1.2;color:#234c3c;margin:0 0 1.5rem;overflow-wrap:anywhere}
.sqt-related-items{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,220px),1fr));gap:1.25rem}
.sqt-related-card{min-width:0;display:flex;flex-direction:column;text-decoration:none!important;color:inherit!important;overflow:hidden;border-radius:8px;background:#fff;border:1px solid #d6ddd5;}
.sqt-related-card:focus-visible{outline:3px solid #234c3c;outline-offset:4px}
.sqt-related-card img{width:100%;height:auto;aspect-ratio:16/10;object-fit:cover;display:block}
.sqt-related-body{padding:1rem;min-width:0;overflow-wrap:anywhere}
.sqt-related h3{font:inherit;font-size:1.1rem;font-weight:600;line-height:1.4;margin:0;color:#203c30}
.sqt-related-card:hover h3{text-decoration:underline;text-underline-offset:3px}
.sqt-related p{font-size:.9rem;line-height:1.6;margin:.6rem 0 0;color:#4b584f}
.sqt-related time{display:block;font-size:.8rem;line-height:1.4;margin-top:.6rem;color:#4b584f}
.sqt-related[data-layout="scroll"] .sqt-related-items{display:flex;overflow-x:auto;scroll-snap-type:x proximity;padding:.3rem .3rem 1rem}
.sqt-related[data-layout="scroll"] .sqt-related-card{flex:0 0 min(85%,290px);scroll-snap-align:start}
.sqt-related[data-layout="list"] .sqt-related-items{grid-template-columns:1fr}
.sqt-related[data-layout="list"] .sqt-related-card{flex-direction:row;align-items:start}
.sqt-related[data-layout="list"] img{width:28%;max-width:160px;flex-shrink:0}
@media(max-width:480px){.sqt-related[data-layout="list"] .sqt-related-card{flex-direction:column}.sqt-related[data-layout="list"] img{width:100%;max-width:none}}
</style>
<script>
(function(){
var config={"blogPath":"/blog","count":3,"layout":"grid","match":"both","fallback":"hide","thumbnails":true,"excerpts":true,"dates":false,"card":"bordered","color":"#234c3c","heading":"Related posts"};

var key='sqt-related-v2:'+config.blogPath;
if(window[key]) return;
window[key]=true;
var cache=null, pending=null, currentBody=null, currentPath='', generation=0, timer;
function pathOf(value){
  try {var u=new URL(value,location.origin);if(u.origin!==location.origin||u.username||u.password)return '';return decodeURIComponent(u.pathname).replace(/\/+$/,'');}catch(e){return '';}
}
function labels(value){return Array.isArray(value)?Array.from(new Set(value.filter(function(t){return typeof t==='string';}).map(function(t){return t.trim().toLowerCase();}).filter(Boolean))):[];}
function score(post,current){
  var total=0;
  ['tags','categories'].forEach(function(field){if(config.match!=='both'&&config.match!==field)return;var mine=labels(current[field]);labels(post[field]).forEach(function(tag){if(mine.indexOf(tag)!==-1)total++;});});
  return total;
}
function plain(value){var doc=new DOMParser().parseFromString(String(value||''),'text/html');doc.querySelectorAll('script,style,iframe,object').forEach(function(n){n.remove();});return (doc.body.textContent||'').replace(/\s+/g,' ').trim().slice(0,180);}
async function read(url){
  var controller=new AbortController(), timeout=setTimeout(function(){controller.abort();},8000);
  try{var r=await fetch(url,{signal:controller.signal,credentials:'same-origin',redirect:'error',headers:{Accept:'application/json'}});if(!r.ok)throw Error('Feed unavailable');return await r.json();}finally{clearTimeout(timeout);}
}
async function load(){
  if(cache&&Date.now()-cache.time<60000)return cache.items;
  if(pending)return pending;
  pending=(async function(){
    var next=new URL(config.blogPath,location.origin);next.searchParams.set('format','json');
    var items=[],seenUrls=new Set(),seenPosts=new Set(),pages=0;
    while(next){
      if(pages>=10||seenUrls.has(next.href))throw Error('Feed pagination limit or loop');
      seenUrls.add(next.href);pages++;
      var data=await read(next.href);if(!Array.isArray(data.items))throw Error('Unexpected feed format');
      data.items.forEach(function(p){if(!p||typeof p!=='object')return;var path=pathOf(p.fullUrl);if(!path||!path.startsWith(config.blogPath+'/')||seenPosts.has(path))return;seenPosts.add(path);items.push(Object.assign({},p,{path:path}));});
      if(items.length>300)throw Error('Collection exceeds 300 posts');
      var page=data.pagination;
      if(page&&page.nextPage){
        if(typeof page.nextPageUrl!=='string')throw Error('Missing next page URL');
        var candidate=new URL(page.nextPageUrl,next.href);
        if(candidate.origin!==location.origin||pathOf(candidate.href)!==config.blogPath||candidate.username||candidate.password)throw Error('Invalid next page URL');
        candidate.searchParams.set('format','json');next=candidate;
      }else{next=null;}
    }
    cache={time:Date.now(),items:items};return items;
  })();
  try{return await pending;}finally{pending=null;}
}
function element(tag,cls,text){var n=document.createElement(tag);if(cls)n.className=cls;if(text!==undefined)n.textContent=text;return n;}
function render(posts,isFallback,body){
  var root=element('section','sqt-related');root.dataset.sqtBlog=config.blogPath;root.dataset.layout=config.layout;root.setAttribute('aria-label',isFallback?'More from the blog':config.heading);
  root.append(element('h2','',isFallback?'More from the blog':config.heading));
  var grid=element('div','sqt-related-items');root.append(grid);
  posts.forEach(function(p){
    var a=element('a','sqt-related-card');a.href=p.path;
    if(config.thumbnails&&typeof p.assetUrl==='string'){
      try{var src=new URL(p.assetUrl,location.origin);if(src.protocol==='https:'&&!src.username&&!src.password){var img=element('img','');src.searchParams.set('format','500w');img.src=src.href;img.alt='';img.loading='lazy';img.width=500;img.height=313;img.addEventListener('error',function(){img.remove();},{once:true});a.append(img);}}catch(e){}
    }
    var content=element('div','sqt-related-body');content.append(element('h3','',typeof p.title==='string'?p.title:'Untitled post'));
    if(config.excerpts){var excerpt=plain(p.excerpt||p.body);if(excerpt)content.append(element('p','',excerpt));}
    if(config.dates&&p.publishOn){var date=new Date(p.publishOn);if(Number.isFinite(date.getTime())){var time=element('time','',date.toLocaleDateString('en-US',{month:'short',day:'numeric',year:'numeric'}));time.dateTime=date.toISOString();content.append(time);}}
    a.append(content);grid.append(a);
  });
  body.after(root);
}
async function run(){
  var path=pathOf(location.href),body=document.querySelector('.blog-item-wrapper .blog-item-content');
  if(path===currentPath&&body===currentBody)return;
  currentPath=path;currentBody=body;generation++;var id=generation;
  document.querySelectorAll('.sqt-related').forEach(function(n){if(n.dataset.sqtBlog===config.blogPath)n.remove();});
  if(!body||!path.startsWith(config.blogPath+'/')||path.startsWith(config.blogPath+'/tag/')||path.startsWith(config.blogPath+'/category/'))return;
  try{
    var posts=await load();if(id!==generation||!body.isConnected||pathOf(location.href)!==path)return;
    var current=posts.find(function(p){return p.path===path;});if(!current)throw Error('Current post missing from complete feed');
    var candidates=posts.filter(function(p){return p.path!==path;}).map(function(p){return {post:p,score:score(p,current)};});
    function order(a,b){return b.score-a.score||(Number(b.post.publishOn)||0)-(Number(a.post.publishOn)||0)||a.post.path.localeCompare(b.post.path);}
    var matches=candidates.filter(function(p){return p.score>0;}).sort(order),fallback=false;
    if(!matches.length&&config.fallback==='recent'){matches=candidates.sort(order);fallback=true;}
    if(!matches.length)return;
    render(matches.slice(0,config.count).map(function(p){return p.post;}),fallback,body);
  }catch(e){console.warn('Squarespace Tools: related posts hidden. '+(e.message||'Collection could not be read.'));}
}
function schedule(){clearTimeout(timer);timer=setTimeout(run,100);}
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',run,{once:true});else run();
new MutationObserver(schedule).observe(document.body,{childList:true,subtree:true});
window.addEventListener('popstate',schedule);

})();
</script>

Install it once. Check it on an article.

  1. Give your blog posts useful, consistent categories and tags. Set the correct collection path above.
  2. Open Pages → Custom Code → Code Injection in Squarespace. Back up the existing Footer field.
  3. Remove an older Related Posts export, then add this complete replacement to Footer. Keep unrelated scripts intact and save.
  4. Exit editing and open an individual published blog post. Check matching posts, a post without matches, and a phone-width preview. The blog listing and ordinary pages should not show this section.
  5. To remove it, delete only this export from Footer Code Injection and save.

Updated exports do not replace code already installed on a site. Copy and reinstall this version to receive the correction.

No related posts appeared?

Check the path, shared labels, and Code Injection access. A missing article, failed request, unexpected feed format, or a collection exceeding the limits keeps the section hidden. Your original blog stays usable. Check the browser console for the Squarespace Tools message. Sites that need guaranteed support for larger libraries should use a native curated Summary Block or a maintained plugin.

Squarespace's related-post instructions · JSON compatibility notice