WordPress to Jekyll part 2 - Comments & commenting
- 📅
- 📝 1,049 words
- 🕙 5 minutes
- 📦 Development
- 🏷️ WordPress, Jekyll, Azure
- 💬 6 responses
I do enjoy discussion and debate, whether designing software or writing articles. Many times the comments have explored the subject further or offered corrections or additional insights and tips. They are vital on my blog, and I was disappointed that Jekyll provides nothing out of the box to handle them.
Third-party solutions like Disqus exist that require you either pay a subscription or have ads inlined with the comments. That $9/month adds up. The alternative of injecting ads onto my blog to support comment infrastructure doesn’t sit right with me.
Storing comments
So what does Jekyll have that we could build upon?
One useful feature is the ability to process ‘site data’ held in YML files as a data source for generating content via the Liquid templating language.
So, if we store each comment in a file named _data/{blog_post_slug}/{comment_id}.yml
with this format:
id: 12345
name: Damien Guard
email: [email protected]
gravatar: dc72963e7279d34c85ed4c0b731ce5a9
url: https://damieng.com/
date: 2007-12-18T18:51:55Z
message: "This is a great solution for 'dynamic' comments on a static blog!"
This gives us a model where we can gather all the ones that respond to a post by traversing a single folder and performing some sorting.
Using one file per-comment, we also make deleting, approving and managing comments as easy as possible.
Rendering comments
Now we can create test data and attempt rendering. I created three Jekyll includes that match my WordPress theme. They are:
- Render an individual comment (comment.html)
- Show a form to accept a new comment (new-comment.html)
- Loop over individual comments for a post (comments.html)
I’ve included all three includes you can copy to your Jekyll _includes
folder.
The simplest option is to include the comments.html file. For example, my blog post template file looks like this:
--- layout: default ---
<div class="post {{ page.class }}">
{% include item.html %} {{ page.content }} {% include comments.html %}
</div>
You’ll also need to add the following line to your Jekyll _config.yml
so my sort function can work due to a couple of restrictions in Jekyll.
emptyArray: []
Exporting comments from WordPress
The next step is getting the comments out of your existing system. I created a PHP script that extracts my WordPress comments into individual files with the right metadata and structure.
- Upload this file to your site
- Access export-blog-comments.php via your browser and wait for it to complete
- Download the
/comments/
folder over SSH and then remove it and the export-blog-comments.php from your server - Copy the
/comments/
folder into your Jekyll_data/
folder
Disqus users should check out Phil Haack’s Disqus exporter!
Accepting new comments with an Azure function
We can now render existing comments, but what about accepting new ones?
At a minimum, we need to accept an HTTP form post and commit a new YML file. It needs validation, a redirect to a thanks page, and the new YML file somewhere. I decided on a pull request for ease-of-use and to act as moderation. Merging the PR causes a site rebuild that publishes the new comment. :)
Platform and choices
I chose:
- GitHub to host my blog and comments as I use it for my code projects
- Azure Function App for the form-post-to-pull-request — details below
- C# for the function — a great language I know with useful libraries
I went with Azure Function Apps for a few reasons:
- They accept HTTP/HTTPS directly without configuring an “API Gateway”
- Comment posting is a short-lived operation that happens infrequently
- Free monthly grants of 1 m executions/400,000 GB-s should mean no charge
- Taking a second or two to spin-up the function should be fine in this context
(Disclaimer: I have a free MSDN subscription that includes Azure credits as part of my ASP Insider membership, although I do not expect this solution to consume any of it)
Other platforms
You could easily port this to another C#-capable environment — or port the solution entirely to another language.
If you many comments, you could run the function on three platforms and round-robin the DNS to take advantage of the free usage tiers on each.
How it works
The form receiver function for comments relies on a couple of libraries to deal with YML and GitHub but is otherwise self-explanatory. What it does is:
- Receives the form post over HTTP/HTTPS
- Attempts to create an instance of the Comment class by mapping form keys to constructor args
- Emits errors if any constructor args are missing (unless they have a default)
- Creates a new branch against your default using the GitHub OctoKit.NET library
- Creates a commit to the new branch with the
Comment
serialized to YML using YamlDotNet - Creates a pull request to merge the branch with an informative title and body
Installation
Installation requires a few steps but can then just update whenever you update your fork.
- Fork the jekyll-blog-comments-azure repo
- Create a Function App in the Azure portal (I went with consumption plan on Windows)
- Go to Deployment Options, tap Setup and choose GitHub
- Authorize it to your GitHub account
- Configure Project to your fork of jekyll-blog-comments-azure
- Configure Branch to master
You also need to set-up two Application Settings for your function so it can create the necessary pull requests. They are:
GitHubToken
should be a personal access token withrepo
rightsPullRequestRepository
should contain the org and repo name, e.g.damieng/my-blog
The final step is to modify your Jekyll _config.yml
so it knows where to post the form. For example:
comments:
receiver: https://damiengapp.azurewebsites.net/api/PostComment
You should now be able to post a comment on your blog and see it turn up as a pull request against your repository!
Extra steps
- You can have post authors replies highlighted differently
- Threaded comments could be supported — feel free to send a pull request
- Anti-spam measures need to improve at some point — currently, this is just client-side in JS that requires a second ‘Confirm comment’ click
In Part 3 of the series, I’ll go into how I implemented my site search with Algolia!
[)amien
6 responses to WordPress to Jekyll part 2 - Comments & commenting
I’ve not had a problem with Azure not building the function any more. Once it is setup and running it has stayed there.
I don’t think you’d ever pay for them unless you’re running some kind of massive site. I never have.
Hi Damian, I just noticed your recent post https://mastodon.social/@damieng/109625494541215747 linking to this very interesting and resourceful page.
My initial and very basic question: Would any of this work with a blog which is strictly not self-hosted but entirely provided through GitHub; such as for instance with https://bcrowell.github.io/ ?
Thanks!
p.s. Since there are preceeding comments with apparently unanswered questions on this page … I may repeat my question in a while through mastodon.
How much does it cost to run the function in Azure?
I am also starting my own blog. I have bought hosting and all, your blog literally helped me in understanding where to start. Will update more here, well done for the effort.
For the Function app, GitHub integration is quite buggy for me. It keeps getting removed, and I have to setup it up all over again. Is it so in your experience too?!
Thanks for this… it’s awesome to finally have something that isn’t hosted elsewhere.... I’m having just one problem though and I feel like I am completely missing something.
When I submit the form on my Jekyll blog, I get the following error. Form value missing for post_id Form value missing for message Form value missing for name
What boggles my mind is I’ve checked and doublechecked, the form references the correct ids and field names. I just can’t seem to find what I’m missing.