-
Notifications
You must be signed in to change notification settings - Fork 81
Description
Plugin version
grav-plugin-form 8.2.1 (and likely all versions since CaptchaManager was introduced)
Description
When captcha validation fails (e.g. basic-captcha, turnstile), CaptchaManager::validateCaptcha() fires the onFormValidationError event with only a top-level message string, but does not include a per-field messages array.
As a result:
form.messages[field.name]is always empty for captcha fields in Twig templates- The field wrapper never receives the
has-errorsCSS class (which is driven byform.messages[field.name]) - The
inline_errors: trueform option has no visual effect on captcha fields — no error text appears under the field, and no red border is applied
All other field types validated via the standard Grav pipeline do populate form.messages correctly, so the problem is specific to the new CaptchaManager.
Steps to reproduce
- Add a
basic-captcha(orturnstile) field to a Grav form - Enable
inline_errors: trueon the form - Submit the form with an incorrect captcha answer
- Observe: the top-level error message appears, but the captcha input field does not get the
has-errorsclass and shows no inline error
Root cause
In classes/Captcha/CaptchaManager.php, the onFormValidationError event is fired without a messages array:
// Current (broken) code — lines ~96–100
Grav::instance()->fireEvent('onFormValidationError', new Event([
'form' => $form,
'message' => $errorMessage,
// 'messages' key is missing!
'provider' => $providerName
]));In form.php, onFormValidationError assigns $event['messages'] to $form->messages:
// form.php, onFormValidationError()
$form->status = 'error';
$form->message = $event['message'];
$form->messages = $event['messages']; // will be null because CaptchaManager didn't set itIn forms/default/field.html.twig, has-errors depends on form.messages[field.name]:
{% set errors = attribute(form.messages, field.name) %}
{%- if errors %}{% set form_field_outer_core = form_field_outer_core ~ ' has-errors' %}{% endif -%}Since form.messages is null, errors is always falsy for captcha fields → no has-errors class.
For comparison, standard field validation in Form.php (line 950–951) correctly populates messages:
$this->messages = array_merge($this->messages, $e->getMessages());
$event = new Event(['form' => $this, 'message' => $this->message, 'messages' => $this->messages]);Expected behaviour
CaptchaManager should pass a messages array in the event, mapping the captcha field name to the error message — exactly the same convention used by regular field validation:
Grav::instance()->fireEvent('onFormValidationError', new Event([
'form' => $form,
'message' => $errorMessage,
'messages' => [$captchaField['name'] => [$errorMessage]], // <-- fix
'provider' => $providerName
]));This should be applied to both the !$result['success'] branch and the catch (\Exception $e) branch in validateCaptcha().
Workaround
Until this is fixed, the has-errors class can be forced in a theme-level Twig override of forms/default/field.html.twig:
{% set errors = attribute(form.messages, field.name) %}
{% if not errors and field.type == 'basic-captcha' and form.status == 'error' %}
{% set errors = [form.message] %}
{% endif %}This is a hack and should not be necessary once CaptchaManager is corrected.