Problem/Motivation

The captcha disappears when the automatic shipping calculation is triggered.

Steps to reproduce

  1. Add a captcha to the checkout flow by creating a new "Captcha point" for the "commerce_checkout_flow_multistep_default" form
  2. Create an order and go to the order information step
  3. I can see the captcha and it works properly
  4. Enter the shipping address to start the automatic calculation
  5. After the automatic calculation, the captcha disappears

Proposed resolution

The captcha disappears because the following code runs:

    if ($form_state->getTriggeringElement() && isset($form_state->getTriggeringElement()['#limit_validation_errors']) && is_array($form_state->getTriggeringElement()['#limit_validation_errors'])) {
      // This is a partial (ajax) submission with limited validation. Do not
      // change anything about the captcha element, assume that it will not
      // update the captcha element, do not generate anything, which keeps the
      // current token intact for the real submission.
      return $element;
    }

But in the case of automatic recalculation, it should not be run.
We need to improve the conditions to not run this code:

    $triggering_element = $form_state->getTriggeringElement();
    $recalculate = !empty($triggering_element['#recalculate']);
    if ($triggering_element && isset($triggering_element['#limit_validation_errors']) && is_array($triggering_element['#limit_validation_errors']) && !$recalculate) {
      // This is a partial (ajax) submission with limited validation. Do not
      // change anything about the captcha element, assume that it will not
      // update the captcha element, do not generate anything, which keeps the
      // current token intact for the real submission.
      return $element;
    }

Issue fork captcha-3439550

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

vmarchuk created an issue. See original summary.

vmarchuk’s picture

We probably need to add more conditions to check if commerce_shipping is enabled, but here is a patch that fixes the problem.

Rajan Kumar@2026 made their first commit to this issue’s fork.

rajan kumar@2026’s picture

Status: Active » Needs review

Hii @vmarchuk

I have successfully applied the above patch #2 and created a merge request. Please review it when you have a chance. Thanks!

joao sausen’s picture

We had a similar issue recently and fixed by repositioning the captcha:

/**
 * Implements hook_captcha_placement_map().
 */
function MODULE_captcha_placement_map() {
  return [
    'commerce_checkout_flow_multistep_default' => [
      'path' => ['actions'],
    ],
  ];
}
leo pitt’s picture

The patches here and solutions don't seem to resolve the issue when recaptcha_v3 is being used.

elaman’s picture

I've created an issue on Commerce Shipping module issue queue, that I will quote below: #3558272: AJAX causes Captcha to loose track of its session

I'm checking this with Math challenge type, but ultimately would be nice to have it working with reCAPTCHAs:

What should happen:
- I visit the Order information page.
- I enter ZIP code.
- I enter Captcha Math challenge response.
- I click submit.
- I see payment form.

What is happening:
- I visit the order information page.
- I enter ZIP code.
- I can't enter Captcha Math challenge response, because input disappeared.
- I click submit.
- I'm still on order information page, but with failed validation: Math question (11 + 1 =) field is required.

What is happening when I comment out #limit_validation_errors:
- I visit the order information page.
- I enter ZIP code.
- I immediately see failed validation "Math question (7 + 10 =) field is required."
- I enter Captcha Math challenge response.
- I click submit.
- I see payment form.

elaman’s picture

The #2 patch resolves the issue with challenge type Math. I'm wondering if it will work for reCAPTCHA v3. I've created issue there: #3558274: Any AJAX on the form, causing reCaptcha v3 to immediately fallback to reCaptcha v2 and will explore further.

anybody’s picture

@vmarchuk could you maybe explain the fix in #2 and add explanations to the code as comments? I don't think this is obvious enough.

What are your further thoughts on the solution?

japerry made their first commit to this issue’s fork.

japerry’s picture

The bug is valid and not specific to Commerce: any rebuild triggered by a `#limit_validation_errors` button empties the CAPTCHA. MR !95's `#recalculate` check is a Commerce-only workaround with side effects, so I replaced it with a generic fix and a functional test.

The new approach, for submissions with limited validation:

  • The challenge is built again in the CAPTCHA session that was posted, so the hidden session ID and token don't change.
  • No new session is created and no validation handler is attached, so the partial submission isn't validated and isn't counted.
  • If there is no session to reuse, the element is left alone, as before.
  • The new challenge's solution is only saved when the element is rendered. An AJAX response that doesn't include the CAPTCHA therefore leaves the question the user can see valid. A response that re-renders it shows the new question, which is what gets checked.

  • japerry committed 3876737e on 2.x
    fix: #3439550 Keep the CAPTCHA on forms rebuilt by limited validation...
japerry’s picture

Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.