11ty logo

I decided webmentions would be much better for comments as it works across sites.
It also allows people to comment using Mastodon & Activitypub.

netlify-logo mastodon-logo

Webmention is an open web standard (W3C Recommendation) for conversations and interactions across the web, a powerful building block used for a growing distributed network of peer-to-peer comments, likes, reposts, and other responses across the web.

Implementing Webmentions #

There are a few options on implementing webmentions, some have opted to use clientside requests using javascript with webmention.io json api.

After reading a few articles I opted to have eleventy fetch the webmentions on build.

Using Webmentions in Eleventy - Max Böck
Adding Webmentions to Your Site - Robb Knight

In order to implement this webmention.io & brid.gy need to be setup.

In addition I am also using Github Actions with Netlify Build Hooks to update webmentions every 12 hours.

Webmention.io #

Webmention.io is a service which collects webmentions for your site & provides a json api.

Webmention.io is a hosted service created to easily receive webmentions on any web page.

Setting up webmention.io requires indielogin.

Instructions to add webmention & pingback urls are provided once logged in.

<link rel="webmention" href="https://webmention.io/blog.equk.co.uk/webmention" />
<link rel="pingback" href="https://webmention.io/blog.equk.co.uk/xmlrpc" />

IndieLogin #

Webmention.io uses indielogin to authenticate.

For github you need a link to your github profile with rel=me.

<a href="https://github.com/equk" rel="me">github.com/equk</a>

Brid.gy #

Bridgy connects with social media in order to get webmentions & send them over to webmention.io.

Bridgy connects your web site to social media. Likes, reposts, mentions, cross-posting, and more...

I am using bridgy to connect with Mastodon.

Implementation #

Once brid.gy & webmention.io are setup it's time to implement some code.

Basic idea:

Fetch Webmentions #

Make a request to webmention.io using the api token.

require('dotenv').config()
const API = 'https://webmention.io/api/'
module.exports = async function() {
    const domain = 'blog.equk.co.uk'
    const token = process.env.WEBMENTION_IO_TOKEN
    const url = `${API}mentions.jf2?domain=${domain}&token=${token}`
    try {
        const response = await fetch(url)
        if (response.ok) {
            const feed = await response.json()
            return feed
        }
    } catch (err) {
        console.error(err)
        return null
    }
}

This is a global data file function in src/_data/webmentions.js which provides {{ webmentions }} to templates.

Filtering Webmentions #

A filter is required in order to display webmentions for the current post url.

eleventyConfig.addFilter('webmentionsByUrl', function (webmentions, url) {
.filter(entry => entry['wm-target'] === url)

Final Implementation #

The final fetch implementation involves saving all webmentions to _cache & then only requests new mentions since the last fetch to merge with the existing cache.

The final filter implementation filters by url & uses sanitize-html on the content of comments, only allowing a few specific html tags (no iframes etc).

Using Webmentions in Eleventy - Max Böck

Design #

The most used design seems to have originated from Robb Knight & was inspired by Zach Leatherman.

Adding Webmentions to Your Site - Robb Knight

I tweaked the styles slightly but the core design comes directly from that article.
Grouping of different mentions (likes, boosts, comments) was also taken from the article.

Netlify Caching #

There is a simple caching plugin used for restoring & saving _cache folder on builds.
This is based on @netlify/cache-utils.

// netlify/cache-plugin/index.js
module.exports = {
  async onPreBuild({ utils }) {
    console.log('Restoring ./_cache/ folder')
    await utils.cache.restore('./_cache')
  },
  async onPostBuild({ utils }) {
    console.log('Saving ./_cache/ folder for future builds')
    await utils.cache.save('./_cache')
  },
}
# netlify/cache-plugin/manifest.yml
name: cache-plugin
[[plugins]]
  package = "./netlify/cache-plugin"

Scheduled Builds #

This can be done using a combination of Github Actions & Netlify Build Hooks.

Netlify Build Hook #

Build hooks are URLs you can use to trigger new builds and deploys

Build hooks can be found under Build & Deploy section.
Name this something memorable as the name will show in your deploys for the site.

Github Actions #

Hook Token #

Add token in Github repo (/settings/secrets/actions).
I named it NETLIFY_BUILD_TOKEN.

Github Actions #

Create a Github Action using cron for schedule.

.github/workflows/build-sched.yml

name: Scheduled build
on:
  schedule:
  - cron: '30 2/12 * * *'
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Trigger Build on Netlify
      run: curl -s -X POST "https://api.netlify.com/build_hooks/${TOKEN}"
      env:
        TOKEN: ${{ secrets.NETLIFY_BUILD_TOKEN }}

You should now see scheduled build in Actions for the repo.
The example above triggers builds at 02:30 & 14:30 every day.

Deploys in netlify should show Deploy triggered by hook:

Production main@HEAD
Deploy triggered by hook: Github Actions
Deployed in 19s

Source Code #

The source for my 11ty blog is available on github.

11ty-equk