Skip to content

Commit a6081df

Browse files
authored
Merge pull request #4548 from woocommerce/dev/PCP-6703-scope-re-captcha-assets-and-markup-to-active-pay-pal-payment-locations
Scope reCAPTCHA assets and markup to active PayPal payment locations (6703)
2 parents a0356d3 + 9be4d86 commit a6081df

3 files changed

Lines changed: 416 additions & 3 deletions

File tree

modules/ppcp-fraud-protection/services.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
$container->get( 'fraud-protection.asset_getter' ),
3030
$container->get( 'ppcp.asset-version' ),
3131
$container->get( 'woocommerce.logger.woocommerce' ),
32-
$container->get( 'fraud-protection.recaptcha.rejection-counter' )
32+
$container->get( 'fraud-protection.recaptcha.rejection-counter' ),
33+
$container->get( 'wcgateway.settings.status' )
3334
);
3435
},
3536
'fraud-protection.recaptcha.integration' => static function (): RecaptchaIntegration {

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

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use WC_Product;
1111
use WooCommerce\PayPalCommerce\Assets\AssetGetter;
1212
use WooCommerce\PayPalCommerce\FraudProtection\PersistentCounter;
13+
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
1314
use WP_Error;
1415
use WP_Post;
1516

@@ -40,6 +41,8 @@ class Recaptcha {
4041

4142
private PersistentCounter $rejection_counter;
4243

44+
private SettingsStatus $settings_status;
45+
4346
private float $last_v3_score = 0;
4447

4548
/**
@@ -49,14 +52,16 @@ class Recaptcha {
4952
* @param string $asset_version
5053
* @param LoggerInterface $logger
5154
* @param PersistentCounter $rejection_counter
55+
* @param SettingsStatus $settings_status
5256
*/
5357
public function __construct(
5458
RecaptchaIntegration $integration,
5559
array $payment_methods,
5660
AssetGetter $asset_getter,
5761
string $asset_version,
5862
LoggerInterface $logger,
59-
PersistentCounter $rejection_counter
63+
PersistentCounter $rejection_counter,
64+
SettingsStatus $settings_status
6065
) {
6166

6267
$this->integration = $integration;
@@ -65,6 +70,7 @@ public function __construct(
6570
$this->asset_version = $asset_version;
6671
$this->logger = $logger;
6772
$this->rejection_counter = $rejection_counter;
73+
$this->settings_status = $settings_status;
6874
}
6975

7076
protected function should_use_recaptcha(): bool {
@@ -101,7 +107,7 @@ public function render_settings_page_log(): string {
101107
}
102108

103109
public function enqueue_scripts(): void {
104-
if ( ! is_checkout() && ! is_cart() && ! is_product() ) {
110+
if ( ! $this->should_enqueue_for_current_location() ) {
105111
return;
106112
}
107113

@@ -154,9 +160,85 @@ public function render_v2_container(): string {
154160
return '';
155161
}
156162

163+
if ( ! $this->should_enqueue_for_current_location() ) {
164+
return '';
165+
}
166+
157167
return '<div id="' . esc_attr( self::V2_CONTAINER_ID ) . '" style="margin:20px 0;"></div>';
158168
}
159169

170+
/**
171+
* Returns the current page's smart button location key, or null when the
172+
* current request is not one of the locations reCAPTCHA supports.
173+
*
174+
* Mirrors the location keys SmartButton uses via SettingsStatus. Checkout
175+
* is split into classic vs. block/express since a merchant may enable
176+
* PayPal for one but not the other.
177+
*/
178+
private function current_smart_button_location(): ?string {
179+
if ( is_product() ) {
180+
return 'product';
181+
}
182+
183+
if ( is_cart() ) {
184+
return 'cart';
185+
}
186+
187+
if ( is_checkout() ) {
188+
return has_block( 'woocommerce/checkout' ) ? 'checkout-block-express' : 'checkout';
189+
}
190+
191+
return null;
192+
}
193+
194+
/**
195+
* Whether reCAPTCHA assets/markup are allowed to load for the current
196+
* page, based on whether the merchant has PayPal enabled for this smart
197+
* button location — the same gating SmartButton uses, so reCAPTCHA never
198+
* loads where no PayPal button/gateway can actually be used.
199+
*/
200+
private function should_enqueue_for_current_location(): bool {
201+
$location = $this->current_smart_button_location();
202+
203+
$enabled_for_location = null !== $location
204+
&& $this->settings_status->is_smart_button_enabled_for_location( $location );
205+
206+
$should_enqueue = $enabled_for_location || $this->has_protected_gateway_on_current_page();
207+
208+
/**
209+
* Filters whether reCAPTCHA assets and markup should be enqueued or
210+
* rendered for the current request.
211+
*
212+
* @param bool $should_enqueue Whether reCAPTCHA should be enqueued.
213+
* @param string|null $location The detected smart button location, or null when none applies.
214+
*/
215+
return (bool) apply_filters(
216+
'woocommerce_paypal_payments_recaptcha_should_enqueue',
217+
$should_enqueue,
218+
$location
219+
);
220+
}
221+
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+
160242
public function intercept_paypal_ajax( array $request_data ): void {
161243
if ( ! $this->should_use_recaptcha() ) {
162244
return;

0 commit comments

Comments
 (0)