This is an old post. Information here may be out-dated, or the post may re­flect opin­ions or be­liefs I no longer share.

I pre­fer and rely on my Static Site Generator to fig­ure out what the cor­rect and up to date perma­link to a post is. I do this as a means to:

  • pro­tect my­self au­to­mat­i­cally against any fu­ture changes in my blog’s perma­link struc­ture, by not need­ing to man­u­ally edit my posts and up­date each link,
  • catch any bro­ken links be­fore they make it to pro­duc­tion, and,
  • reap a small ben­e­fit of one less HTTP re­quest.

If you hap­pen to change your perma­link struc­ture, you’ll be con­fig­ur­ing a HTTP 301 redi­rect on the server re­gard­less. However, I be­lieve us­ing a helper tag is a cleaner so­lu­tion for links within your do­main.

Why did I end up writ­ing this short­code?

I re­cently moved from Jekyll to 11ty for var­i­ous rea­sons, chief among them the de­sire to move from two ecosys­tems, Ruby and JavaScript, to just JavaScript. It al­lows me to add new func­tion­al­ity with ease. Additionally, work­ing with and de­bug­ging in a sin­gle as­set pipeline is eas­ier.

Jekyll of­fers a cus­tom liq­uid tag, post_url (see here). 11ty does not have this short­code. However, it’s easy to ex­tend the frame­work.

In your .eleventy.js file, add:

module.exports = function(config11ty) {
config11ty.addShortcode("post_url", (collection, slug) => {
try {
if (collection.length < 1) throw "Collection appears to be empty";
if (!Array.isArray(collection))
throw "Collection is an invalid type - it must be an array!";
if (typeof slug !== "string")
throw "Slug is an invalid type - it must be a string!";

const found = collection.find(p => p.fileSlug.includes(slug));
if (found === 0 || found === undefined)
throw `${slug} not found in specified collection.`;
else return found.url;
} catch (e) {
`An error occured while searching for the url to ${slug}. Details:`,

We have a few san­ity checks on the collection and slug ar­gu­ments passed in. An er­ror will be thrown in case the col­lec­tion is empty, or in­valid, or if the slug passed in is not a string, or if no file is found with the pro­vided slug.

Use the short­code as fol­lows in your blog posts. I use Shopify’s liq­uid, so for me it looks like:

{% post_url collections.articles, 'check-string-in-array-liquid-vs-nunjucks' %}

On my blog, it gen­er­ates:


If you’re in the process of mi­grat­ing away from Jekyll, this would al­low you to mod­ify your files as lit­tle as pos­si­ble. You can use RegEx to sim­ply add the col­lec­tion name where post_url tag has been used ear­lier.

You can also pass this re­sult to a cus­tom fil­ter that con­verts it to an ab­solute URL. If you’d like to see how I have im­ple­mented this fil­ter, do let me know!

Added flex­i­bil­ity - use any col­lec­tion!

One ap­par­ent ad­van­tage of spec­i­fy­ing the col­lec­tion to use is you’re not just lim­ited to gen­er­at­ing links to your blog posts. You can do so for any col­lec­tion - notes, pro­jects, and so on, and on any page that your tem­plat­ing en­gine will process.

If this is a use-case for you, you might also wish to re­name the short­code to some­thing more ap­pro­pri­ate.