1010use WC_Product ;
1111use WooCommerce \PayPalCommerce \Assets \AssetGetter ;
1212use WooCommerce \PayPalCommerce \FraudProtection \PersistentCounter ;
13+ use WooCommerce \PayPalCommerce \WcGateway \Helper \SettingsStatus ;
1314use WP_Error ;
1415use 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