eleventy-cache-webmentions

Cache webmentions using eleventy-fetch and make them available to use in collections, layouts, pages, etc. in Eleventy.
There are 17 stargazers on GitHub and it has over 8,150 downloads on npm.

A hand with a tattoo reading, “Cache up Sucker” with a dollar sign in the middle

eleventy-cache-webmentions on GitHub eleventy-cache-webmentions Releases eleventy-cache-webmentions License

Breaking changes for v2.0.0!

Version 2.0.0 introduces a breaking change for those migrating from earlier versions of the plugin. This affects usage of the plugin from JavaScript files; specifically, you will need to make a small change to the way that you require() the plugin by removing an extra set of parentheses:

v1.2.5 and below

require("@chrisburnell/eleventy-cache-webmentions")()

v2.0.0 and above

require("@chrisburnell/eleventy-cache-webmentions")

Quick Guide Permalink

I wrote a quicker and simpler guide to getting this Eleventy plugin working that cuts out all the fluff and extra details.

Check it out: Webmention Setup for Eleventy.

Installation Permalink

Available on npm:

npm install @chrisburnell/eleventy-cache-webmentions --save-dev

You can also download it directly from GitHub:

https://github.com/chrisburnell/eleventy-cache-webmentions/archive/main.zip

Inside your Eleventy config file, use addPlugin() to add it to your project:

const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions")

module.exports = function(eleventyConfig) {
	eleventyConfig.addPlugin(pluginWebmentions, {
		// These 3 fields are all required!
		domain: "https://example.com",
		feed: "https://webmentions.example.com?token=S3cr3tT0k3n",
		key: "array_of_webmentions"
	})
}

Make sure you get the correct values for this configuration. Check below for both Webmention.io configuration and go-jamming configuration.

Full options list
const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions")

module.exports = function(eleventyConfig) {
	eleventyConfig.addPlugin(pluginWebmentions, {
		// The website you’re fetching Webmentions for.
		domain: "https://example.com",

		// The URL of your Webmention server’s feed for your website.
		feed: "https://webmentions.example.com?token=S3cr3tT0k3n",

		// The key in your Webmention server’s feed that contains the array of
		// Webmentions.
		key: "array_of_webmentions",

		// Where the cached file containing your Webmentions is stored.
		// See: https://www.11ty.dev/docs/plugins/cache/#cache-directory
		directory: ".cache",

		// The length of time to wait between fetching fresh Webmentions.
		// See: https://www.11ty.dev/docs/plugins/cache/#change-the-cache-duration
		duration: "1d",

		// The name of the file generated by Eleventy Fetch.
		uniqueKey: "webmentions",

		// What HTML elements are allowed within Webmention content.
		// Elements/attributes not here are removed when getting the content of
		// a Webmention.
		// See: https://www.npmjs.com/package/sanitize-html
		allowedHTML: {
			allowedTags: ["b", "i", "em", "strong", "a"],
			allowedAttributes: {
				a: ["href"],
			},
		},

		// An Array of URLs from which Webmentions are exclusively kept.
		allowlist: [],

		// An Array of URLs from which Webmentions are discarded.
		blocklist: [],

		// An Object of key-value string pairs containing from-to URL
		// replacements on your website.
		urlReplacements: {},

		// Maximum number of characters in a Webmention’s HTML content, beyond
		// which point a different message is shown, referring to the original
		// source.
		maximumHtmlLength: 2000,

		// The glue-y part of the message displayed when a Webmention content’s
		// character count exceeds `maximumHtmlLength`.
		maximumHtmlText: "mentioned this in",
	})
}

Usage Permalink

eleventy-cache-webmentions comes with a number of ways of accessing your Webmentions as Global Data in both JavaScript and Liquid/Nunjucks as well as a series of Eleventy Filters and JavaScript Functions for filtering, sorting, and reading properties about each Webmention:

Global Data

