Static Comments in Jekyll

Posted: Tue, 19 July 2011 | permalink | 8 Comments

When I recently switched my blog over to Jekyll as my blog/site generation platform, one of the driving forces was implementing comments. I’ve been a comment-free blogger for years, but I’ve just decided to change my opinions on things and see what happens. (Turns out: you get some cool comments. And a lot of spam.)

However, the standard advice when it comes to handling comments with Jekyll is “use Disqus” (or, very occasionally, some other Insert-Javascript-Here “cloud” commenting service). Not being one to stand for the conventional wisdom, and given that I’m allergic to “the cloud”, I decided to go a different way – an all-static comment handling system for Jekyll.

First off, you need a way to render comments inside Jekyll. This was disturbingly easy with Jekyll’s plugin system. With around 30 lines of Ruby, it was done. It simply reads a pile of YAML files from a _comments directory, and adds them to the individual blog post objects in the templating system, which can then be iterated over when rendering a post.

Obviously, you need to also adjust your blog post templates to suit. This is fairly straightforward; just render each of page.comments in a list. Adding a comment submission form is also necessary, and similarly trivial.

The only “moving part” in this whole system is the bit of code that handles comment form submissions. The simplest way to handle it, which is what I’ve gone with, is a few lines of PHP that writes the contents of the form out as YAML and e-mails it to me. Although I’m not a fan of PHP for web applications, this is sort of job is where PHP excels – it’s ubiquitous, trivial to deploy, and easy to understand (in small doses). Using a CGI or anything larger (like, say, a sinatra app) would be massive overkill.

Since I’m still a control freak at heart, I’m hand-moderating all comments by the simple expedient of having all blog comments e-mailed to me1, and I have to import them into the blog and re-upload. Mutt makes this trivial; I’ve got a script that I trigger by pressing ‘C’ (for comment) that pipes the message to formail to strip the RFC2822 header, then drops the rest into my blog’s _comments directory. A quick rake upload and they’re published.

If you’re not as obsessive as me about hand-moderating your comments, it wouldn’t be hard to write a slightly different PHP script that commits the comment directly to a git repo2 and re-renders the site. All you’d have to do when you wanted to make a new post is merge those new comment commits from the “live” git repo and go to work. This would then be a completely static site (with all the performance benefits that implies) with immediate-gratification comments.

So, if you’re suspicious of the cloud, or just want to be the cool kid whose blog comments load even when people have turned cookies off, check out my Jekyll static comments plugin.

  1. A side-bonus of running all my blog comments through my e-mail is that all of the comment spam gets handled through my existing spam filter, so there’s no new complexities. The stuff that bogofilter is really sure is spam just goes straight to /dev/null, while the slightly-less-sure stuff goes into an IMAP folder I ignore except when I’m extra-super-bored. Interestingly, bogofilter was already pre-trained and ready to go on my blog spam – it caught most of the spam straight away, with no additional training from me, and after being trained on two examples, it’s now going great guns auto-flushing the one persistent spammer who hammers one particular old post a couple of times a day with link farms.

  2. I’d strongly recommend having some sort of anti-spam setup before you blindly render the comments onto your site, lest your comments list looks like complete balls within a matter of days.


From: Steve Kemp
2011-07-19 20:27

Thats very similar to how I have comments handled on my own static-blog.

Comments are written to disk via a simple CGI script, and also emailed to me. I move the comments that are submitted from ./comments/ to ./comments/good or ./comments/bad via a keybinding in mutt.

Anything that is a good comment gets added the next time I re-render, and anything that is a bad comment gets added to my firewall such that they can no longer view my blog or submit new comments.

From: Guillermo Garron
2012-03-15 13:22

Wow, this is a great idea. I’ve just removed comments from my site, for two reasons.

  1. Because of the spam
  2. Because I was using Disqus, and that makes my site slower.

I’m not going to run a super-fast-jekyll blog just to slow it down because of Disqus Java Script.

I’ll have to read a little more about Mutt, which seems to be the heart of your solution. As well as the the solution for Steve Kemp in the previous comment.

Thanks again.

From: Matt Palmer
2012-03-15 15:28

Hi Guillermo,

I wouldn’t say mutt is “the heart” of my solution, but it certainly helps. Any MUA capable of piping a message through a program would provide much the same outcome. You can also have the script that receives the comment POST do things other than send an e-mail – it could, for instance, put the comments in a directory on the server for your to periodically download and review, if that was your preference. The nice thing is, it’s flexible enough to do whatever you prefer to do.

From: Tobias
2012-03-18 23:18

Hey Matt,

with little modifications, your Jekyll-Plugin works like a charme for me in my very young Octopress-Blog.

I felt very the same about Disqus-Comments. More than this German data privacy laws (Datenschutzrecht) is very restrictive about passing sensible data (like IP-Adresses) to external servies, when hosting of your own. So your solution provides as much privacy I can offer and being extensible enough for future adaptions.

Thanks a lot!

From: Matt Palmer
2012-03-19 06:48

Hi Tobias,

Glad to hear my plugin helped you out. Are the modifications you made “general purpose”, or are they just tweaks to make it work better for you? If the former, I’d love to incorporate them back into the plugin.

From: m-r-r
2013-07-22 00:54


I reused your plugin for my website, and it works fine :-)

I only changed the backend: I have a account that allow me to run CGI scripts, so i re-wrote the backend in Python.

My new backend has the following features:

  • It sends multipart emails: the comment entered by the visitor is shown as text with Content-Disposition: inline and the YAML body is attached with Content-Disposition: attachment.
    The only thing i have to do to in order to save a comment is clicking on the YAML file in my webmail and saving it on the disk.
  • The multipart email has additional MIME fields: the IP address of the visitor is saved in the X-Remote-Address field, the user agent is saved in X-User-Agent, and the field X-Post-Id contains the post_id.
    This is useful for creating email filters.
  • It supports Gravatar avatars: the MD5 hash of the visitor’s email is used to get the URL on his/her avatar on
    The URL of the picture is stored in a YAML field and displayed on my Jekyll templates.
  • It can display error messages: if the user has forgottent to enter a name or an email, a message will be shown. The script also show a message if the SMTP server is unreachable.
  • The script can also display its own source code, so here is the code.

This code is a bit dirty, but i hope it will be useful to someone.

p.s.: Here is a mirror, in the case I change the script’s URL.

From: Martin
2014-01-30 09:40


is this plugin still uptodate? I always get this error while trying to rebuild my blog after adding your plugin:

/home/martin/blog/_plugins/static_comments.rb:24:in `to_liquid': wrong number of arguments (1 for 0) (ArgumentError) It would be nice if you could tell me how to use it. :)

Best regards Martin

2014-02-12 08:42

Hi Martin,

I haven’t kept the plugin up-to-date with changes in Jekyll. I still use an older version of Jekyll myself (0.10.0), since I have no need for features which may have been added, and the chances of a security bug are pretty much nil. That, plus having had no reports of any problems (before now) has meant that I haven’t checked compatibility issues.

I always get this error while trying to rebuild my blog after adding your plugin:

/home/martin/blog/_plugins/static_comments.rb:24:in `to_liquid’: wrong number of arguments (1 for 0) (ArgumentError)

Looks like newer versions of Jekyll have added an optional parameter to to_liquid. I’ve updated the code on github such that that should be handled correctly now.

Post a comment

All comments are held for moderation; markdown formatting accepted.

This is a honeypot form. Do not use this form unless you want to get your IP address blacklisted. Use the second form below for comments.
Name: (required)
E-mail: (required, not published)
Website: (optional)
Name: (required)
E-mail: (required, not published)
Website: (optional)