Skip to main content

Webmentions and 11ty

Update 6/19/2024: I updated the code in this post to show the changes with Eleventy 3.0.0.alpha & my simplified(?) eleventy.config.js.

I have been struggling getting webmentions working on the site. It's worth noting that I don't have many yet, but I like to think I'm preparing for the future.

I found Bob Monsour's blog post on the topic the most helpful. While your mileage may vary, I found a couple of changes helped with my flow. It's worth noting, my JS skills are not the strongest, so troubleshooting some of the issues was perhaps more difficult for me than they may be for you.

First, my _data/webmentions.js looks like this:

import EleventyFetch from "@11ty/eleventy-fetch";
import dotenv from 'dotenv';

dotenv.config();

export default async function () {
  const WEBMENTIONS_STUFF = process.env.WEBMENTION_IO_TOKEN;
  const url = `https://webmention.io/api/mentions.jf2?token=${WEBMENTIONS_STUFF}&per-page=900`;
  const res = await EleventyFetch(url, {
    duration: "1h",
    type: "json",
  });
  const webmentions = res;
  return {
    mentions: webmentions.children,
  };
}

This adds the import dotenv from 'dotenv'; to it. If you already trigger that elsewhere, disregard this adjustment.

Additionally, don't forget to add these to your eleventy.js (or eleventy.config.js) file.

eleventyConfig.addFilter("webmentionsByUrl", webmentionsByUrl);
eleventyConfig.addFilter("plainDate", plainDate);

Since I no longer have a ./config/filters/index.js I added the filters directly to my eleventy.config.js file:

export const webmentionsByUrl = (webmentions, url) => {
  const allowedTypes = {
    likes: ["like-of"],
    reposts: ["repost-of"],
    comments: ["mention-of", "in-reply-to"],
  };

  const sanitize = (entry) => {
    if (entry.content && entry.content.html) {
      entry.content = sanitizeHTML(entry.content.html, {
        allowedTags: ["b", "i", "em", "strong", "a"],
      });
    }
    return entry;
  };

  const pageWebmentions = webmentions
    .filter(
      (mention) => mention["wm-target"] === "https://stuffandthings.lol" + url
    )
    .sort((a, b) => new Date(b.published) - new Date(a.published))
    .map(sanitize);

  const likes = pageWebmentions
    .filter((mention) => allowedTypes.likes.includes(mention["wm-property"]))
    .filter((like) => like.author)
    .map((like) => like.author);

  const reposts = pageWebmentions
    .filter((mention) => allowedTypes.reposts.includes(mention["wm-property"]))
    .filter((repost) => repost.author)
    .map((repost) => repost.author);

  const comments = pageWebmentions
    .filter((mention) => allowedTypes.comments.includes(mention["wm-property"]))
    .filter((comment) => {
      const { author, published, content } = comment;
      return author && author.name && published && content;
    });

  const mentionCount = likes.length + reposts.length + comments.length;
  const data = { likes, reposts, comments, mentionCount };
  return data;
};

export const plainDate = (isoDate) => {
  let date = new Date(isoDate);
  let options = { year: "numeric", month: "long", day: "numeric" };
  let formattedDate = date.toLocaleDateString("en-US", options);
  return formattedDate;
};

With those, I was able to get webmentions working. You'll see them in action on this post and others. I'll note that I did remove the Comments section of the webmentions. I know there's debate on the privacy on webmentions and (as of right now) think this a good compromise.

Likes (5)


Reposts (2)


photo of the author of one of the webmentions for this page photo of the author of one of the webmentions for this page