A commenting system for Jekyll
Jekyll is a powerful blog-aware static site generator. Due to the nature of static sites, including dynamic content — in particular, user-generated content — on a page can be quite challenging. A typical example of that is a blog's commenting system. How to serve that content with an application that consists of pure static HTML files?
As I described in this post and, more in depth, in this post, there are several options to address this limitation. Third-party commenting platforms like Disqus are quite popular and easy to implement.
However, as explained by Tom Preston-Werner in this talk, that comes with the huge caveat of not hosting the comments data, taking away one of the great selling points of Jekyll — the fact that the entire data is hosted together in a repository, not scattered through a myriad of databases and servers.
Other approaches include the actual comments with the rest of the data, but require either a manual build or a complex Continuous Integration process. That makes the integration with GitHub Pages much more difficult.
Jekyll Discuss is a Node.js server-side middleman that handles comments as POST requests from a form, creates data files with its contents and pushes them to a GitHub repository. When using GitHub Pages, that will automatically trigger a build and the new data files will be part of the generated site.
There was a previous iteration of this project written in PHP, which I'll no longer maintain.
This project is still pretty much at a point where it's made to solve my specific needs — a commenting system to use with Jekyll, GitHub Pages and Mailgun. I'm always happy to make it as generic and flexible as possible, so please feel free to change it in any way you see fit and submit a pull request.
-
Install via NPM
npm install jekyll-discuss cd jekyll-discuss
-
Edit and rename template config file
vi config.template mv config.template config
-
Start server
node app.js
Jekyll Discuss consists essentially of an Express server that handles requests, and a Bash script that pushes files to GitHub. Both of these components read information from a shared config file, which contains the following entries.
Key | Mandatory | Description |
---|---|---|
SERVER_HTTP_PORT |
YES | Port to be used by the HTTP version of the Express server |
SERVER_HTTPS_PORT |
No | Port to be used by the HTTPS version of the Express server |
SERVER_HTTPS_KEY |
No | Path to the certificate key to be used by the HTTPS server |
SERVER_HTTPS_CRT |
No | Path to the certificate file to be used by the HTTPS server |
SERVER_HTTPS_PASSPHRASE |
No | Passphrase to be used with the HTTPS certificate |
COMMENTS_DIR_FORMAT |
YES | Path and format of the comments directory (e.g. _data/comments/@post-slug ) |
COMMENTS_FILE_FORMAT |
YES | Path and format of the comment files (e.g. @timestamp-@hash.yml ) |
GIT_USERNAME |
YES | Username to use when pushing comments to GitHub |
GIT_TOKEN |
YES | GitHub personal access token (info) |
GIT_USER |
YES | GitHub user name |
GIT_EMAIL |
YES | GitHub user email |
GIT_REPO |
YES | Path to the local copy of the repository |
GIT_REPO_REMOTE |
YES | Repository URL (.git) |
GIT_COMMIT_MESSAGE |
YES | Message to be used on commits |
SUBSCRIPTIONS_DATABASE |
No | Path to the file-based database used to manage subscriptions |
SUBSCRIPTIONS_NOTIFY_ALL |
No | Email address to where notifications for all posts are sent |
MAILGUN_DOMAIN |
No | Mailgun domain from where to send subscription notifications |
MAILGUN_KEY |
No | Mailgun key |
MAILGUN_FROM |
No | Sender name and email address for subscription notifications |
Jekyll Discuss will be expecting POST requests containing the following fields:
Field | Description |
---|---|
name |
Commenter's name |
email |
Commenter's email address |
url |
Commenter's URL (optional) |
message |
Comment body |
company |
Honeypot field for basic spam detection (info) |
subscribe |
Whether to notify the commenter of future comments by email (must equal subscribe ) |
post-slug |
Post slug |
post-title |
Post title |
post-url |
Post URL |
On the Jekyll side, showing comments for a post can be done simply by iterating through a set of data files.
Example:
{% if site.data.comments[post_slug] %}
{% assign comments = site.data.comments[post_slug] | sort %}
{% for comment in comments %}
<div class="comment">
<h3 class="comment__author"><a href="{{ comment[1].url }}">{{ comment[1].name }}</a></h3
<p class="comment__date">{{ comment[1].date }}</p>
<img class="comment__avatar" src="https://www.gravatar.com/avatar/{{ comment[1].hash }}?d=mm&s=180">
{{ comment[1].message }}
</div>
{% endfor %}
{% endif %}
Jekyll Discuss can be used with Mailgun to send email notifications, allowing commenters to subscribe to new comments on any post. To do this, fill in the Mailgun related fields in the configuration file and edit the email templates that ship with the repo.
Here's an example (email-templates/new-comment.template.html
):
<!-- New comment on Eduardo saying things -->
Hi {{ subscriber }},<br><br>
{{ commenter }} just commented on the post titled "{{ title }}" you subscribed to on <a href="https://eduardoboucas.com/blog">Eduardo saying things</a>.<br><br>
Click <a href="https://eduardoboucas.com{{ link }}">here</a> to see the comment or <a href="https://aws.bouc.as/jekyll-discuss/unsubscribe/{{ unsubscribe }}">unsubscribe</a> from future notifications.<br><br>
Best,<br>
Eduardo
The first line of the file, wrapped inside HTML comments, will be used as the subject of the email messages that use this template. The {{ subscriber }}
, {{ commenter }}
, {{ link }}
and {{ unsubscribe }}
placeholders will be automatically replaced by the values passed by the subscriptions
module:
var data = {
title: parsedData['post-title'],
slug: parsedData['post-slug'],
link: parsedData['post-url'],
subscriber: subscription.name,
commenter: parsedData['name'],
unsubscribe: subscription._id
};
mailman.send('new-comment', subscription.email, data, function (body, error) {
if (error) {
console.log('[!] Error sending email: ' + error);
}
});