Skip to main content
notes.jays.net

11ty

I forked 11ty/eleventy-base-blog and was super happy.

Cute 11ty logo I found.

Then I realized when I share my blog posts in Discord or Mastodon (etc.), previews weren't working. My pretty images weren't previewing. Sad.

Those work via the Open Graph protocol, which is og:image and other tags in your <html><head>.

I tried adding those tags, and got sad when I hit a bunch of problems. So I went to the 11ty Discord and asked what gives?

And they said eleventy-base-blog has a bug. The new super fancy image stuff doesn't play well with a per-post og:image. Sad. But it's a known issue and there's even a solution! Yay!

So I implemented it, and it worked for me! Yay!

Here's what I did, stealing Seramis' code:

eleventy.json.cfg

Jump to section titled: eleventy.json.cfg

I added this line at the end of function(eleventyConfig):

eleventyConfig.addFilter("contentImgUrlFilter", contentImgUrlFilter);

Where'd that filter come from? It's new. We add it to the bottom of that same file:

// Author: Seramis
// https://github.com/11ty/eleventy-img/issues/278
import path from 'node:path';
import Image from '@11ty/eleventy-img';
async function contentImgUrlFilter(src) {
  const inputDir = path.dirname(this.page.inputPath);
  const imagePath = path.resolve(inputDir, src);
  const outputDir = path.dirname(this.page.outputPath);
  const urlPath = this.page.url;

  const stats = await Image(imagePath, {
    widths: [1200], // Width for Open Graph image
    formats: ["jpg", "png"],
    outputDir: outputDir, // Output directory
    urlPath: urlPath, // Public URL path
    filenameFormat: function (hash, src, width, format) {
        return `${hash}-${width}.${format}`;
    },
  });
  return stats.jpeg[0].url; // Return the URL of the processed image
}

Those import commands should really be up top next to all the other ones. 🙂 I put 'em down there to be more obvious that I added them for my future merges of upstream/main. 🤷‍♂️

So now we have a new Filter. Neat. How do we use it? Like this:

_includes/layouts/base.njk

Jump to section titled: _includes/layouts/base.njk

I didn't have any og:* meta tags, so I added all of 'em. Sort of:

  <head> ...
    <!-- <meta property="og:url" content="TODO" /> -->
    <!-- <meta property="og:logo" content="TODO" /> -->
    <meta property="og:type" content="website" />
    <meta property="og:title" content="{{ title }}" />
    <meta property="og:description" content="{{ description or metadata.description }}" />
    {% if image %}
        <meta property="og:image" content="{{ image | contentImgUrlFilter | absoluteUrl(metadata.url) }}" />
    {% endif %}

You can use OrcaScan to check if it's working.

Where does image come from? From each of your blog posts. Like this:

content/blog/11ty.md

Jump to section titled: content/blog/11ty.md
---
title: "11ty"
description: "Various tricks I've stumbled into."
date: 2025-02-11
image: 11ty.jpeg
---

11ty is cool!
<img src="11ty.jpeg" alt="Cute 11ty logo I found.">

And yay! It works!? All done! Now my blog posts preview on Discord, etc. with my images. 🙂 Thanks Seramis! And thank you to cassey in 11ty Discord for all their help too!

Presumably some day soon-ish eleventy-base-blog will have native support for og:image and friends? But not yet, apparently, since I just merged upstream/main and don't see it in there yet... Until then maybe this hackery will be useful to you too.

Happy blogging!