Welcome back!
This entry is about one feature, and it's one I built out of necessity rather than ambition: spam protection for comments, in the form of Google reCAPTCHA v2.
The Reason: A Flood of Bots
This wasn't a theoretical "nice to have." I'd been getting a steady flood of bot comments on the site, and the moderation queue was filling up with junk faster than I could clear it. Open comment forms are a spam magnet, and mine had clearly been found.
So I added Google reCAPTCHA v2 — the classic "I'm not a robot" checkbox — to the public comment form. I wanted a real gate without bolting on something heavy.
How I Built It
A few principles shaped the whole thing:
Opt-in. reCAPTCHA needs two keys — a public site key (safe to put in the page, Google's widget needs it to render) and a server-only secret key (used to verify submissions). If either one is missing, reCAPTCHA is simply treated as off. That means a fresh install still posts comments without anyone having to configure anything first — the historical behavior is preserved until you opt in.
Fail-closed. When the secret is set and a comment comes in, the server verifies the token with Google before accepting it. If the token is missing, malformed, rejected, or Google's endpoint is having a bad day and the request errors out — the comment is rejected. A flaky upstream should never silently open a spam window.
The secret stays secret. In the admin settings, the site key is echoed back into the form (it's public anyway), but the secret key is write-only: it's never re-emitted, a blank field means "keep the current value," and clearing it is a separate, explicit "Disable & clear keys" action behind a confirm dialog. There's also a live Enabled/Disabled status indicator so you can see at a glance whether the gate is actually up.
On the verification side, I deliberately don't surface Google's internal error codes to the visitor — every failure shows the same generic "please try again" message, so a bot scripting the form can't learn anything from the responses.
The Small Details That Matter
A couple of ordering decisions that aren't obvious but make a real difference:
The reCAPTCHA check runs after the normal form validation passes. No point burning a verify round-trip to Google on a submission that was going to fail validation anyway.
When verification fails, the form re-renders with everything the visitor typed still filled in, plus the error — because nothing's more infuriating than a captcha wiping your comment.
The theme side is dead simple: themes get a recaptchaSiteKey value in their render context that's only non-null when reCAPTCHA is fully configured. The default theme renders the widget and loads Google's script only when that key is present. A theme that ignores the field just gets un-gated comments — no breakage, no surprises.
Did It Work?
This is exactly the kind of "plumbing" feature that's invisible when it works — lots of careful failure handling, opt-in defaults, very little that's flashy. But after wading through a spam-clogged moderation queue, getting the boring parts right here felt very worth it. The junk dropped off, and I get my comments section back.
Next up I want to dig into the theme system itself — how templates get linted and where I think it's still too rigid. More on that soon.
Thanks for reading — see you in the next entry!
[ COMMENTS · 0 ON FILE ]
No comments on file yet — be the first to transmit.
Open a return channel