Fediverse comments with Publii

I decided I wanted something a little slicker than a command line for my new blog so I went with Publii. Unfortunately, that made integrating pulling a thread from Mastodon for comments a little bit trickier than I think it would’ve been otherwise. In this post I’ll go through how I wound up doing it.

For Mastodon comments I’m using this widget by Daniel Pecos Martínez. You’ll want to add mastodon-comments.js to your site via the file manager (Tools & Plugins) and then add the links to purify.js and Font Awesome in the custom HTML section for the head of your site (also in Tools & Plugins) as well as link mastodon-comments.js. If that file lives in the root of your website, you can link it like so:

<script type="module" src="/mastodon-comments.js"></script>

The easiest way then to add comments is to just plonk the <mastodon-comments/> widget at the bottom of your posts. If that’s alright with you, then things are easy and you don’t have to continue reading. Just do that.

I thought that was a little bit untidy though, so the first I did was add the <mastodon-comments/> widget to the “after every post” section for custom HTML. Obviously, this means I can’t embed the tootId property in the widget though, so I had to solve that. My first thought was to put <script>mastodonCommentsId="109574160582937075"</script> in my post, and then grab that global in the mastodon-comments.js JavaScript code. That worked fine, but it’s still untidy because the script tag still shows up in the RSS feed.

My second attempt involved creating a commentsid.json file in the file manager, which looks a little like this:

{
    "testing-fediverse-comments": "113114374538482908"
    , "what-the-ultima-series-means-to-me": "113125860938508763"
}

Just a simple json file mapping post slugs to the correct Mastodon post ID. The plan was that the code would fetch this json, parse it, and then grab the correct ID using the current post’s slug.

To do that I want to make sure the json is always loaded before the widget tries to load the comments though. Inside connectedCallback the code calls this.respondToVisibility which creates an IntersectionObserver that’s used to lazy load the comments. So long as that observer doesn’t exist, the comments won’t load, so I replaced that with my own function loadCommentsId.

Inside that function I fetch /commentsids.json and parse it. Then I use document.querySelector("link[rel='canonical']").href to get the post’s canonical URL and parse out the slug using group 1 of the regular expression /\/posts\/([^\/]+)/.

Note that this works on my site because under “Site settings > URLs” I set “Posts prefix” to “posts”, so every post on my site ends in /posts/<slug>/ with maybe a file at the end. If your site is already up and running and you don’t wanna change that setting, you’ll have to use a different method to capture the post slug.

Finally with my json and post slug in hand I look up the ID, set tootId and call the respondToVisibility function in order to start lazy loading the comments.

I did add a little bit more customization, where the comments section starts out with the text “Comments are not available for this post” and once I verify I have an actual post ID I switch it to the proper comments text, otherwise I set commentsLoaded to true and remove the element with the ID mastodon-stats from the document.

Anyway, hope that helps. If you want to see the full code, it’s right over here. Please note that I made other minor modifications to the HTML and code as well (adding a wrapper div, changing where the date element is on posts, and adding <wbr> in front of any @ beyond the first in usernames.)