This originates from #3636853: Provide a CAPTCHA integration point for (anonymous) flagging and unflagging

Problem/Motivation

The logic that picks the CAPTCHA point for a form lives inline in captcha_form_alter(): the point for the form ID, then the base form ID if that point is missing or disabled, then a point built on the fly when "enable globally" is set, plus the "skip CAPTCHA" permission check.

Other modules sometimes need this answer before a form is built, to decide whether to show it at all. Example: Flag (#3636853) sends users to a confirm form, or opens it in a modal, only when a CAPTCHA would be shown there, and keeps one-click links for everyone else. Today such modules have to copy the lookup and can drift from CAPTCHA's behaviour.

A related point: CaptchaPoint declares list_cache_tags = ['rendered'], so saving any point clears the entire render cache. Callers that cache their decision can't use a narrower tag.

Proposed resolution

  • Move the lookup into a service method on captcha.helper, for example:

    getCaptchaPointForForm(string $form_id, ?string $base_form_id = NULL, ?AccountInterface $account = NULL, ?RefinableCacheableDependencyInterface $cacheability = NULL): ?CaptchaPointInterface

    It would return the enabled point that applies, or NULL, and add the cacheability metadata it depends on: user.permissions, the point list tag and captcha.settings.
  • Use it from captcha_form_alter(), so there is one source of truth.
  • Optionally, decide whether the IP whitelist and the admin-route condition for "enable globally" belong in the method or stay in the form alter. They depend on the request, not only on the form.
  • Optionally, in a separate follow-up: use the default config:captcha_point_list cache tag instead of rendered.

Remaining tasks

  • Agree on the method signature.
  • Implement it and refactor captcha_form_alter() to use it.
  • Add kernel tests for the lookup order (form ID, base form ID, disabled points, enable globally, skip permission).

API changes

A new public method on the CAPTCHA helper service. No behaviour change.

Issue fork captcha-3636870

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

anybody created an issue. See original summary.

anybody’s picture

Issue summary: View changes
anybody’s picture

Status: Active » Needs review

MR drafted using AI (Claude Opus)

anybody’s picture

Doesn't look bad and also starts cleaning up the large .module file already by splitting this into a service. So I'd say this could be a win-win.

If other maintainers agree with that general approach, I'd proceed here and review it more in detail. Thanks!!