JavaScript
const {
	defaults, // default options for the plugin
	webmentionsByUrl, // Object containing Arrays of Webmentions by URL
} = require("@chrisburnell/eleventy-cache-webmentions")
Liquid / Nunjucks
{# default options for the plugin #}
{{ webmentionsDefaults }}
{# Object containing Arrays of Webmentions by URL #}
{{ webmentionsByUrl }}

Filters

JavaScript
const {
	getWebmentions, // get Array of Webmentions for a given URL
	getByTypes, // filter Webmentions by their response type
	getPublished, // get received/published time of a Webmention
	getContent, // get content of a Webmention
	getSource, // get source URL of a Webmention (where it's from)
	getTarget, // get target URL of a Webmention (where it's sent to)
	getType, // get response type of a Webmention
} = require("@chrisburnell/eleventy-cache-webmentions")

// This is NOT the best way to get Webmentions!
// See "Attach Webmentions to Pages using Directory Data" below.
const webmentions = getWebmentions({
	domain: "https://example.com",
	feed: "https://webmentions.example.com?token=S3cr3tT0k3n",
	key: "array_of_webmentions"
}, "https://example.com/specific-page/")

const responsesOnly = getByTypes(webmentions, ['mention-of', 'in-reply-to'])

webmentions.forEach((webmention) => {
	const published = getPublished(webmention)
	const content = getContent(webmention)
	const source = getSource(webmention)
	const target = getTarget(webmention)
	const type = getType(webmention)
})
Liquid / Nunjucks
{# get Array of Webmentions for a given URL #}
{% set webmentions = ('https://example.com' + page.url) | getWebmentions %}

{# filter Webmentions by their response type #}
{{ set responses = webmentions | getWebmentionsByTypes(['mention-of', 'in-reply-to']) }}

{% for webmention in webmentions %}
    {# get received/published time of a Webmention #}
    {{ webmentions | getWebmentionPublished }}
    {# get content of a Webmention #}
    {{ webmentions | getWebmentionContent }}
    {# get source URL of a Webmention (where it's from) #}
    {{ webmentions | getWebmentionSource }}
    {# get target URL of a Webmention (where it's sent to) #}
    {{ webmentions | getWebmentionTarget }}
    {# get response type of a Webmention #}
    {{ webmentions | getWebmentionType }}
{% endfor %}

Attach Webmentions to Pages using Directory Data Permalink

Using Eleventy’s Data Cascade, you can attach Webmentions to each page by using Directory Specific Data Files.

For example, if you have a folder, /pages/, and want to attach Webmentions to each page, create or add the following to a pages.11tydata.js file within the folder:

const { getWebmentions, getPublished } = require("@chrisburnell/eleventy-cache-webmentions")

module.exports = {
	eleventyComputed: {
		webmentions: (data) => {
			// Get this page's Webmentions as an Array (based on the URL)
			const webmentionsForUrl = getWebmentions({
				domain: "https://example.com",
				feed: "https://webmentions.example.com?token=S3cr3tT0k3n",
				key: "array_of_webmentions"
			}, "https://example.com" + data.page.url)

			// If there are Webmentions for this page
			if (webmentionsForUrl.length) {
				// Sort them (based on when they were received/published)
				return webmentionsForUrl.sort((a, b) => {
					return getPublished(b) - getPublished(a)
				})
			}
			// Otherwise, return an empty Array
			return []
		},
	},
}

This attaches an Array containing Webmentions to each page (based on its URL). You can then access this Array of Webmentions with the variable, webmentions, within a Layout, Include, or from the page itself:

{% for webmention in webmentions %}
    {# Do something with each Webmention #}
{% endfor %}

These Arrays of Webmentions can even be accessed when building Collections, allowing you to create a Collection of pages sorted by their number of Webmentions, for example:

module.exports = (eleventyConfig) => {
	eleventyConfig.addCollection("popular", (collection) => {
		return collection
			.sort((a, b) => {
				return b.data.webmentions.length - a.data.webmentions.length
			})
	})
}

Without Directory Data Permalink

If you would rather get Webmentions for a given page directly from a Layout/Include/Page itself, you can do so using the Filter, getWebmentions:

{% set webmentions = ('https://example.com' + page.url) | getWebmentions %}
{% for webmention in webmentions %}
    ...
{% endfor %}

Get specific types of Webmentions Permalink

Instead of getting all the Webmentions for a given page, you may want to grab only certain types of Webmentions. This is useful if you want to display different types of Webmentions separately, e.g.:

{% set bookmarks = webmentions | getTypes(['bookmark-of']) %}
{% set likes = webmentions | getTypes(['like-of']) %}
{% set reposts = webmentions | getTypes(['repost-of']) %}

{% set replies = webmentions | getTypes(['mention-of', 'in-reply-to']) %}

Get all Webmentions at once Permalink

If you need it, the plugin also makes available an Object containing your cached Webmentions organised in key:value pairs, where each key is a full URL on your website and its value is an Array of Webmentions sent to that URL:

{% set count = 0 %}
{% for url, array in webmentionsByUrl %}
	{% set count = array.length + count %}
{% endfor %}
<p>This website has received {{ count }} Webmentions!</p>

Webmention.io Permalink

Webmention.io is a in-place Webmention receiver solution that you can use by authenticating yourself via IndieAuth (or host it yourself), and, like so much other publicly-available IndieWeb software, is built and hosted by Aaron Parecki.

Add your token

Get set up on Webmention.io and add your API Key (found on your settings page) to your project as an environment variable, i.e. in a .env file in the root of your project:

WEBMENTION_IO_TOKEN=njJql0lKXnotreal4x3Wmd

Set your feed and key config options

The example below requests the JF2 file format, which I highly recommend using; although, there is a JSON format available from Webmention.io as well. The official documentation has more information on how to use these two formats.

The key difference between the two feed formats is in the naming of the keys: the JF2 format holds the array of Webmentions in the children key, whereas the JSON format holds them in the links key. The JF2 format, however, provides keys and values that more tightly-align with microformats, the method I recommend the most for marking up HTML such that it can be consumed and understood by search engines, aggregators, and other tools across the IndieWeb.

const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions")

module.exports = function(eleventyConfig) {
	eleventyConfig.addPlugin(pluginWebmentions, {
		domain: "https://example.com",
		feed: `https://webmention.io/api/mentions.jf2?domain=example.com&per-page=9001&token=${process.env.WEBMENTION_IO_TOKEN}`,
		key: "children"
	})
}

If you want to use the JSON format instead, make sure that you replace mentions.jf2 in the URL with mentions.json and change the value of the key from children to links.

go-jamming Permalink

go-jamming is a self-hosted Webmention sender and receiver, built in Go by Wouter Groeneveld and available with more information on his personal git instance.

Add your token

Once you’ve set up your go-jamming server and you’ve defined your token, you’ll need add it to your project as an environment variable, i.e. in a .env file in the root of your project:

GO_JAMMING_TOKEN=njJql0lKXnotreal4x3Wmd

Set your feed and key config options

const pluginWebmentions = require("@chrisburnell/eleventy-cache-webmentions")

module.exports = function(eleventyConfig) {
	eleventyConfig.addPlugin(pluginWebmentions, {
		domain: "https://example.com",
		feed: `https://jam.example.com/webmention/example.com/${process.env.GO_JAMMING_TOKEN}`,
		key: "json"
	})
}

You can also send an anonymous reply (using Quill and Comment Parade).

47 Responses

  1. 19 Likes
  2. 5 Reposts
  3. 4 Links
  4. 17 Stargazers
  1. Fixed a bug in eleventy-cache-webmentions from a silly assumption I made about determining a since value to get new webmentions when the cache exists.