Skip to content

Commit fd9eb78

Browse files
committed
fix(fraud-protection): also enqueue reCAPTCHA when a protected gateway is available regardless of smart-button location
should_enqueue_for_current_location() only checked the merchant's Smart Button Location setting, but that setting solely controls the wallet button. ACDC, AXO, and the card button gateway are independent WC_Payment_Gateway entries that can be selectable at checkout (or the My Account "Add payment method" page) even when the wallet button is disabled for that location — and reCAPTCHA protects exactly those gateways via $payment_methods. Add has_protected_gateway_on_current_page(), checking WC's own available-gateways list against the protected set, and OR it into the enqueue decision so reCAPTCHA isn't skipped while ACDC/AXO/card-button remain reachable.
1 parent 87562ed commit fd9eb78

2 files changed

Lines changed: 49 additions & 3 deletions

File tree

modules/ppcp-fraud-protection/src/Recaptcha/Recaptcha.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,11 @@ private function current_smart_button_location(): ?string {
200200
private function should_enqueue_for_current_location(): bool {
201201
$location = $this->current_smart_button_location();
202202

203-
$should_enqueue = null !== $location
203+
$enabled_for_location = null !== $location
204204
&& $this->settings_status->is_smart_button_enabled_for_location( $location );
205205

206+
$should_enqueue = $enabled_for_location || $this->has_protected_gateway_on_current_page();
207+
206208
/**
207209
* Filters whether reCAPTCHA assets and markup should be enqueued or
208210
* rendered for the current request.
@@ -217,6 +219,26 @@ private function should_enqueue_for_current_location(): bool {
217219
);
218220
}
219221

222+
/**
223+
* True when a reCAPTCHA-protected gateway (ACDC card fields, AXO, card button,
224+
* standard PayPal) is available on a checkout / order-pay / add-payment-method
225+
* page — surfaces whose availability is independent of the smart-button location.
226+
*/
227+
private function has_protected_gateway_on_current_page(): bool {
228+
if ( ! is_checkout() && ! is_add_payment_method_page() ) {
229+
return false;
230+
}
231+
232+
$available = WC()->payment_gateways->get_available_payment_gateways();
233+
foreach ( $this->payment_methods as $id ) {
234+
if ( isset( $available[ $id ] ) ) {
235+
return true;
236+
}
237+
}
238+
239+
return false;
240+
}
241+
220242
public function intercept_paypal_ajax( array $request_data ): void {
221243
if ( ! $this->should_use_recaptcha() ) {
222244
return;

tests/PHPUnit/FraudProtection/Recaptcha/RecaptchaTest.php

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,18 @@ public function setUp(): void {
3030

3131
when( 'is_user_logged_in' )->justReturn( false );
3232
when( 'has_block' )->justReturn( false );
33+
when( 'is_add_payment_method_page' )->justReturn( false );
3334
}
3435

3536
/**
3637
* Builds a Recaptcha instance configured so should_use_recaptcha() is true
3738
* (valid v2/v3 keys, integration enabled), so tests only need to control
3839
* the location-gating logic under test.
40+
*
41+
* @param string[] $payment_methods The gateway IDs reCAPTCHA protects, mirroring the
42+
* `fraud-protection.recaptcha.payment-methods` service.
3943
*/
40-
private function make_testee( SettingsStatus $settings_status ): Recaptcha {
44+
private function make_testee( SettingsStatus $settings_status, array $payment_methods = array() ): Recaptcha {
4145
$integration = Mockery::mock( RecaptchaIntegration::class );
4246
$integration->enabled = 'yes';
4347
$integration->shouldReceive( 'get_option' )->andReturnUsing(
@@ -54,7 +58,7 @@ function ( string $key, $default = false ) {
5458

5559
return new Recaptcha(
5660
$integration,
57-
array(),
61+
$payment_methods,
5862
$asset_getter,
5963
'1.0.0',
6064
$logger,
@@ -63,6 +67,24 @@ function ( string $key, $default = false ) {
6367
);
6468
}
6569

70+
/**
71+
* Stubs WC()->payment_gateways->get_available_payment_gateways() to return the given
72+
* gateway IDs as available, for has_protected_gateway_on_current_page() to check against.
73+
*
74+
* @param string[] $available_gateway_ids
75+
*/
76+
private function stub_available_gateways( array $available_gateway_ids = array() ): void {
77+
$payment_gateways = Mockery::mock();
78+
$payment_gateways->shouldReceive( 'get_available_payment_gateways' )->andReturn(
79+
array_fill_keys( $available_gateway_ids, true )
80+
);
81+
82+
$woocommerce = Mockery::mock();
83+
$woocommerce->payment_gateways = $payment_gateways;
84+
85+
when( 'WC' )->justReturn( $woocommerce );
86+
}
87+
6688
public function test_enqueue_scripts_skips_on_unsupported_page(): void {
6789
when( 'is_product' )->justReturn( false );
6890
when( 'is_cart' )->justReturn( false );
@@ -125,6 +147,8 @@ public function test_enqueue_scripts_checks_block_express_location_on_block_chec
125147
when( 'is_checkout' )->justReturn( true );
126148
when( 'has_block' )->justReturn( true );
127149

150+
$this->stub_available_gateways();
151+
128152
$settings_status = Mockery::mock( SettingsStatus::class );
129153
$settings_status->shouldReceive( 'is_smart_button_enabled_for_location' )
130154
->with( 'checkout-block-express' )

0 commit comments

Comments
 (0)