A few weeks ago, a user named Roger filed a bug report. Not the kind that makes you cringe - the kind that makes you think. He'd placed two forms on the same page, both protected by Captcha - HashCash, and neither submit button would enable until both forms had their required fields filled in. Worse, the button decoration logic was cross-wiring between forms. Fill out the second form completely? HashCash was still waiting on the first one.
He was right. It was broken. And fixing it properly led to something better than just a bug fix.
Roger's Two-Form Page Bug Report
Roger's page had a Joomla Contact Form component and a newsletter subscription module sitting side by side. Both were running HashCash. The expected behavior: each form manages its own state, its own hash calculation, its own submit button - independently. The actual behavior: they were tangled. The plugin was treating the page as a single form context, not two separate ones.
To reproduce it reliably, I needed a real third-party newsletter form to test against. That's where Christopher Mavros and his Newsletter Subscriber module came in.
Christopher's module is exactly what it sounds like - a clean, lightweight Joomla newsletter subscription module, free, available on the JED. When I reached out to explain the situation and ask if I could use it as a test case, he was immediately generous about it. That kind of open collaboration is what makes the Joomla ecosystem worth building for. The module gave me a realistic two-form environment to work in, and it's what drove the solution from "technically fixed" to "actually works well in the wild."
What Was Broken and Why
The root cause was straightforward once I could see it clearly: the button decoration logic - the code responsible for disabling the submit button while the hash calculates and re-enabling it when done - wasn't scoped per form instance. It was written assuming one HashCash instance per page. When a second instance loaded, both were reaching for the same DOM context, stepping on each other's state.
The fix required scoping each instance to its own form, so each one tracks its own calculation state, manages its own button, and completes entirely independently of anything else on the page.
That's version 5.6.0 - and it came with a bonus.
The Bonus: The Generic Decorator
While working through the fix with Christopher's module as my test bed, something became obvious. Roger had noted a secondary quirk: the Newsletter Subscriber form's submit button wasn't being decorated - no spinner, no "Loading..." state - because HashCash didn't have a registered decorator for that form context. The form worked, the hash calculated, the spam was blocked - but the UX was rougher than it should be.
Previously, the solution would have been to write a custom decorator - a small JavaScript file, correctly named and placed, telling HashCash how to find and manage the submit button for that specific form. That's documented, it works, and it's not hard for a developer. But it is friction, and it means every third-party form is a potential "does HashCash know about this one?" question for site builders.
So I built a generic decorator into 5.6.0.
It activates automatically for any form HashCash doesn't have a specific decorator for, using reasonable assumptions about form structure that hold true for the vast majority of Joomla-compatible forms in the wild - including Newsletter Subscriber. Drop HashCash onto a page with a third-party form today and it will almost certainly just work. Full decoration, correct button behavior, proper UX - out of the box, no custom code required.
Christopher's module was the proving ground. It works beautifully.
If You Have an Existing Custom Decorator
Good news: your custom decorator still works. You don't need to do anything for your forms to remain protected and functional.
The one reason to update is to get the full multi-form benefits. If your page only ever has one HashCash-protected form, there's no urgency. If you have - or plan to have - multiple forms on the same page, a small update to your decorator will bring it in line with the new per-form scoping.
I've made that update as easy as I could: the original decorator code is left commented inside the new scripts, so you can see exactly what changed at a glance. The diff is minimal. Check the updated com_contact.contact.js in /media/plg_captcha_hashcash/js/ as your reference - the old code is right there alongside the new.
When You'd Still Write a Custom Decorator
The generic decorator handles typical form structures well. There are edge cases where a custom decorator remains the right call:
- Non-standard submit elements - if the button isn't a
<button>or<input type="submit">, or is positioned outside the form element in the DOM - Multi-step or conditional forms where the loading state needs to interact with your own step logic
- Forms with their own loading UI that would conflict with the generic decorator's spinner
- Strict design system requirements where you need precise control over the loading treatment
For everything else, 5.6.0 has you covered.
Bug Report: Closed
A genuine thank-you to Roger for the detailed bug report - the kind that includes reproduction steps, follow-up testing, and patience while the fix baked. And to Christopher Mavros at mavxr.com for his generosity in letting Newsletter Subscriber serve as the real-world test case that shaped this release. If you're looking for a clean, no-fuss Joomla newsletter subscription module, his work is worth your time.
Captcha - HashCash is free, self-hosted, and listed on the Joomla Extension Directory with 5-star reviews. No paid tier, no third-party dependencies, no tracking. If it's useful to you, a review on the JED is all I ask.