PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 3.16.5
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v3.16.5
4.0.3 4.0.2 4.0.1 4.0.0 3.16.6 3.16.5 3.16.4 3.16.3 3.16.2 3.16.1 3.16.0 3.15.9 3.9.9 3.9.5 3.9.6 3.9.7 3.9.8 1.1.7 1.1.8 1.1.9 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 341 releases
profile-builder / front-end / default-fields / recaptcha / recaptcha.php

recaptcha.php in User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor 3.16.5, at front-end/default-fields/recaptcha/recaptcha.php

1,042 lines 50.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
4 /**
5 * Encodes the given data into a query string format
6 * @param $data - array of string elements to be encoded
7 * @return string - encoded request
8 */
9 function _wppb_encodeQS($data)
10 {
11 $req = "";
12 foreach ($data as $key => $value) {
13 $req .= $key . '=' . urlencode(stripslashes($value)) . '&';
14 }
15 // Cut the last '&'
16 $req=substr($req, 0, strlen($req)-1);
17 return $req;
18 }
19
20
21
22 /**
23 * Submits an HTTP GET to a reCAPTCHA server
24 * @param string $path
25 * @param array $data
26 */
27 function _wppb_submitHTTPGet($path, $data)
28 {
29 $req = _wppb_encodeQS($data);
30 $response = wp_remote_get($path . $req);
31
32 if ( ! is_wp_error( $response ))
33 return $response["body"];
34 }
35
36 /**
37 * Gets the challenge HTML (javascript and non-javascript version).
38 * This is called from the browser, and the resulting reCAPTCHA HTML widget
39 * is embedded within the HTML form it was called from.
40 * @param string $pubkey A public key for reCAPTCHA
41 * @param string $error The error given by reCAPTCHA (optional, default is null)
42 * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
43
44 * @return string - The HTML to be embedded in the user's form.
45 */
46 function wppb_recaptcha_get_html ( $pubkey, $form_name='' ){
47 global $wppb_recaptcha_forms; // is the counter for the number of forms that have recaptcha so we always have unique ids on the element
48 if( is_null( $wppb_recaptcha_forms ) )
49 $wppb_recaptcha_forms = 0;
50 $wppb_recaptcha_forms++;
51
52 $field = wppb_get_recaptcha_field();
53
54 if ( empty($pubkey) )
55 echo '<span class="error">'. esc_html__("To use reCAPTCHA you must get an API key from", "profile-builder"). " <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a></span><br/><br/>";
56
57 // extra class needed for Invisible reCAPTCHA html
58 $invisible_class = '';
59 $v3_field_html = '';
60 if ( isset($field['recaptcha-type']) && ($field['recaptcha-type'] == 'invisible') ) {
61 $invisible_class = 'wppb-invisible-recaptcha';
62 } elseif ( isset($field['recaptcha-type']) && ($field['recaptcha-type'] == 'v3') ) {
63 $invisible_class = 'wppb-v3-recaptcha';
64 $v3_field_html = '<input type="hidden" name="g-recaptcha-response" class="g-recaptcha-response wppb-v3-recaptcha">';
65 }
66
67 $output = '<div id="wppb-recaptcha-element-'.$form_name.$wppb_recaptcha_forms.'" class="wppb-recaptcha-element '.$invisible_class.'">'.$v3_field_html.'</div>';
68
69 if ( isset($field['recaptcha-type']) && ($field['recaptcha-type'] == 'v3') ) {
70 $output .= '<input type="hidden" name="wppb-recaptcha-v3" value="1">';
71
72 if( $form_name == 'pb_login' ) {
73 add_filter( 'wppb_login_submit_button_extra_attributes', 'wppb_recaptcha_login_submit_button_extra_attributes' );
74 }
75
76 }
77
78 // reCAPTCHA html for all forms and we make sure we have a unique id for v2
79 return $output;
80 }
81
82 /**
83 * Add disabled attribute to login form submit button when reCaptcha v3 is used
84 * This is used to prevent form submission before the reCaptcha script is loaded and a token is received
85 *
86 * @param string $attributes
87 * @return string
88 */
89 function wppb_recaptcha_login_submit_button_extra_attributes( $attributes ) {
90 return $attributes . ' disabled="disabled"';
91 }
92
93 /**
94 * Add reCAPTCHA scripts to both front-end PB forms (with support for multiple forms) as well as Default WP forms
95 */
96 function wppb_recaptcha_script_footer(){
97 $field = wppb_get_recaptcha_field();
98 /* if we do not have a recaptcha field do nothing */
99 if( empty( $field ) )
100 return;
101
102 //do not add script if there is no shortcode
103 global $wppb_shortcode_on_front;
104 if( current_filter() == 'wp_footer' && ( !isset( $wppb_shortcode_on_front ) || $wppb_shortcode_on_front === false ) )
105 return;
106
107 //do not add script if the html for the field has not been added
108 global $wppb_recaptcha_present;
109 if( !isset( $wppb_recaptcha_present ) || $wppb_recaptcha_present === false )
110 return;
111
112 //we don't have jquery on the backend
113 if( current_filter() != 'wp_footer' ) {
114 wp_print_scripts('jquery');
115 }else if(!wp_script_is('jquery')){
116 wp_print_scripts('jquery');
117 }
118
119 //get site key
120 $pubkey = '';
121 if( isset( $field['public-key'] ) ) {
122 $pubkey = sanitize_text_field( $field['public-key'] );
123 }
124
125 // Check if we have a reCAPTCHA type
126 if ( !isset($field['recaptcha-type']) )
127 $field['recaptcha-type'] = 'v2' ;
128
129 /*for invisible recaptcha we have extra parameters and the selector is different. v2 is initialized on the id of the div
130 that must be unique and invisible is on the submit button of the forms that have the div */
131 if ( $field['recaptcha-type'] === 'invisible' ) {
132 $callback_conditions = 'jQuery("input[type=\'submit\']", jQuery( ".wppb-recaptcha-element" ).closest("form") )';
133 $invisible_parameters = '"callback" : wppbInvisibleRecaptchaOnSubmit,"size": "invisible"';
134 } elseif ( $field['recaptcha-type'] === 'v3' ) {
135 $callback_conditions = 'jQuery( jQuery( ".wppb-recaptcha-element" ).closest("form") )';
136 $invisible_parameters = '';
137 } else {
138 $callback_conditions = 'jQuery(".wppb-recaptcha-element")';
139 $invisible_parameters = '';
140 }
141
142 if( $field['recaptcha-type'] === 'v3' ) {
143
144 //the section below is properly escaped or the variables contain static strings
145 // phpcs:disable
146 echo '
147 <script>
148 window.wppbRecaptchaCallbackExecuted = false;
149 window.wppbRecaptchaV3 = true;
150 var wppbRecaptchaCallback = function() {
151 if( !window.wppbRecaptchaCallbackExecuted ){
152 '.$callback_conditions.'.each(function() {
153 let wppbElement = jQuery(this),
154 form = wppbElement.is("form") ? wppbElement : wppbElement.find("form"),
155 currentForm = form[0];
156
157 // Ensure we have a PB Form
158 if (form.length === 0) {
159 return;
160 }
161
162 // Listen for PB-Form submission
163 jQuery(currentForm).on("submit.wppbRecaptchaV3", wppbInitializeRecaptchaV3);
164 });
165 window.wppbRecaptchaCallbackExecuted = true;//we use this to make sure we only run the callback once
166
167 // Enable login form submit button
168 if( jQuery("#wppb-loginform input[type=submit]").length > 0 ) {
169 jQuery("#wppb-loginform input[type=submit]").attr("disabled", false);
170 }
171 }
172 };
173
174 function wppbInitializeRecaptchaV3( event = null, current_form = null ){
175
176 if( event ){
177 event.preventDefault();
178 event.stopPropagation();
179 }
180
181 let currentForm = this
182
183 if( current_form != null && current_form && current_form[0] ){
184 currentForm = current_form[0]
185 }
186
187 return new Promise((resolve) => {
188
189 grecaptcha.ready(function() {
190 grecaptcha.execute("' . $pubkey . '", {action: "submit"}).then(function(token) {
191
192 let recaptchaResponse = jQuery(currentForm).find(".wppb-v3-recaptcha.g-recaptcha-response");
193 jQuery(recaptchaResponse).val(token); // Set the recaptcha response
194
195 if( token === false ){
196 return wppbRecaptchaInitializationError();
197 }
198
199 var submitForm = true
200
201 /* dont submit form if PMS gateway is Stripe */
202 if( jQuery(".pms_pay_gate[type=radio]").length > 0 ){
203 jQuery(".pms_pay_gate").each( function(){
204 if( jQuery(this).is(":checked") && !jQuery(this).is(":disabled") && ( jQuery(this).val() == "stripe_connect" || jQuery(this).val() == "stripe_intents" || jQuery(this).val() == "stripe" || jQuery(this).val() == "paypal_connect" ) )
205 submitForm = false
206 })
207 } else if( jQuery(".pms_pay_gate[type=hidden]").length > 0 ) {
208
209 if( !jQuery(".pms_pay_gate[type=hidden]").is(":disabled") && ( jQuery(".pms_pay_gate[type=hidden]").val() == "stripe_connect" || jQuery(".pms_pay_gate[type=hidden]").val() == "stripe_intents" || jQuery(".pms_pay_gate[type=hidden]").val() == "stripe" || jQuery(".pms_pay_gate[type=hidden]").val() == "paypal_connect" ) )
210 submitForm = false
211 } else if( currentForm.classList.contains("wppb-ajax-form") ) {
212 submitForm = false;
213 } else if( currentForm.classList.contains("wppb-2fa-form") ) {
214 submitForm = false;
215 }
216
217 if( currentForm.classList.contains("wppb-2fa-authentication-requested" ) ){
218 submitForm = true;
219 }
220
221 if( submitForm ){
222 jQuery(currentForm).off("submit.wppbRecaptchaV3");
223 currentForm.submit();
224 } else {
225 jQuery(document).trigger( "wppb_v3_recaptcha_success", jQuery( "input[type=\'submit\']", jQuery( currentForm ) ) )
226 }
227
228 resolve( token );
229
230 });
231 });
232
233 });
234 }
235
236 /* the callback function for when the captcha does not load propperly, maybe network problem or wrong keys */
237 function wppbRecaptchaInitializationError(){
238 window.wppbRecaptchaInitError = true;
239 ';
240
241 } else {
242 //the section below is properly escaped or the variables contain static strings
243 // phpcs:disable
244 echo '
245 <script>
246 window.wppbRecaptchaCallbackExecuted = false;
247 window.wppbRecaptcha = true;
248 var wppbRecaptchaCallback = function() {
249 if( !window.wppbRecaptchaCallbackExecuted ){//see if we executed this before
250 ' . $callback_conditions . '.each(function(){
251 var $recaptchaElement = jQuery(this);
252 var existingRecaptchaId = $recaptchaElement.data("wppb-recaptcha-id");
253
254 if ( typeof existingRecaptchaId !== "undefined" ) {
255 grecaptcha.reset( existingRecaptchaId );
256 return;
257 }
258
259 var recID = grecaptcha.render(
260 $recaptchaElement.attr("id"),
261 {
262 "sitekey" : "' . $pubkey . '",
263 "error-callback": wppbRecaptchaInitializationError,
264 ' . $invisible_parameters . '
265 }
266 )
267
268 $recaptchaElement.data("wppb-recaptcha-id", recID);
269 });
270 window.wppbRecaptchaCallbackExecuted = true;//we use this to make sure we only run the callback once
271 }
272 };
273
274 /* the callback function for when the captcha does not load propperly, maybe network problem or wrong keys */
275 function wppbRecaptchaInitializationError(){
276 window.wppbRecaptchaInitError = true;
277 ';
278 }
279
280 if ( $field['recaptcha-type'] === 'invisible' ) {
281 echo '
282 /* make sure that if the invisible recaptcha did not load properly ( network error or wrong keys ) we can still submit the form */
283 jQuery("input[type=\'submit\']", jQuery( ".wppb-recaptcha-element" ).closest("form") ).on("click", function(e){
284 jQuery(this).closest("form").submit();
285 });
286 ';
287 }
288
289 echo '
290 //add a captcha field so we do not just let the form submit if we do not have a captcha response
291 jQuery( ".wppb-recaptcha-element" ).after(\'' . wp_nonce_field( 'wppb_recaptcha_init_error', 'wppb_recaptcha_load_error', false, false ) . '\');
292 }
293
294 /* compatibility with other plugins that may include recaptcha with an onload callback. if their script loads first then our callback will not execute so call it explicitly */
295 jQuery( window ).on( "load", function() {
296 wppbRecaptchaCallback();
297 });
298 </script>';
299 // phpcs:enable
300 if ( $field['recaptcha-type'] === 'invisible' ) {
301 echo '<script>
302 /* success callback for invisible recaptcha. it submits the form that contains the right token response */
303 function wppbInvisibleRecaptchaOnSubmit(token){
304
305 var elem = jQuery(".g-recaptcha-response").filter(function(){
306 return jQuery(this).val() === token;
307 });
308
309 var form = elem.closest("form");
310
311 var submitForm = true
312
313 /* dont submit form if PMS gateway is Stripe */
314 if( jQuery(".pms_pay_gate[type=radio]").length > 0 ){
315 jQuery(".pms_pay_gate").each( function(){
316 if( jQuery(this).is(":checked") && !jQuery(this).is(":disabled") && ( jQuery(this).val() == "stripe_connect" || jQuery(this).val() == "stripe_intents" || jQuery(this).val() == "stripe" || jQuery(this).val() == "paypal_connect" ) )
317 submitForm = false
318 })
319 } else if( jQuery(".pms_pay_gate[type=hidden]").length > 0 ) {
320
321 if( !jQuery(".pms_pay_gate[type=hidden]").is(":disabled") && ( jQuery(".pms_pay_gate[type=hidden]").val() == "stripe_connect" || jQuery(".pms_pay_gate[type=hidden]").val() == "stripe_intents" || jQuery(".pms_pay_gate[type=hidden]").val() == "stripe" || jQuery(".pms_pay_gate[type=hidden]").val() == "paypal_connect" ) )
322 submitForm = false
323
324 } else if( form.hasClass("wppb-ajax-form") ) {
325 submitForm = false;
326 } else if( form.hasClass("wppb-2fa-form") ) {
327 submitForm = false;
328 }
329
330 if( form.hasClass("wppb-2fa-authentication-requested" ) ){
331 submitForm = true;
332 }
333
334 if( submitForm ){
335 form.submit();
336 } else {
337 jQuery(document).trigger( "wppb_invisible_recaptcha_success", jQuery( ".form-submit input[type=\'submit\']", elem.closest("form") ) )
338 return true;
339 }
340 }
341 </script>';
342 }
343
344 $lang = '&hl=en';
345 $locale = get_locale();
346 if(!empty($locale)) {
347 $locale_parts = explode('_',$locale);
348 $lang = '&hl='.urlencode($locale_parts[0]);
349 }
350
351 $source = apply_filters( 'wppb_recaptcha_custom_field_source', 'www.google.com' );
352
353 if( $field['recaptcha-type'] === 'v3' ) {
354 echo '<script src="https://'. esc_attr( $source ) .'/recaptcha/api.js?render='.esc_attr( $pubkey ).'" async defer></script>';
355 } else {
356 echo '<script src="https://'. esc_attr( $source ) .'/recaptcha/api.js?onload=wppbRecaptchaCallback&render=explicit'.esc_attr( $lang ).'" async defer></script>';
357 }
358
359 }
360 add_action('wp_footer', 'wppb_recaptcha_script_footer', 9999);
361 add_action('login_footer', 'wppb_recaptcha_script_footer');
362 add_action('register_form', 'wppb_recaptcha_script_footer');
363 add_action('lost_password', 'wppb_recaptcha_script_footer');
364
365
366 /**
367 * Print style
368 *
369 */
370 function wppb_recaptcha_print_style() {
371 echo '<style type="text/css">
372 /* Hide reCAPTCHA V3 badge */
373 .grecaptcha-badge {
374
375 visibility: hidden !important;
376
377 }
378 </style>';
379 }
380
381 add_action( 'wp_footer', 'wppb_recaptcha_print_style' );
382 add_action( 'login_footer', 'wppb_recaptcha_print_style' );
383
384
385 /**
386 * A wppb_ReCaptchaResponse is returned from wppb_recaptcha_check_answer()
387 */
388 class wppb_ReCaptchaResponse {
389 var $is_valid;
390 }
391
392
393 /**
394 * Calls an HTTP POST function to verify if the user's answer was correct
395 * @param string $privkey
396 * @param string $remoteip
397 * @param string $response
398 * @return wppb_ReCaptchaResponse
399 */
400 function wppb_recaptcha_check_answer ( $privkey, $remoteip, $response, $score_threshold = 0.5 ) {
401
402 if ( $remoteip == null || $remoteip == '' )
403 echo '<span class="error">'. esc_html__("For security reasons, you must pass the remote ip to reCAPTCHA!", "profile-builder") .'</span><br/><br/>';
404
405 // Discard empty solution submissions. Fail closed: a missing token is never valid.
406 // The previous wppb_recaptcha_load_error nonce "escape hatch" was removed - that nonce is printed in the
407 // page HTML, so a bot could replay it to skip verification. A genuinely unconfigured reCAPTCHA (empty keys)
408 // is handled upstream in wppb_validate_captcha_response(), so this does not lock users out on misconfig.
409 if ($response == null || strlen($response) == 0) {
410 $recaptchaResponse = new wppb_ReCaptchaResponse();
411 $recaptchaResponse->is_valid = false;
412
413 return $recaptchaResponse;
414 }
415
416 $source = apply_filters( 'wppb_recaptcha_custom_field_source', 'www.google.com' );
417
418 $getResponse = _wppb_submitHTTPGet(
419 "https://".$source."/recaptcha/api/siteverify?",
420 array (
421 'secret' => $privkey,
422 'remoteip' => $remoteip,
423 'response' => $response
424 )
425 );
426
427 $answers = json_decode($getResponse, true);
428 $recaptchaResponse = new wppb_ReCaptchaResponse();
429
430 if (trim($answers ['success']) == true) {
431 if ( array_key_exists( 'score', $answers ) ) {
432 $recaptchaResponse->is_valid = ($answers['score'] >= $score_threshold);
433 } else {
434 $recaptchaResponse->is_valid = true;
435 }
436 } else {
437 $recaptchaResponse->is_valid = false;
438 }
439
440 return $recaptchaResponse;
441
442 }
443
444 /* the function to display error message on the registration page */
445 function wppb_validate_captcha_response( $publickey, $privatekey, $score_threshold = 0.5 ){
446 /* If the reCAPTCHA keys are not configured the widget cannot work for anyone, so do not enforce -
447 otherwise an incomplete setup would lock every visitor out of the form. These keys are admin-side
448 configuration, not attacker controlled, so this cannot be used to bypass a properly configured reCAPTCHA. */
449 if ( empty( $publickey ) || empty( $privatekey ) ) {
450 return true;
451 }
452
453 if (isset($_POST['g-recaptcha-response'])){
454 $recaptcha_response_field = sanitize_textarea_field( $_POST['g-recaptcha-response'] );
455 } else {
456 $recaptcha_response_field = '';
457 }
458
459 $already_validated = false;
460 $saved = get_option( 'wppb_recaptcha_validations', array() );
461
462 if( isset( $saved[ $recaptcha_response_field ] ) && $saved[ $recaptcha_response_field ] == true ){
463 $already_validated = true;
464
465 if( !wp_doing_ajax() ){
466 unset( $saved[ $recaptcha_response_field ] );
467
468 update_option( 'wppb_recaptcha_validations', $saved, false );
469 }
470 }
471
472 if( !$already_validated ){
473
474 if( isset( $_SERVER["REMOTE_ADDR"] ) ){
475 $resp = wppb_recaptcha_check_answer($privatekey, sanitize_text_field( $_SERVER["REMOTE_ADDR"] ), $recaptcha_response_field, $score_threshold );
476
477 if( isset( $resp ) ){
478 $already_validated = ( ( !$resp->is_valid ) ? false : true );
479 }
480 }
481
482 }
483
484 // Save valid results when they are being triggered from an ajax request
485 if( wp_doing_ajax() && isset( $_POST['action'] ) && $_POST['action'] == 'pms_validate_checkout' ){
486
487 $saved = get_option( 'wppb_recaptcha_validations', array() );
488
489 if( $already_validated === true )
490 $saved[ $recaptcha_response_field ] = true;
491
492 update_option( 'wppb_recaptcha_validations', $saved, false );
493
494 }
495
496 return $already_validated;
497
498 }
499
500 /* the function to add reCAPTCHA to the registration form of PB */
501 function wppb_recaptcha_handler ( $output, $form_location, $field, $user_id, $field_check_errors, $request_data ){
502 if ( $field['field'] == 'reCAPTCHA' ){
503 $item_title = apply_filters( 'wppb_'.$form_location.'_recaptcha_custom_field_'.$field['id'].'_item_title', wppb_icl_t( 'plugin profile-builder-pro', 'custom_field_'.$field['id'].'_title_translation', $field['field-title'], true ) );
504 $item_description = wppb_icl_t( 'plugin profile-builder-pro', 'custom_field_'.$field['id'].'_description_translation', $field['description'], true );
505
506 wppb_recaptcha_set_default_values();
507
508 if ( ($form_location == 'register') && ( isset($field['captcha-pb-forms']) ) && ( strpos($field['captcha-pb-forms'],'pb_register') !== false || ( $field['recaptcha-type'] == 'v3' && wppb_maybe_enable_recaptcha_v3_on_form( $field ) ) ) ) {
509 $error_mark = ( ( $field['required'] == 'Yes' ) ? '<span class="wppb-required" title="'.wppb_required_field_error($field["field-title"]).'">*</span>' : '' );
510
511 global $wppb_recaptcha_present;
512 $wppb_recaptcha_present = true;
513
514 if ( array_key_exists( $field['id'], $field_check_errors ) )
515 $error_mark = '<img src="'.WPPB_PLUGIN_URL.'assets/images/pencil_delete.png" title="'.wppb_required_field_error($field["field-title"]).'"/>';
516
517 $publickey = trim( $field['public-key'] );
518 $privatekey = trim( $field['private-key'] );
519
520 if ( empty( $publickey ) || empty( $privatekey ) )
521 return '<span class="custom_field_recaptcha_error_message" id="'.$field['meta-name'].'_error_message">'.apply_filters( 'wppb_'.$form_location.'_recaptcha_custom_field_'.$field['id'].'_error_message', __("To use reCAPTCHA you must get an API public key from:", "profile-builder"). '<a href="https://www.google.com/recaptcha/admin/create">https://www.google.com/recaptcha/admin/create</a>' ).'</span>';
522
523 if ( empty($field['recaptcha-type']) || ($field['recaptcha-type'] == 'v2') ) {
524 $output = '<label for="recaptcha_response_field">' . $item_title . $error_mark . '</label>' . wppb_recaptcha_get_html($publickey, 'pb_register');
525 if (!empty($item_description))
526 $output .= '<span class="wppb-description-delimiter">' . $item_description . '</span>';
527 }
528 else {
529 // html for Invisible reCAPTCHA
530 $output = wppb_recaptcha_get_html($publickey, 'pb_register');
531 }
532
533
534 return $output;
535
536 }
537 }
538 }
539 add_filter( 'wppb_output_form_field_recaptcha', 'wppb_recaptcha_handler', 10, 6 );
540
541
542 /* handle reCAPTCHA field validation on PB Register form */
543 function wppb_check_recaptcha_value( $message, $field, $request_data, $form_location ){
544 if( $field['field'] == 'reCAPTCHA' ){
545 if ( ( $form_location == 'register' ) && ( isset($field['captcha-pb-forms']) ) && ( strpos($field['captcha-pb-forms'],'pb_register') !== false || ( $field['recaptcha-type'] == 'v3' && wppb_maybe_enable_recaptcha_v3_on_form( $field ) ) ) ) {
546 /* theme my login plugin executes the register_errors hook on the frontend on all pages so on our register forms we might have already a recaptcha response
547 so do not verify it again or it will fail */
548 global $wppb_recaptcha_response;
549 if (!isset($wppb_recaptcha_response)){
550 $wppb_recaptcha_response = wppb_validate_captcha_response( trim( $field['public-key'] ), trim( $field['private-key'] ), isset( $field['score-threshold'] ) ? trim( $field['score-threshold'] ) : 0.5 );
551 }
552 /* reCAPTCHA must fail closed: whenever it is configured to display on this form it has to be
553 verified, regardless of the "required" toggle. A missing/empty token makes
554 wppb_validate_captcha_response() return false, so bots that omit g-recaptcha-response are blocked. */
555 if ( $wppb_recaptcha_response == false ){
556 return wppb_required_field_error($field["field-title"]);
557 }
558 }
559 }
560 return $message;
561 }
562 add_filter( 'wppb_check_form_field_recaptcha', 'wppb_check_recaptcha_value', 10, 4 );
563
564 // Get the reCAPTCHA field information
565 function wppb_get_recaptcha_field(){
566 $wppb_manage_fields = get_option( 'wppb_manage_fields', 'not_found' );
567 $field = array();
568 if ( $wppb_manage_fields != 'not_found' ) {
569 foreach ($wppb_manage_fields as $value) {
570 if ($value['field'] == 'reCAPTCHA'){
571 $field = $value;
572 break;
573 }
574 }
575 }
576 return $field;
577 }
578
579 /* Display reCAPTCHA on PB Recover Password form */
580 function wppb_display_recaptcha_recover_password( $output ){
581 $field = wppb_get_recaptcha_field();
582
583 if ( !empty($field) ) {
584 $publickey = trim($field['public-key']);
585 $item_title = apply_filters('wppb_recover_password_recaptcha_custom_field_' . $field['id'] . '_item_title', wppb_icl_t('plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_title_translation', $field['field-title'], true));
586 $item_description = wppb_icl_t('plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_description_translation', $field['description'], true);
587
588 // check where reCAPTCHA should display and add reCAPTCHA html
589 if ( isset($field['captcha-pb-forms']) && ( strpos( $field['captcha-pb-forms'],'pb_recover_password' ) !== false || ( $field['recaptcha-type'] == 'v3' && wppb_maybe_enable_recaptcha_v3_on_form( $field ) ) ) ) {
590
591 global $wppb_recaptcha_present;
592 $wppb_recaptcha_present = true;
593
594 if ( empty($field['recaptcha-type']) || ($field['recaptcha-type'] == 'v2') ) {
595 $recaptcha_output = '<label for="recaptcha_response_field">' . $item_title . '</label>' . wppb_recaptcha_get_html($publickey, 'pb_recover_password');
596 if (!empty($item_description))
597 $recaptcha_output .= '<span class="wppb-description-delimiter">' . $item_description . '</span>';
598
599 $output = str_replace('</ul>', '<li class="wppb-form-field wppb-recaptcha wppb-recaptcha-'. $field['recaptcha-type'] .'">' . $recaptcha_output . '</li>' . '</ul>', $output);
600 }
601 else {
602 // output Invisible reCAPTCHA html
603 $output = str_replace('</ul>', '<li class="wppb-form-field wppb-recaptcha wppb-recaptcha-'. $field['recaptcha-type'] .'">' . wppb_recaptcha_get_html($publickey, 'pb_recover_password') . '</li>' . '</ul>', $output);
604 }
605 }
606 }
607 return $output;
608 }
609 add_filter('wppb_recover_password_generate_password_input','wppb_display_recaptcha_recover_password');
610
611 /* Function that changes the messageNo from the Recover Password form */
612 function wppb_recaptcha_change_recover_password_message_no($messageNo) {
613
614 if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'recover_password') {
615 $field = wppb_get_recaptcha_field();
616 if (!empty($field)) {
617
618 global $wppb_recaptcha_response;
619 if (!isset($wppb_recaptcha_response)) $wppb_recaptcha_response = wppb_validate_captcha_response( trim( $field['public-key'] ), trim( $field['private-key'] ), isset( $field['score-threshold'] ) ? trim( $field['score-threshold'] ) : 0.5 );
620
621 if ( isset($field['captcha-pb-forms']) && (strpos($field['captcha-pb-forms'], 'pb_recover_password') !== false) ) {
622
623 if ( $wppb_recaptcha_response == false )
624 $messageNo = '';
625 }
626 }
627 }
628
629 return $messageNo;
630 }
631 add_filter('wppb_recover_password_message_no', 'wppb_recaptcha_change_recover_password_message_no');
632
633 /* Function that adds the reCAPTCHA error message on the Recover Password form */
634 function wppb_recaptcha_recover_password_displayed_message1( $message ) {
635 $field = wppb_get_recaptcha_field();
636
637 if ( !empty($field) ){
638 global $wppb_recaptcha_response;
639 if (!isset($wppb_recaptcha_response)) $wppb_recaptcha_response = wppb_validate_captcha_response( trim( $field['public-key'] ), trim( $field['private-key'] ), isset( $field['score-threshold'] ) ? trim( $field['score-threshold'] ) : 0.5 );
640
641 if ( isset($field['captcha-pb-forms']) && ( strpos( $field['captcha-pb-forms'],'pb_recover_password' ) !== false ) && ( $wppb_recaptcha_response == false )) {
642
643 // This message is also altered by the plugin-compatibilities.php file, in regards to Captcha plugin ( function wppb_captcha_recover_password_displayed_message1 )
644 if (($message == '<p class="wppb-warning">wppb_recaptcha_error</p>') || ($message == '<p class="wppb-warning">wppb_captcha_error</p>'))
645 $message = '<p class="wppb-warning">' . wppb_recaptcha_field_error($field["field-title"]) . '</p>';
646 else
647 $message = $message . '<p class="wppb-warning">' . wppb_recaptcha_field_error($field["field-title"]) . '</p>';
648
649 }
650 }
651
652 return $message;
653 }
654 add_filter('wppb_recover_password_displayed_message1', 'wppb_recaptcha_recover_password_displayed_message1');
655
656 /* Function that changes the default success message to wppb_recaptcha_error if the reCAPTCHA doesn't validate
657 so that we can change the message displayed with the wppb_recover_password_displayed_message1 filter */
658 function wppb_recaptcha_recover_password_sent_message_1($message) {
659
660 if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'recover_password') {
661 $field = wppb_get_recaptcha_field();
662
663 if (!empty($field)) {
664 global $wppb_recaptcha_response;
665 if (!isset($wppb_recaptcha_response)) $wppb_recaptcha_response = wppb_validate_captcha_response( trim( $field['public-key'] ), trim( $field['private-key'] ), isset( $field['score-threshold'] ) ? trim( $field['score-threshold'] ) : 0.5 );
666
667 if ( isset($field['captcha-pb-forms']) && ( strpos($field['captcha-pb-forms'], 'pb_recover_password') !== false ) && ( $wppb_recaptcha_response == false ) ){
668 $message = 'wppb_recaptcha_error';
669 }
670 }
671
672 }
673
674 return $message;
675 }
676 add_filter('wppb_recover_password_sent_message1', 'wppb_recaptcha_recover_password_sent_message_1');
677
678 /* Display reCAPTCHA html on PB Login form */
679 function wppb_display_recaptcha_login_form($form_part, $args) {
680
681 if( !isset( $args['form_id'] ) || $args['form_id'] != 'wppb-loginform' )
682 return $form_part;
683
684 $field = wppb_get_recaptcha_field();
685
686 if ( !empty($field) ) {
687 $item_title = apply_filters('wppb_login_recaptcha_custom_field_' . $field['id'] . '_item_title', wppb_icl_t('plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_title_translation', $field['field-title'], true));
688 $item_description = wppb_icl_t('plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_description_translation', $field['description'], true);
689
690 if ( isset($field['captcha-pb-forms']) && ( strpos( $field['captcha-pb-forms'],'pb_login' ) !== false || ( $field['recaptcha-type'] == 'v3' && wppb_maybe_enable_recaptcha_v3_on_form( $field ) ) ) ) { // check where reCAPTCHA should display and add reCAPTCHA html
691
692 global $wppb_recaptcha_present;
693 $wppb_recaptcha_present = true;
694
695 if ( empty($field['recaptcha-type']) || ($field['recaptcha-type'] == 'v2') ) {
696 $recaptcha_output = '<label for="recaptcha_response_field">' . $item_title . '</label>' . wppb_recaptcha_get_html(trim($field['public-key']), 'pb_login');
697 if (!empty($item_description))
698 $recaptcha_output .= '<span class="wppb-description-delimiter">' . $item_description . '</span>';
699
700 $form_part .= '<div class="wppb-form-field wppb-recaptcha wppb-recaptcha-'. $field['recaptcha-type'] .'">' . $recaptcha_output . '</div>';
701 }
702 else {
703 //output Invisible reCAPTCHA html
704 // $form_part .= wppb_recaptcha_get_html(trim($field['public-key']), 'pb_login');
705 $form_part .= '<div class="wppb-form-field wppb-recaptcha wppb-recaptcha-'. $field['recaptcha-type'] .'">' . wppb_recaptcha_get_html(trim($field['public-key']), 'pb_login') . '</div>';
706 }
707 }
708 }
709
710 return $form_part;
711 }
712 add_filter('login_form_middle', 'wppb_display_recaptcha_login_form', 10, 2);
713
714 /* Display reCAPTCHA html on default WP Login form */
715 function wppb_display_recaptcha_wp_login_form(){
716 $field = wppb_get_recaptcha_field();
717
718 if ( !empty($field) ) {
719 $item_title = apply_filters('wppb_login_recaptcha_custom_field_' . $field['id'] . '_item_title', wppb_icl_t('plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_title_translation', $field['field-title'], true));
720 $item_description = wppb_icl_t('plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_description_translation', $field['description'], true);
721
722 if ( isset($field['captcha-wp-forms']) && (strpos( $field['captcha-wp-forms'],'default_wp_login' ) !== false) ) { // check where reCAPTCHA should display and add reCAPTCHA html
723
724 global $wppb_recaptcha_present;
725 $wppb_recaptcha_present = true;
726
727 if ( empty($field['recaptcha-type']) || ($field['recaptcha-type'] == 'v2') ) {
728 $recaptcha_output = '<label for="recaptcha_response_field" style="padding-left:15px; padding-bottom:7px;">' . $item_title . '</label>' . wppb_recaptcha_get_html(trim($field['public-key']));
729 if (!empty($item_description))
730 $recaptcha_output .= '<span class="wppb-description-delimiter">' . $item_description . '</span>';
731
732 echo '<div class="wppb-form-field wppb-recaptcha" style="margin-left:-14px; margin-bottom: 15px;">' . $recaptcha_output . '</div>'; /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ /* properly escaped when constructing the var */
733 }
734 else {
735 // output Invisible reCAPTCHA html
736 echo wppb_recaptcha_get_html( trim($field['public-key'])); /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ /* properly escaped when constructing the var */
737 }
738 }
739 }
740 }
741 add_action( 'login_form', 'wppb_display_recaptcha_wp_login_form' );
742
743 //Show reCAPTCHA error on Login form (both default and PB one)
744 function wppb_recaptcha_login_wp_error_message($user){
745 //make sure you're on a Login form (WP or PB)
746 if ( isset( $_POST['log'] ) && !is_wp_error($user) && !isset( $_POST['pms_login'] ) ) {
747
748 $field = wppb_get_recaptcha_field();
749 if ( !empty($field) ){
750 global $wppb_recaptcha_response;
751
752 if (!isset($wppb_recaptcha_response)) $wppb_recaptcha_response = wppb_validate_captcha_response( trim( $field['public-key'] ), trim( $field['private-key'] ), isset( $field['score-threshold'] ) ? trim( $field['score-threshold'] ) : 0.5 );
753
754 $recaptcha_error_message = __('reCaptcha could not be verified. Please try again.','profile-builder');
755
756 if( isset( $field['recaptcha-type'] ) && $field['recaptcha-type'] === 'v2' ) {
757 $recaptcha_error_message = __('Please enter a (valid) reCAPTCHA value','profile-builder');
758 }
759
760 //reCAPTCHA error for displaying on the PB login form
761 if ( isset($_POST['wppb_login']) && ($_POST['wppb_login'] == true) ) {
762
763 // it's a PB login form, check if we have a reCAPTCHA on it and display error if not valid
764 if ((isset($field['captcha-pb-forms'])) && (strpos($field['captcha-pb-forms'], 'pb_login') !== false || ( $field['recaptcha-type'] == 'v3' && wppb_maybe_enable_recaptcha_v3_on_form( $field ) ) ) && ($wppb_recaptcha_response == false)) {
765 $user = new WP_Error('wppb_recaptcha_error', $recaptcha_error_message);
766 remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
767 remove_filter( 'authenticate', 'wp_authenticate_email_password', 20, 3 );
768 }
769
770 }
771 else {
772 //reCAPTCHA error for displaying on the default WP login form
773 if (isset($field['captcha-wp-forms']) && (strpos($field['captcha-wp-forms'], 'default_wp_login') !== false) && ($wppb_recaptcha_response == false)) {
774 $user = new WP_Error('wppb_recaptcha_error', $recaptcha_error_message);
775 remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
776 remove_filter( 'authenticate', 'wp_authenticate_email_password', 20, 3 );
777 }
778
779 }
780 }
781 }
782 return $user;
783 }
784 add_filter('authenticate','wppb_recaptcha_login_wp_error_message', 9);
785
786 /**
787 * Add a reCAPTCHA type–specific CSS class to the Register form field
788 *
789 * @param $classes - existing field classes
790 * @param $field - field data
791 * @return mixed|string
792 */
793 function wppb_register_form_recaptcha_type_class( $classes, $field ){
794
795 if ( isset( $field['field'] ) && $field['field'] == 'reCAPTCHA' && ! empty( $field['recaptcha-type'] ) )
796 $classes .= ' wppb-recaptcha-' . $field['recaptcha-type'];
797
798 return $classes;
799 }
800 add_filter( 'wppb_field_css_class', 'wppb_register_form_recaptcha_type_class', 20, 2);
801
802 // Display reCAPTCHA html on default WP Recover Password form
803 function wppb_display_recaptcha_default_wp_recover_password() {
804 $field = wppb_get_recaptcha_field();
805
806 if (!empty($field)) {
807 $publickey = trim($field['public-key']);
808 $item_title = apply_filters('wppb_recover_password_recaptcha_custom_field_' . $field['id'] . '_item_title', wppb_icl_t('plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_title_translation', $field['field-title'], true));
809 $item_description = wppb_icl_t('plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_description_translation', $field['description'], true);
810
811 if ( isset($field['captcha-wp-forms']) && (strpos( $field['captcha-wp-forms'], 'default_wp_recover_password') !== false) ) { // check where reCAPTCHA should display and add reCAPTCHA html
812
813 global $wppb_recaptcha_present;
814 $wppb_recaptcha_present = true;
815
816 if ( empty($field['recaptcha-type']) || ($field['recaptcha-type'] == 'v2') ){
817 $recaptcha_output = '<label for="recaptcha_response_field" style="padding-left:15px; padding-bottom:7px;">' . $item_title . '</label>' . wppb_recaptcha_get_html($publickey);
818 if (!empty($item_description))
819 $recaptcha_output .= '<span class="wppb-description-delimiter">' . $item_description . '</span>';
820
821 echo '<div class="wppb-form-field wppb-recaptcha" style="margin-left:-14px; margin-bottom: 15px;">' . $recaptcha_output . '</div>'; /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ /* properly escaped when constructing the var */
822 }
823 else {
824 // output Invisible reCAPTCHA html
825 echo wppb_recaptcha_get_html($publickey); /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ /* properly escaped when constructing the var */
826 }
827 }
828 }
829 }
830 add_action('lostpassword_form','wppb_display_recaptcha_default_wp_recover_password');
831
832 // Verify and show reCAPTCHA errors for default WP Recover Password
833 function wppb_verify_recaptcha_default_wp_recover_password(){
834
835 // If field 'username or email' is empty - return
836 if( isset( $_REQUEST['user_login'] ) && "" === $_REQUEST['user_login'] )
837 return;
838
839 $field = wppb_get_recaptcha_field();
840 if ( !empty($field) ){
841 global $wppb_recaptcha_response;
842 if (!isset($wppb_recaptcha_response)) $wppb_recaptcha_response = wppb_validate_captcha_response( trim( $field['public-key'] ), trim( $field['private-key'] ), isset( $field['score-threshold'] ) ? trim( $field['score-threshold'] ) : 0.5 );
843
844 $recaptcha_error_message = esc_html__('reCaptcha could not be verified. Please try again.','profile-builder');
845
846 if( isset( $field['recaptcha-type'] ) && $field['recaptcha-type'] === 'v2' ) {
847 $recaptcha_error_message = esc_html__('Please enter a (valid) reCAPTCHA value','profile-builder');
848 }
849
850 // Fail closed, but only where reCAPTCHA is configured for this form. Gate on captcha-wp-forms (as the
851 // login path does) instead of isset() of the token, so a missing token is treated as a failed verification
852 // without blocking default WP password recovery on sites that only use reCAPTCHA on PB forms.
853 if ( isset( $field['captcha-wp-forms'] ) && ( strpos( $field['captcha-wp-forms'], 'default_wp_recover_password' ) !== false ) && ( $wppb_recaptcha_response == false ) ) {
854 wp_die( esc_html( $recaptcha_error_message ) . '<br />' . esc_html__( "Click the BACK button on your browser, and try again.", 'profile-builder' ) ) ;
855 }
856 }
857 }
858 add_action('lostpassword_post','wppb_verify_recaptcha_default_wp_recover_password');
859
860 /* Display reCAPTCHA html on default WP Register form */
861 function wppb_display_recaptcha_default_wp_register(){
862 $field = wppb_get_recaptcha_field();
863
864 if (!empty($field)) {
865
866 $publickey = trim($field['public-key']);
867 $item_title = apply_filters('wppb_register_recaptcha_custom_field_' . $field['id'] . '_item_title', wppb_icl_t('plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_title_translation', $field['field-title'], true));
868 $item_description = wppb_icl_t('plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_description_translation', $field['description'], true);
869
870 wppb_recaptcha_set_default_values();
871 if (isset($field['captcha-wp-forms']) && (strpos($field['captcha-wp-forms'], 'default_wp_register') !== false)) { // check where reCAPTCHA should display and add reCAPTCHA html
872
873 global $wppb_recaptcha_present;
874 $wppb_recaptcha_present = true;
875
876 if ( empty($field['recaptcha-type']) || ($field['recaptcha-type'] == 'v2') ) {
877 $recaptcha_output = '<label for="recaptcha_response_field" style="padding-left:15px; padding-bottom:7px;">' . $item_title . '</label>' . wppb_recaptcha_get_html($publickey);
878 if (!empty($item_description))
879 $recaptcha_output .= '<span class="wppb-description-delimiter">' . $item_description . '</span>';
880
881 echo '<div class="wppb-form-field wppb-recaptcha" style="margin-left:-14px; margin-bottom: 15px;">' . $recaptcha_output . '</div>'; /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ /* properly escaped when constructing the var */
882 }
883 else {
884 // output reCAPTCHA html
885 echo wppb_recaptcha_get_html($publickey); /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ /* properly escaped when constructing the var */
886 }
887 }
888 }
889 }
890 add_action( 'register_form', 'wppb_display_recaptcha_default_wp_register' );
891
892 // Verify and show reCAPTCHA errors for default WP Register form
893 function wppb_verify_recaptcha_default_wp_register( $errors ){
894
895 $field = wppb_get_recaptcha_field();
896 if ( !empty($field) ){
897 global $wppb_recaptcha_response;
898 if (!isset($wppb_recaptcha_response)) $wppb_recaptcha_response = wppb_validate_captcha_response( trim( $field['public-key'] ), trim( $field['private-key'] ), isset( $field['score-threshold'] ) ? trim( $field['score-threshold'] ) : 0.5 );
899
900 $recaptcha_error_message = esc_html__('reCaptcha could not be verified. Please try again.','profile-builder');
901
902 if( isset( $field['recaptcha-type'] ) && $field['recaptcha-type'] === 'v2' ) {
903 $recaptcha_error_message = esc_html__('Please enter a (valid) reCAPTCHA value','profile-builder');
904 }
905
906 // Fail closed, but only where reCAPTCHA is configured for this form. Gate on captcha-wp-forms (as the
907 // login path does) instead of isset() of the token, so a missing token is treated as a failed verification
908 // without blocking default WP registration on sites that only use reCAPTCHA on PB forms.
909 if ( isset( $field['captcha-wp-forms'] ) && ( strpos( $field['captcha-wp-forms'], 'default_wp_register' ) !== false ) && ( $wppb_recaptcha_response == false ) ) {
910 $errors->add( 'wppb_recaptcha_error', $recaptcha_error_message );
911 }
912 }
913
914 return $errors;
915 }
916 add_filter('registration_errors','wppb_verify_recaptcha_default_wp_register');
917
918 // set default values in case there's already an existing reCAPTCHA field in Manage fields (when upgrading)
919 function wppb_recaptcha_set_default_values() {
920 $manage_fields = get_option('wppb_manage_fields', 'not_set');
921 if ($manage_fields != 'not_set') {
922 foreach ($manage_fields as $key => $value) {
923 if ($value['field'] == 'reCAPTCHA') {
924 if ( !isset($value['captcha-pb-forms']) ) $manage_fields[$key]['captcha-pb-forms'] = 'pb_register';
925 if ( !isset($value['captcha-wp-forms']) ) $manage_fields[$key]['captcha-wp-forms'] = 'default_wp_register';
926 if ( !isset($value['recaptcha-type']) ) $manage_fields[$key]['recaptcha-type'] = 'v2';
927 }
928 }
929 update_option('wppb_manage_fields', $manage_fields);
930 }
931 }
932
933 if ( function_exists( 'is_plugin_active' ) && is_plugin_active( 'paid-member-subscriptions/index.php' ) && defined( 'PMS_VERSION' ) && version_compare( PMS_VERSION, '2.12.9', '<' ) ) {
934
935 $notifications = WPPB_Plugin_Notifications::get_instance();
936
937 // this must be unique
938 $notification_id = 'wppb_pms_recaptcha_compatibility';
939
940 $notification_message = '<p>' . __( 'reCAPTCHA v3 is not compatible with Paid Member Subscriptions versions that are older than <strong>2.12.7</strong>. <br>Please update Paid Member Subscriptions to a newer version to avoid any issues.', 'profile-builder' ) . '</p>';
941 $notification_message .= '<a href="' . wp_nonce_url( add_query_arg( array( 'wppb_dismiss_admin_notification' => $notification_id ) ), 'wppb_plugin_notice_dismiss' ) . '" type="button" class="notice-dismiss"><span class="screen-reader-text">' . __( 'Dismiss this notice.', 'profile-builder' ) . '</span></a>';
942
943 // add the notification (we need to add the "notice is-dismissible" classes for the dismiss button to be correctly positioned)
944 $notifications->add_notification( $notification_id, $notification_message, 'wppb-notice notice notice-warning is-dismissible', false );
945
946 }
947
948 // Make sure the reCAPTCHA field score threshold is set correctly
949 function wppb_check_recaptcha_fields_settings( $values ) {
950 if( isset( $values['field'] ) && $values['field'] == 'reCAPTCHA' ) {
951 if ( empty( $values['score-threshold'] ) || $values['score-threshold'] < 0 || $values['score-threshold'] > 1 ) {
952 $values['score-threshold'] = 0.5;
953 }
954 }
955
956 return $values;
957 }
958 add_action( 'wck_update_meta_filter_values_wppb_manage_fields', 'wppb_check_recaptcha_fields_settings' );
959
960 function wppb_maybe_enable_recaptcha_v3_on_form( $recaptcha_field ){
961
962 // Static cache to avoid repeated calculations
963 static $cache = array();
964
965 // Early validation checks
966 if( empty( $recaptcha_field ) || empty( $recaptcha_field['captcha-pb-forms'] ) )
967 return false;
968
969 $post_id = get_the_ID();
970 $post = get_post( $post_id );
971
972 // Check if post is set, if not return false
973 if( empty( $post ) || empty( $post->post_content ) )
974 return false;
975
976 // Create cache key based on post ID and captcha forms configuration
977 $cache_key = md5( $post_id . serialize( $recaptcha_field['captcha-pb-forms'] ) );
978
979 // Return cached result if available
980 if( isset( $cache[ $cache_key ] ) )
981 return $cache[ $cache_key ];
982
983 $wppb_recaptcha_v3 = false;
984
985 // Define form configurations for loop processing
986 $form_configs = array(
987 'pb_register' => array(
988 'shortcode_pattern' => '[wppb-register',
989 'block_name' => 'wppb/register',
990 'other_forms' => array(
991 array( 'shortcode' => '[wppb-login', 'block' => 'wppb/login', 'form_type' => 'pb_login' ),
992 array( 'shortcode' => '[wppb-recover-password', 'block' => 'wppb/recover-password', 'form_type' => 'pb_recover_password' )
993 )
994 ),
995 'pb_login' => array(
996 'shortcode_pattern' => '[wppb-login',
997 'block_name' => 'wppb/login',
998 'other_forms' => array(
999 array( 'shortcode' => '[wppb-register', 'block' => 'wppb/register', 'form_type' => 'pb_register' ),
1000 array( 'shortcode' => '[wppb-recover-password', 'block' => 'wppb/recover-password', 'form_type' => 'pb_recover_password' )
1001 )
1002 ),
1003 'pb_recover_password' => array(
1004 'shortcode_pattern' => '[wppb-recover-password',
1005 'block_name' => 'wppb/recover-password',
1006 'other_forms' => array(
1007 array( 'shortcode' => '[wppb-register', 'block' => 'wppb/register', 'form_type' => 'pb_register' ),
1008 array( 'shortcode' => '[wppb-login', 'block' => 'wppb/login', 'form_type' => 'pb_login' )
1009 )
1010 )
1011 );
1012
1013 // Process each form type using loop
1014 foreach( $form_configs as $form_type => $config ) {
1015 // Skip if this form type is already enabled in captcha-pb-forms
1016 if( strpos( $recaptcha_field['captcha-pb-forms'], $form_type ) !== false )
1017 continue;
1018
1019 // Check if current form type exists on the page
1020 $current_form_exists = ( strpos( $post->post_content, $config['shortcode_pattern'] ) !== false || has_block( $config['block_name'] ) );
1021
1022 if( $current_form_exists ) {
1023 // Check if any other enabled form types also exist on the page
1024 foreach( $config['other_forms'] as $other_form ) {
1025 $other_form_exists = ( strpos( $post->post_content, $other_form['shortcode'] ) !== false || has_block( $other_form['block'] ) );
1026 $other_form_enabled = ( strpos( $recaptcha_field['captcha-pb-forms'], $other_form['form_type'] ) !== false );
1027
1028 if( $other_form_exists && $other_form_enabled ) {
1029 $wppb_recaptcha_v3 = true;
1030 break 2; // Break out of both loops since we found a match
1031 }
1032 }
1033 }
1034 }
1035
1036 // Cache the result
1037 $cache[ $cache_key ] = $wppb_recaptcha_v3;
1038
1039 return $wppb_recaptcha_v3;
1040
1041 }
1042