PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 4.0.3
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v4.0.3
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
← All changes | front-end/default-fields/recaptcha/recaptcha.php +216 -74 3.15.9 → 4.0.3 View file →
@@ -28,10 +28,13 @@
28 28 {
29 29 $req = _wppb_encodeQS($data);
30 30 $response = wp_remote_get($path . $req);
31 31
32 - if ( ! is_wp_error( $response ))
33 - return $response["body"];
32 + if ( is_wp_error( $response ) ) {
33 + return '';
34 + }
35 +
36 + return isset( $response['body'] ) ? $response['body'] : '';
34 37 }
35 38
36 39 /**
37 40 * Gets the challenge HTML (javascript and non-javascript version).
@@ -98,15 +101,16 @@
98 101 /* if we do not have a recaptcha field do nothing */
99 102 if( empty( $field ) )
100 103 return;
101 104
102 - //do not add script if there is no shortcode
105 + global $wppb_recaptcha_present;
103 106 global $wppb_shortcode_on_front;
104 - if( current_filter() == 'wp_footer' && ( !isset( $wppb_shortcode_on_front ) || $wppb_shortcode_on_front === false ) )
107 +
108 + //do not add script on regular frontend pages unless a PB shortcode or reCAPTCHA HTML is present
109 + if( current_filter() == 'wp_footer' && ( !isset( $wppb_shortcode_on_front ) || $wppb_shortcode_on_front === false ) && ( !isset( $wppb_recaptcha_present ) || $wppb_recaptcha_present === false ) )
105 110 return;
106 111
107 112 //do not add script if the html for the field has not been added
108 - global $wppb_recaptcha_present;
109 113 if( !isset( $wppb_recaptcha_present ) || $wppb_recaptcha_present === false )
110 114 return;
111 115
112 116 //we don't have jquery on the backend
@@ -138,8 +142,20 @@
138 142 $callback_conditions = 'jQuery(".wppb-recaptcha-element")';
139 143 $invisible_parameters = '';
140 144 }
141 145
146 + /* For Invisible reCAPTCHA the token is only produced once the async grecaptcha script has loaded and bound the
147 + submit button. Until then the submit button behaves like a plain button, so an early click would submit the form
148 + with an empty g-recaptcha-response. Since validation now fails closed on a missing token, disable the submit
149 + button(s) until the widget is ready and re-enable them afterwards (same approach used for reCAPTCHA v3 login). */
150 + $invisible_submit_selector = 'jQuery( "input[type=\'submit\'], button[type=\'submit\']", jQuery( ".wppb-recaptcha-element" ).closest( "form" ) )';
151 + $invisible_disable_submit_js = '';
152 + $invisible_enable_submit_js = '';
153 + if ( $field['recaptcha-type'] === 'invisible' ) {
154 + $invisible_disable_submit_js = $invisible_submit_selector . '.prop( "disabled", true ).addClass( "wppb-recaptcha-not-ready" );';
155 + $invisible_enable_submit_js = $invisible_submit_selector . '.prop( "disabled", false ).removeClass( "wppb-recaptcha-not-ready" );';
156 + }
157 +
142 158 if( $field['recaptcha-type'] === 'v3' ) {
143 159
144 160 //the section below is properly escaped or the variables contain static strings
145 161 // phpcs:disable
@@ -219,9 +235,13 @@
219 235 }
220 236
221 237 if( submitForm ){
222 238 jQuery(currentForm).off("submit.wppbRecaptchaV3");
223 - currentForm.submit();
239 + if( currentForm.id === "commentform" ){
240 + HTMLFormElement.prototype.submit.call(currentForm);
241 + } else {
242 + currentForm.submit();
243 + }
224 244 } else {
225 245 jQuery(document).trigger( "wppb_v3_recaptcha_success", jQuery( "input[type=\'submit\']", jQuery( currentForm ) ) )
226 246 }
227 247
@@ -244,8 +264,12 @@
244 264 echo '
245 265 <script>
246 266 window.wppbRecaptchaCallbackExecuted = false;
247 267 window.wppbRecaptcha = true;
268 +
269 + /* keep the form from being submitted with an empty token before the invisible reCAPTCHA is ready */
270 + ' . $invisible_disable_submit_js . '
271 +
248 272 var wppbRecaptchaCallback = function() {
249 273 if( !window.wppbRecaptchaCallbackExecuted ){//see if we executed this before
250 274 ' . $callback_conditions . '.each(function(){
251 275 var $recaptchaElement = jQuery(this);
@@ -255,26 +279,41 @@
255 279 grecaptcha.reset( existingRecaptchaId );
256 280 return;
257 281 }
258 282
259 - var recID = grecaptcha.render(
260 - $recaptchaElement.attr("id"),
261 - {
262 - "sitekey" : "' . $pubkey . '",
263 - "error-callback": wppbRecaptchaInitializationError,
264 - ' . $invisible_parameters . '
283 + try {
284 + var recID = grecaptcha.render(
285 + $recaptchaElement.attr("id"),
286 + {
287 + "sitekey" : "' . $pubkey . '",
288 + "error-callback": wppbRecaptchaInitializationError,
289 + ' . $invisible_parameters . '
290 + }
291 + )
292 +
293 + $recaptchaElement.data("wppb-recaptcha-id", recID);
294 + } catch( error ) {
295 + if( error && error.message && error.message.indexOf("already been rendered") !== -1 ) {
296 + return;
265 297 }
266 - )
267 298
268 - $recaptchaElement.data("wppb-recaptcha-id", recID);
299 + throw error;
300 + }
269 301 });
302 +
303 + /* the invisible reCAPTCHA is now bound to the submit button, so it is safe to re-enable it */
304 + ' . $invisible_enable_submit_js . '
305 +
270 306 window.wppbRecaptchaCallbackExecuted = true;//we use this to make sure we only run the callback once
271 307 }
272 308 };
273 -
309 +
274 310 /* the callback function for when the captcha does not load propperly, maybe network problem or wrong keys */
275 311 function wppbRecaptchaInitializationError(){
276 312 window.wppbRecaptchaInitError = true;
313 +
314 + /* the widget could not load, so re-enable the submit button and let the (fallback) submit below run */
315 + ' . $invisible_enable_submit_js . '
277 316 ';
278 317 }
279 318
280 319 if ( $field['recaptcha-type'] === 'invisible' ) {
@@ -279,9 +318,9 @@
279 318
280 319 if ( $field['recaptcha-type'] === 'invisible' ) {
281 320 echo '
282 321 /* 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){
322 + jQuery("input[type=\'submit\']", jQuery( ".wppb-recaptcha-element" ).closest("form") ).not("#commentform input[type=\'submit\']").on("click", function(e){
284 323 jQuery(this).closest("form").submit();
285 324 });
286 325 ';
287 326 }
@@ -331,9 +370,13 @@
331 370 submitForm = true;
332 371 }
333 372
334 373 if( submitForm ){
335 - form.submit();
374 + if( form.attr("id") === "commentform" && form[0] ){
375 + HTMLFormElement.prototype.submit.call(form[0]);
376 + } else {
377 + form.submit();
378 + }
336 379 } else {
337 380 jQuery(document).trigger( "wppb_invisible_recaptcha_success", jQuery( ".form-submit input[type=\'submit\']", elem.closest("form") ) )
338 381 return true;
339 382 }
@@ -401,17 +444,16 @@
401 444
402 445 if ( $remoteip == null || $remoteip == '' )
403 446 echo '<span class="error">'. esc_html__("For security reasons, you must pass the remote ip to reCAPTCHA!", "profile-builder") .'</span><br/><br/>';
404 447
405 - // Discard empty solution submissions
448 + // Discard empty solution submissions. Fail closed: a missing token is never valid.
449 + // The previous wppb_recaptcha_load_error nonce "escape hatch" was removed - that nonce is printed in the
450 + // page HTML, so a bot could replay it to skip verification. A genuinely unconfigured reCAPTCHA (empty keys)
451 + // is handled upstream in wppb_validate_captcha_response(), so this does not lock users out on misconfig.
406 452 if ($response == null || strlen($response) == 0) {
407 453 $recaptchaResponse = new wppb_ReCaptchaResponse();
454 + $recaptchaResponse->is_valid = false;
408 455
409 - if( isset( $_POST['wppb_recaptcha_load_error'] ) && wp_verify_nonce( sanitize_text_field( $_POST['wppb_recaptcha_load_error'] ), 'wppb_recaptcha_init_error' ) )
410 - $recaptchaResponse->is_valid = true;
411 - else
412 - $recaptchaResponse->is_valid = false;
413 -
414 456 return $recaptchaResponse;
415 457 }
416 458
417 459 $source = apply_filters( 'wppb_recaptcha_custom_field_source', 'www.google.com' );
@@ -424,19 +466,21 @@
424 466 'response' => $response
425 467 )
426 468 );
427 469
428 - $answers = json_decode($getResponse, true);
470 + $answers = json_decode( $getResponse, true );
429 471 $recaptchaResponse = new wppb_ReCaptchaResponse();
430 472
431 - if (trim($answers ['success']) == true) {
432 - if ( array_key_exists( 'score', $answers ) ) {
433 - $recaptchaResponse->is_valid = ($answers['score'] >= $score_threshold);
434 - } else {
435 - $recaptchaResponse->is_valid = true;
436 - }
473 + // Fail closed when the HTTP call fails or the body is not valid JSON.
474 + if ( ! is_array( $answers ) || empty( $answers['success'] ) ) {
475 + $recaptchaResponse->is_valid = false;
476 + return $recaptchaResponse;
477 + }
478 +
479 + if ( array_key_exists( 'score', $answers ) ) {
480 + $recaptchaResponse->is_valid = ( $answers['score'] >= $score_threshold );
437 481 } else {
438 - $recaptchaResponse->is_valid = false;
482 + $recaptchaResponse->is_valid = true;
439 483 }
440 484
441 485 return $recaptchaResponse;
442 486
@@ -443,8 +487,15 @@
443 487 }
444 488
445 489 /* the function to display error message on the registration page */
446 490 function wppb_validate_captcha_response( $publickey, $privatekey, $score_threshold = 0.5 ){
491 + /* If the reCAPTCHA keys are not configured the widget cannot work for anyone, so do not enforce -
492 + otherwise an incomplete setup would lock every visitor out of the form. These keys are admin-side
493 + configuration, not attacker controlled, so this cannot be used to bypass a properly configured reCAPTCHA. */
494 + if ( empty( $publickey ) || empty( $privatekey ) ) {
495 + return true;
496 + }
497 +
447 498 if (isset($_POST['g-recaptcha-response'])){
448 499 $recaptcha_response_field = sanitize_textarea_field( $_POST['g-recaptcha-response'] );
449 500 } else {
450 501 $recaptcha_response_field = '';
@@ -474,15 +525,16 @@
474 525 }
475 526
476 527 }
477 528
478 - // Save valid results when they are being triggered from an ajax request
479 - if( wp_doing_ajax() && isset( $_POST['action'] ) && $_POST['action'] == 'pms_validate_checkout' ){
529 + // Save valid results when they are being triggered from an ajax request that only pre-validates the
530 + // credentials, so the same single use token is still accepted on the form submission that follows it
531 + if( wppb_is_captcha_prevalidation_request() ){
480 532
481 - $saved = get_option( 'wppb_recaptcha_validations', array() );
533 + $saved = wppb_prune_captcha_prevalidations( get_option( 'wppb_recaptcha_validations', array() ) );
482 534
483 535 if( $already_validated === true )
484 - $saved[ $recaptcha_response_field ] = true;
536 + $saved[ $recaptcha_response_field ] = time();
485 537
486 538 update_option( 'wppb_recaptcha_validations', $saved, false );
487 539
488 540 }
@@ -542,9 +594,12 @@
542 594 global $wppb_recaptcha_response;
543 595 if (!isset($wppb_recaptcha_response)){
544 596 $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 );
545 597 }
546 - if ( ( $wppb_recaptcha_response == false ) && ( $field['required'] == 'Yes' ) ){
598 + /* reCAPTCHA must fail closed: whenever it is configured to display on this form it has to be
599 + verified, regardless of the "required" toggle. A missing/empty token makes
600 + wppb_validate_captcha_response() return false, so bots that omit g-recaptcha-response are blocked. */
601 + if ( $wppb_recaptcha_response == false ){
547 602 return wppb_required_field_error($field["field-title"]);
548 603 }
549 604 }
550 605 }
@@ -610,9 +665,9 @@
610 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 );
611 666
612 667 if ( isset($field['captcha-pb-forms']) && (strpos($field['captcha-pb-forms'], 'pb_recover_password') !== false) ) {
613 668
614 - if ( ($wppb_recaptcha_response == false ) && ( $field['required'] == 'Yes' ) )
669 + if ( $wppb_recaptcha_response == false )
615 670 $messageNo = '';
616 671 }
617 672 }
618 673 }
@@ -737,37 +792,37 @@
737 792 if ( isset( $_POST['log'] ) && !is_wp_error($user) && !isset( $_POST['pms_login'] ) ) {
738 793
739 794 $field = wppb_get_recaptcha_field();
740 795 if ( !empty($field) ){
741 - global $wppb_recaptcha_response;
796 + /* Work out whether reCAPTCHA is enabled for the form that was actually submitted before verifying
797 + anything. The token is single use, so verifying it on a form where our widget was never displayed
798 + spends a token that belongs to whatever else protects that form, and that plugin's own check
799 + then fails as a duplicate. */
800 + if ( isset($_POST['wppb_login']) && ($_POST['wppb_login'] == true) ) {
801 + // it's a PB login form, check if we have a reCAPTCHA on it
802 + $recaptcha_enabled = ( 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 ) ) ) );
803 + }
804 + else {
805 + // default WP login form
806 + $recaptcha_enabled = ( isset($field['captcha-wp-forms']) && (strpos($field['captcha-wp-forms'], 'default_wp_login') !== false) );
807 + }
742 808
743 - 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 );
809 + if ( $recaptcha_enabled ) {
810 + global $wppb_recaptcha_response;
744 811
745 - $recaptcha_error_message = __('reCaptcha could not be verified. Please try again.','profile-builder');
812 + 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 );
746 813
747 - if( isset( $field['recaptcha-type'] ) && $field['recaptcha-type'] === 'v2' ) {
748 - $recaptcha_error_message = __('Please enter a (valid) reCAPTCHA value','profile-builder');
749 - }
814 + $recaptcha_error_message = __('reCaptcha could not be verified. Please try again.','profile-builder');
750 815
751 - //reCAPTCHA error for displaying on the PB login form
752 - if ( isset($_POST['wppb_login']) && ($_POST['wppb_login'] == true) ) {
753 -
754 - // it's a PB login form, check if we have a reCAPTCHA on it and display error if not valid
755 - 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)) {
756 - $user = new WP_Error('wppb_recaptcha_error', $recaptcha_error_message);
757 - remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
758 - remove_filter( 'authenticate', 'wp_authenticate_email_password', 20, 3 );
816 + if( isset( $field['recaptcha-type'] ) && $field['recaptcha-type'] === 'v2' ) {
817 + $recaptcha_error_message = __('Please enter a (valid) reCAPTCHA value','profile-builder');
759 818 }
760 819
761 - }
762 - else {
763 - //reCAPTCHA error for displaying on the default WP login form
764 - if (isset($field['captcha-wp-forms']) && (strpos($field['captcha-wp-forms'], 'default_wp_login') !== false) && ($wppb_recaptcha_response == false)) {
820 + if ( $wppb_recaptcha_response == false ) {
765 821 $user = new WP_Error('wppb_recaptcha_error', $recaptcha_error_message);
766 822 remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
767 823 remove_filter( 'authenticate', 'wp_authenticate_email_password', 20, 3 );
768 824 }
769 -
770 825 }
771 826 }
772 827 }
773 828 return $user;
@@ -828,20 +883,25 @@
828 883 return;
829 884
830 885 $field = wppb_get_recaptcha_field();
831 886 if ( !empty($field) ){
832 - global $wppb_recaptcha_response;
833 - 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 );
887 + /* Only verify where the captcha is configured for the form being submitted. The token is single use,
888 + so verifying it on a form our widget was never displayed on spends a token that another plugin
889 + protecting that form still needs, and its own check then fails as a duplicate. */
890 + if ( isset( $field['captcha-wp-forms'] ) && ( strpos( $field['captcha-wp-forms'], 'default_wp_recover_password' ) !== false ) ) {
891 + global $wppb_recaptcha_response;
892 + 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 );
834 893
835 - $recaptcha_error_message = esc_html__('reCaptcha could not be verified. Please try again.','profile-builder');
894 + $recaptcha_error_message = esc_html__('reCaptcha could not be verified. Please try again.','profile-builder');
836 895
837 - if( isset( $field['recaptcha-type'] ) && $field['recaptcha-type'] === 'v2' ) {
838 - $recaptcha_error_message = esc_html__('Please enter a (valid) reCAPTCHA value','profile-builder');
839 - }
896 + if( isset( $field['recaptcha-type'] ) && $field['recaptcha-type'] === 'v2' ) {
897 + $recaptcha_error_message = esc_html__('Please enter a (valid) reCAPTCHA value','profile-builder');
898 + }
840 899
841 - // If reCAPTCHA not entered or incorrect reCAPTCHA answer
842 - if ( isset( $_REQUEST['g-recaptcha-response'] ) && ( ( "" === $_REQUEST['g-recaptcha-response'] ) || ( $wppb_recaptcha_response == false ) ) ) {
843 - wp_die( esc_html( $recaptcha_error_message ) . '<br />' . esc_html__( "Click the BACK button on your browser, and try again.", 'profile-builder' ) ) ;
900 + // Fail closed: a missing token is treated as a failed verification.
901 + if ( $wppb_recaptcha_response == false ) {
902 + wp_die( esc_html( $recaptcha_error_message ) . '<br />' . esc_html__( "Click the BACK button on your browser, and try again.", 'profile-builder' ) ) ;
903 + }
844 904 }
845 905 }
846 906 }
847 907 add_action('lostpassword_post','wppb_verify_recaptcha_default_wp_recover_password');
@@ -882,20 +942,25 @@
882 942 function wppb_verify_recaptcha_default_wp_register( $errors ){
883 943
884 944 $field = wppb_get_recaptcha_field();
885 945 if ( !empty($field) ){
886 - global $wppb_recaptcha_response;
887 - 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 );
946 + /* Only verify where the captcha is configured for the form being submitted. The token is single use,
947 + so verifying it on a form our widget was never displayed on spends a token that another plugin
948 + protecting that form still needs, and its own check then fails as a duplicate. */
949 + if ( isset( $field['captcha-wp-forms'] ) && ( strpos( $field['captcha-wp-forms'], 'default_wp_register' ) !== false ) ) {
950 + global $wppb_recaptcha_response;
951 + 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 );
888 952
889 - $recaptcha_error_message = esc_html__('reCaptcha could not be verified. Please try again.','profile-builder');
953 + $recaptcha_error_message = esc_html__('reCaptcha could not be verified. Please try again.','profile-builder');
890 954
891 - if( isset( $field['recaptcha-type'] ) && $field['recaptcha-type'] === 'v2' ) {
892 - $recaptcha_error_message = esc_html__('Please enter a (valid) reCAPTCHA value','profile-builder');
893 - }
955 + if( isset( $field['recaptcha-type'] ) && $field['recaptcha-type'] === 'v2' ) {
956 + $recaptcha_error_message = esc_html__('Please enter a (valid) reCAPTCHA value','profile-builder');
957 + }
894 958
895 - // If reCAPTCHA not entered or incorrect reCAPTCHA answer
896 - if ( isset( $_REQUEST['g-recaptcha-response'] ) && ( ( "" === $_REQUEST['g-recaptcha-response'] ) || ( $wppb_recaptcha_response == false ) ) ) {
897 - $errors->add( 'wppb_recaptcha_error', $recaptcha_error_message );
959 + // Fail closed: a missing token is treated as a failed verification.
960 + if ( $wppb_recaptcha_response == false ) {
961 + $errors->add( 'wppb_recaptcha_error', $recaptcha_error_message );
962 + }
898 963 }
899 964 }
900 965
901 966 return $errors;
@@ -900,8 +965,85 @@
900 965
901 966 return $errors;
902 967 }
903 968 add_filter('registration_errors','wppb_verify_recaptcha_default_wp_register');
969 +
970 +/* Display reCAPTCHA html on default WP Comments form */
971 +function wppb_display_recaptcha_default_wp_comments(){
972 + $field = wppb_get_recaptcha_field();
973 +
974 + if ( !empty( $field ) ) {
975 + if ( isset( $field['captcha-wp-forms'] ) && ( strpos( $field['captcha-wp-forms'], 'default_wp_comments' ) !== false ) ) {
976 + $publickey = trim( $field['public-key'] );
977 + $item_title = apply_filters( 'wppb_comments_recaptcha_custom_field_' . $field['id'] . '_item_title', wppb_icl_t( 'plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_title_translation', $field['field-title'], true ) );
978 + $item_description = wppb_icl_t( 'plugin profile-builder-pro', 'custom_field_' . $field['id'] . '_description_translation', $field['description'], true );
979 + $recaptcha_type = empty( $field['recaptcha-type'] ) ? 'v2' : $field['recaptcha-type'];
980 +
981 + global $wppb_recaptcha_present;
982 + $wppb_recaptcha_present = true;
983 +
984 + if ( $recaptcha_type == 'v2' ) {
985 + $recaptcha_output = '<label for="recaptcha_response_field">' . $item_title . '</label>' . wppb_recaptcha_get_html( $publickey, 'default_wp_comments' );
986 + if ( !empty( $item_description ) )
987 + $recaptcha_output .= '<span class="wppb-description-delimiter">' . $item_description . '</span>';
988 +
989 + echo '<div class="wppb-form-field wppb-recaptcha wppb-recaptcha-' . esc_attr( $recaptcha_type ) . '">' . $recaptcha_output . '</div>'; /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ /* properly escaped when constructing the var */
990 + }
991 + else {
992 + echo wppb_recaptcha_get_html( $publickey, 'default_wp_comments' ); /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ /* properly escaped when constructing the var */
993 + }
994 + }
995 + }
996 +}
997 +add_action( 'comment_form_after_fields', 'wppb_display_recaptcha_default_wp_comments' );
998 +add_action( 'comment_form_logged_in_after', 'wppb_display_recaptcha_default_wp_comments' );
999 +
1000 +function wppb_display_recaptcha_default_wp_comments_error(){
1001 + if ( !isset( $_GET['wppb_comment_recaptcha_error'] ) )
1002 + return;
1003 +
1004 + $field = wppb_get_recaptcha_field();
1005 +
1006 + if ( empty( $field ) || !isset( $field['captcha-wp-forms'] ) || ( strpos( $field['captcha-wp-forms'], 'default_wp_comments' ) === false ) )
1007 + return;
1008 +
1009 + echo '<p class="wppb-error wppb-comment-captcha-error" id="wppb_comment_recaptcha_error">' . esc_html( wppb_recaptcha_field_error( $field['field-title'] ) ) . '</p>';
1010 +}
1011 +add_action( 'comment_form_top', 'wppb_display_recaptcha_default_wp_comments_error' );
1012 +
1013 +// Verify reCAPTCHA for default WP Comments form
1014 +function wppb_verify_recaptcha_default_wp_comments( $approved, $commentdata ){
1015 + if ( !isset( $_POST['comment_post_ID'] ) )
1016 + return $approved;
1017 +
1018 + $field = wppb_get_recaptcha_field();
1019 +
1020 + if ( !empty( $field ) ) {
1021 + if ( isset( $field['captcha-wp-forms'] ) && ( strpos( $field['captcha-wp-forms'], 'default_wp_comments' ) !== false ) ) {
1022 + global $wppb_recaptcha_response;
1023 + if ( !isset( $wppb_recaptcha_response ) )
1024 + $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 );
1025 +
1026 + if ( $wppb_recaptcha_response == false ) {
1027 + $redirect_to = wp_get_referer();
1028 +
1029 + if ( empty( $redirect_to ) && isset( $commentdata['comment_post_ID'] ) )
1030 + $redirect_to = get_permalink( absint( $commentdata['comment_post_ID'] ) );
1031 +
1032 + if ( !empty( $redirect_to ) && !wp_doing_ajax() ) {
1033 + $redirect_to = preg_replace( '/#.*$/', '', remove_query_arg( array( 'wppb_comment_recaptcha_error', 'wppb_comment_turnstile_error' ), $redirect_to ) );
1034 + wp_safe_redirect( add_query_arg( 'wppb_comment_recaptcha_error', '1', $redirect_to ) . '#respond' );
1035 + exit;
1036 + }
1037 +
1038 + return new WP_Error( 'wppb_recaptcha_error', wppb_recaptcha_field_error( $field['field-title'] ), 200 );
1039 + }
1040 + }
1041 + }
1042 +
1043 + return $approved;
1044 +}
1045 +add_filter( 'pre_comment_approved', 'wppb_verify_recaptcha_default_wp_comments', 10, 2 );
904 1046
905 1047 // set default values in case there's already an existing reCAPTCHA field in Manage fields (when upgrading)
906 1048 function wppb_recaptcha_set_default_values() {
907 1049 $manage_fields = get_option('wppb_manage_fields', 'not_set');