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!
My file is the following
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| {{ define "css" }}
<link rel="stylesheet" type="text/css" href="{{.Site.BaseURL}}css/article.css" />
{{ end }}
{{ define "main" }}
{{ if eq .Type "blog" }}
{{ if not .Params.menu }}
<p>
<i>
<time datetime="{{ .Date.Format "2006-01-02" }}" pubdate>
{{ .Date.Format (default "2006-01-02" .Site.Params.dateFormat) }}
</time>
</i>
</p>
{{ end }}
{{ end }}
{{ if .Params.toc }}
<details>
<summary>Table of Contents</summary>
{{ .TableOfContents }}
</details>
{{ end }}
<content>
{{ .Content }}
</content>
{{ partial "comments/comments.html" .}}
<p>
{{ range (.GetTerms "tags") }}
<a href="{{ .Permalink }}">#{{ .LinkTitle }}</a>
{{ end }}
</p>
{{ end }}
|
You can find the newest file at my repo.
Now is the time to add the comment system.
Just create a file layouts/partials/comments/comments.html and paste the following content:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
| {{ with .Params.comments }}
<div class="article-content">
<article>
<h2>Comments</h2>
<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>
<p id="mastodon-comments-list"><button id="load-comment">Load comments</button></p>
<noscript><p>You need JavaScript to view the comments.</p></noscript>
<script type="text/javascript">
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
document.getElementById("load-comment").addEventListener("click", function() {
document.getElementById("load-comment").innerHTML = "Loading";
fetch('https://{{ .host }}/api/v1/statuses/{{ .id }}/context')
.then(function(response) {
return response.json();
})
.then(function(data) {
if(data['descendants'] &&
Array.isArray(data['descendants']) &&
data['descendants'].length > 0) {
document.getElementById('mastodon-comments-list').innerHTML = "";
data['descendants'].forEach(function(reply) {
reply.account.display_name = escapeHtml(reply.account.display_name);
reply.account.emojis.forEach(emoji => {
reply.account.display_name = reply.account.display_name.replace(`:${emoji.shortcode}:`,
`<img src="${escapeHtml(emoji.static_url)}" alt="Emoji ${emoji.shortcode}" height="20" width="20" />`);
});
mastodonComment =
`<div class="mastodon-comment">
<div class="avatar">
<img src="${escapeHtml(reply.account.avatar_static)}" height=60 width=60 alt="">
</div>
<div class="content">
<div class="author">
<a href="${reply.account.url}" rel="nofollow">
<span>${reply.account.display_name}</span>
<span class="disabled">${escapeHtml(reply.account.acct)}</span>
</a>
<a class="date" href="${reply.uri}" rel="nofollow">
${reply.created_at.substr(0, 10)}
</a>
</div>
<div class="mastodon-comment-content">${reply.content}</div>
</div>
</div>`;
var DOMPurifyScript = document.createElement('script');
DOMPurifyScript.src = "/js/comments/purify.min.js";
DOMPurifyScript.onload = function() {
document.getElementById('mastodon-comments-list').appendChild(DOMPurify.sanitize(mastodonComment, {'RETURN_DOM_FRAGMENT': true}));
};
document.body.appendChild(DOMPurifyScript);
});
} else {
document.getElementById('mastodon-comments-list').innerHTML = "<p>Not comments found</p>";
}
});
});
</script>
</article>
</div>
{{ end }}
|
You can also find the newest comment partial here.
If you’re lazy you can also clone this:
1
| wget 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
:
1
| wget https://raw.githubusercontent.com/cure53/DOMPurify/main/dist/purify.min.js
|
You’re done copying code! Add some comments!
To add comments, add to your file header:
1
2
3
4
| comments:
host: toot.teckids.org
username: tuxilio
id: 112290674602230410
|
host
: just your hostusername
: your usernameid
: post id
End#
You’re done 🎉!