One of the biggest disadvantages of static site generators is that they are static and can’t include comments.

In this short blog entry, I’ll explain how to add a comment system to Hugo’s static blog engine. I’ll expand on Carl Schwan’s and Tony Cheneau’s blog article and attempt to make it more accessible to Hugo’s newcomers.

Foreword

Most the hard work has been pulled of by Carl. I just made some minor changes. I hope it will help others like me, willing to bring some life into their blogs.

Tutorial structure

  • modify your existing template to make it possible to add comments
  • adding the comment system
  • copying some Javascript dependencies
  • how to add comments

Getting started

Modify default themes

Creating files

If you have a file at layouts/_default/single.html, you don’t have to copy something. If you don’t have his file - no worries, it’s easy!

Just copy the file themes/your-theme-name/layouts/_default/single.html to layouts/_default/single.html.

Editing files

If you open the file, you’ll see that there is already some content. Just add this line:

1{{ partial "comments/comments.html" .}}

If If you want the comments right above your footer, place this above it. Really simple!

 1{{ define "css" }}
 2<link rel="stylesheet" type="text/css" href="{{.Site.BaseURL}}css/article.css" />
 3{{ end }}
 4
 5{{ define "main" }}
 6  {{ if eq .Type "blog" }}
 7    {{ if not .Params.menu }}
 8      <p>
 9        <i>
10          <time datetime="{{ .Date.Format "2006-01-02" }}" pubdate>
11            {{ .Date.Format (default "2006-01-02" .Site.Params.dateFormat) }}
12          </time>
13        </i>
14      </p>
15    {{ end }}
16  {{ end }}
17  {{ if .Params.toc }}
18    <details>
19      <summary>Table of Contents</summary>
20      {{ .TableOfContents }}
21    </details>
22  {{ end }}
23  <content>
24    {{ .Content }}
25  </content>
26  {{ partial "comments/comments.html" .}}
27  <p>
28    {{ range (.GetTerms "tags") }}
29      <a href="{{ .Permalink }}">#{{ .LinkTitle }}</a>&nbsp;&nbsp;
30    {{ end }}
31  </p>
32{{ end }}

You can find the newest file at my repo.

Adding comment system

Now is the time to add the comment system.

Just create a file layouts/partials/comments/comments.html and paste the following content:

 1{{ with .Params.comments }}
 2<div class="article-content">
 3  <article>
 4  <h2>Comments</h2>
 5  <p>You can use your <a class="link" href="https://joinmastodon.org/">Mastodon</a> account to reply to <a class="link" href="https://{{ .host }}/@{{ .username }}/{{ .id }}">this post</a>.</p>
 6  <p id="mastodon-comments-list"><button id="load-comment">Load comments</button></p>
 7  <noscript><p>You need JavaScript to view the comments.</p></noscript>
 8  <script type="text/javascript">
 9    function escapeHtml(unsafe) {
10      return unsafe
11           .replace(/&/g, "&amp;")
12           .replace(/</g, "&lt;")
13           .replace(/>/g, "&gt;")
14           .replace(/"/g, "&quot;")
15           .replace(/'/g, "&#039;");
16   }
17
18    document.getElementById("load-comment").addEventListener("click", function() {
19      document.getElementById("load-comment").innerHTML = "Loading";
20      fetch('https://{{ .host }}/api/v1/statuses/{{ .id }}/context')
21        .then(function(response) {
22          return response.json();
23        })
24        .then(function(data) {
25          if(data['descendants'] &&
26             Array.isArray(data['descendants']) &&
27            data['descendants'].length > 0) {
28              document.getElementById('mastodon-comments-list').innerHTML = "";
29              data['descendants'].forEach(function(reply) {
30                reply.account.display_name = escapeHtml(reply.account.display_name);
31                reply.account.emojis.forEach(emoji => {
32                  reply.account.display_name = reply.account.display_name.replace(`:${emoji.shortcode}:`,
33                    `<img src="${escapeHtml(emoji.static_url)}" alt="Emoji ${emoji.shortcode}" height="20" width="20" />`);
34                });
35                mastodonComment =
36                  `<div class="mastodon-comment">
37                     <div class="avatar">
38                       <img src="${escapeHtml(reply.account.avatar_static)}" height=60 width=60 alt="">
39                     </div>
40                     <div class="content">
41                       <div class="author">
42                         <a href="${reply.account.url}" rel="nofollow">
43                           <span>${reply.account.display_name}</span>
44                           <span class="disabled">${escapeHtml(reply.account.acct)}</span>
45                         </a>
46                         <a class="date" href="${reply.uri}" rel="nofollow">
47                           ${reply.created_at.substr(0, 10)}
48                         </a>
49                       </div>
50                       <div class="mastodon-comment-content">${reply.content}</div>
51                     </div>
52                   </div>`;
53                var DOMPurifyScript = document.createElement('script');
54                DOMPurifyScript.src = "/js/comments/purify.min.js";
55                DOMPurifyScript.onload = function() {
56                  document.getElementById('mastodon-comments-list').appendChild(DOMPurify.sanitize(mastodonComment, {'RETURN_DOM_FRAGMENT': true}));
57                };
58                document.body.appendChild(DOMPurifyScript);
59              });
60          } else {
61            document.getElementById('mastodon-comments-list').innerHTML = "<p>Not comments found</p>";
62          }
63        });
64      });
65  </script>
66  </article>
67</div>
68{{ end }}

You can also find the newest comment partial here.

If you’re lazy you can also clone this:

1wget https://codeberg.org/Tuxilio/website/raw/branch/main/layouts/partials/comments/comments.html

Copy Javascript dependencies

DOMPurify is used to sanitize the code. Therefore, clone it to static/js/comments:

1wget https://raw.githubusercontent.com/cure53/DOMPurify/main/dist/purify.min.js

Add comments!

You’re done copying code! Add some comments!

To add comments, add to your file header:

1comments:
2  host: toot.teckids.org
3  username: tuxilio
4  id: 112290674602230410
  • host: just your host
  • username: your username
  • id: post id

End

You’re done 🎉!

(This post is my 8th post at #100DaysToOffload challenge)