no-comment is a drop-in replacement for staticman in Jekyll:
- HTML Form ➡️ JSON file
- For Cloudflare Workers
- Creates pull requests against selected branch - you have to appove manually to eliminate comment spam.
- Supports both GitHub and GitLab repositories
- Optional Akismet spam comment checking -- instructions
- "works for me"
- Interested to help? Please open a ticket...
Install nodejs, git and text editor, then install wrangler.
npm install -g wrangler
wrangler loginCreate a fine-grained access token
Settings ➡️ Developer Settings ➡️ Personal access tokens ➡️ Fine-grained tokens
Only select repositories: choose repository to write to
contents: read and writemetadata: read (mandatory)pull requests: read and write
- Save the token somewhere safe after creating it as it will only be displayed once
- Max token validity is 1 year, so remember to come back and do this again in a year
Create a personal access token
Settings ➡️ Access Tokens
read_repository: Necessary to read the Staticman site configapi: Necessary to create and merge merge requests
- Save the token somewhere safe after creating it as it will only be displayed once
- Set an expiration date for your token (recommended: 1 year maximum)
- For self-hosted GitLab instances, make sure your instance is accessible from the internet
- Fork this repository
- Clone to workstation
- Edit
wrangler.toml, set variables:- Common settings:
GIT_AUTHOR: Name for comments (ignored when using personal access token)GIT_EMAIL: email for comments (ignored when using personal access token)GIT_BRANCH_TO_MERGE_INTO: git branch to create pull requests forCOMMENT_DIR: directory to save comments to in repositoryPROVIDER: "github" or "gitlab" depending on which service you want to use
- GitHub specific settings (when using
PROVIDER = "github"):GITHUB_OWNER: GitHub account containing the repository to updateGITHUB_REPO: GitHub repository to update
- GitLab specific settings (when using
PROVIDER = "gitlab"):GITLAB_URL: GitLab instance URL (e.g., "https://gitlab.com/" - include trailing slash)GITLAB_PROJECT_ID: GitLab project ID or path with namespace (e.g., "username/repo")
- Common settings:
npm installwrangler loginnpm run deploy- note the deployment URL from this command, its needed to setup Jekyll- Set your token as a secret:
- For GitHub:
npx wrangler secret put GITHUB_TOKEN- when prompted enter the GitHub token created earlier - For GitLab:
npx wrangler secret put GITLAB_TOKEN- when prompted enter the GitLab token created earlier
- For GitHub:
- create
.dev.varswith content based on your provider:- For GitHub:
GITHUB_TOKEN = "XXX", replaceXXXwith your GitHub token - For GitLab:
GITLAB_TOKEN = "XXX", replaceXXXwith your GitLab token
- For GitHub:
npm run start- This will give you a web server at
http://localhost:8787that you can make test requests to, either withcurlor by configuring your blog to post to the same URL. For Jekyll:
# comment out the real server, add your test server
#no_comment_url: https://xxxxx.workers.dev
no_comment_url: http://localhost:8787Add a comments section to _layouts/post.html:
- Adds a comment form
- Displays saved comments
- On successfully adding a comment, user is redirected
Configs needed:
- form
action: This is the URL the Cloudflare Worker was deployed to options[redirect]URL to redirect to after successfully adding a comment. Must be fully-qualified URL- Configure directly in HTML or add to
_config.yml
<h2>Post comment</h2>
<form method="POST" action="{{ site.no_comment_url }}">
<em><a href="https://www.markdownguide.org/">Markdown</a> is allowed, HTML is not. All comments are moderated.</em>
<br />
<input name="options[redirect]" type="hidden" value="{{ site.no_comment_redirect }}">
<input name="options[slug]" type="hidden" value="{{ page.slug }}">
<!-- e.g. "2016-01-02-this-is-a-post" -->
<label style="width: 20px; display: inline-block">Name <input name="fields[name]" type="text"></label>
<br/>
<label style="width: 20px; display: inline-block">Email<input name="fields[email]" type="email"></label>
<br/>
<label style="width: 20px; display: inline-block">Message<textarea rows="40" cols="80" name="fields[message]"></textarea></label>
<br/>
<button type="submit">Post</button>
</form>
{% if site.data.comments[page.slug] %}
<h2>Comments</h2>
<div>
{% for comment_entry in site.data.comments[page.slug] %}
{% assign comment = comment_entry[1] %}
<div>
{{comment.date | date: "%Y-%m-%d"}} {{comment.name | strip_html}}
<br />
{{comment.message | strip_html | markdownify }}
</div>
<hr>
{% endfor %}
</div>
{% endif %}You can add additional parameters to the redirect URL, such as the original page URL to redirect back after submission:
<h2>Post comment</h2>
<form method="POST" action="{{ site.no_comment_url }}" id="comment-form" autocomplete="off">
<em><a href="https://www.markdownguide.org/">Markdown</a> is allowed, HTML is not. All comments are moderated.</em>
<br />
<input name="options[redirect]" type="hidden" value="{{ site.no_comment_redirect }}?from={{ page.url | url_encode }}">
<input name="options[slug]" type="hidden" value="{{ page.slug }}">
<input name="fields[name]" type="text" autocomplete="off" placeholder="Name">
<br/>
<input name="fields[email]" type="email" autocomplete="off" placeholder="Email">
<br/>
<textarea rows="40" cols="80" name="fields[message]" autocomplete="off" placeholder="Message"></textarea>
<br/>
<button type="submit">Post</button>
</form>With this setup, after submitting a comment, users will be redirected to the thanks page with a from parameter containing the original page URL. You can then use JavaScript on your thanks page to redirect users back to the original page after a delay:
---
layout: default
title: Thanks for your comment
permalink: /thanks/
---
<h1>Thanks for your comment!</h1>
<p>Your comment has been submitted and is awaiting moderation.</p>
<p>Redirecting you back...</p>
<script>
// Get the 'from' parameter from the URL
const urlParams = new URLSearchParams(window.location.search);
const fromPath = urlParams.get('from');
// Redirect after a short delay
setTimeout(function() {
if (fromPath) {
window.location.href = decodeURIComponent(fromPath);
} else {
window.location.href = '/'; // Fallback to homepage
}
}, 3000); // 3 second delay
</script>Just what I use:
- name
- comment
- Deployed to cloudflare worker and not working? Run locally and point your blog comment form at localhost
- Errors about wrong
Content-Typefrom this wrangler: upgrade NodeJS - Akismet integration not working: Make sure to spell
AKISMETproperly 🤦 - Jekyll local server not starting: use a new Ruby but not too new:
3.2.2working today - Error deploying:
cloudflare workers bundle You can mark the path "axios" as external to exclude it from the bundle, which will remove this error.(or similar) - make sure to install the dependencies:npm install
If you use client-side email encryption in your blog (for privacy), no-comment can decrypt emails temporarily for Akismet spam checking while keeping them encrypted in GitLab/GitHub.
- Add your RSA private key as a Cloudflare secret:
npx wrangler secret put RSA_PRIVATE_KEY
- Paste your private key in PEM format when prompted
- Emails are decrypted only in memory for spam checking
- The encrypted version is stored in the merge/pull request
- If no private key is configured, the system works normally with plain emails
- Compatible with both encrypted and plain email submissions
- GitLab support: Antenore Gatta (@antenore)
- Original concept: staticman
- Inspiration: comment-worker
Last but not least:
- The army of spammers for giving us fun and interesting work to do