From b9e0014d471df2dd2f83b91f2ca45316b5f1c615 Mon Sep 17 00:00:00 2001 From: Sapayth Hossain Date: Tue, 29 Oct 2024 13:14:50 +0600 Subject: [PATCH 1/5] toggle button styling and data save in settings --- Lib/WeDevs_Settings_API.php | 30 ++++++++++++ assets/css/admin.css | 44 ++++++++++++++++++ assets/css/admin/wpuf-module.css | 59 ------------------------ assets/less/admin.less | 53 +++++++++++++++++++++ includes/Admin/Plugin_Upgrade_Notice.php | 2 +- includes/functions/settings-options.php | 6 +++ 6 files changed, 134 insertions(+), 60 deletions(-) diff --git a/Lib/WeDevs_Settings_API.php b/Lib/WeDevs_Settings_API.php index 7a5cd9ad5..5a29b0c5f 100644 --- a/Lib/WeDevs_Settings_API.php +++ b/Lib/WeDevs_Settings_API.php @@ -460,6 +460,36 @@ function callback_color( $args ) { echo $html; } + /** + * Displays a toggle field for a settings field + * + * @param array $args settings field args + */ + public function callback_toggle( $args ) { + $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); + $disabled = ! empty( $args['is_pro_preview'] ) && $args['is_pro_preview'] ? 'disabled' : ''; + $name = $args['section'] . '[' . $args['id'] . ']'; + ?> +
+ +
+ =' ) ) { + if ( version_compare( WPUF_VERSION, $min_version, '>=' ) ) { return; } diff --git a/includes/functions/settings-options.php b/includes/functions/settings-options.php index 16d75bb82..753748a83 100644 --- a/includes/functions/settings-options.php +++ b/includes/functions/settings-options.php @@ -159,6 +159,12 @@ function wpuf_settings_fields() { 'desc' => __( 'Register here to get reCaptcha Site and Secret keys.', 'wp-user-frontend' ), ], + [ + 'name' => 'enable_turnstile', + 'label' => __( 'Enable Turnstile', 'wp-user-frontend' ), + 'type' => 'toggle', + 'default' => 'off', + ], [ 'name' => 'custom_css', 'label' => __( 'Custom CSS codes', 'wp-user-frontend' ), From 6b01a8c2c1c7ce0f35ee49c037eeff9dba24f143 Mon Sep 17 00:00:00 2001 From: Sapayth Hossain Date: Tue, 29 Oct 2024 16:09:33 +0600 Subject: [PATCH 2/5] show/hide dependent field conditionally --- Lib/WeDevs_Settings_API.php | 47 +++++++++++++++++++++++-- includes/functions/settings-options.php | 17 +++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/Lib/WeDevs_Settings_API.php b/Lib/WeDevs_Settings_API.php index 5a29b0c5f..90b8638f7 100644 --- a/Lib/WeDevs_Settings_API.php +++ b/Lib/WeDevs_Settings_API.php @@ -140,6 +140,7 @@ function admin_init() { 'max' => isset( $option['max'] ) ? $option['max'] : '', 'step' => isset( $option['step'] ) ? $option['step'] : '', 'is_pro_preview' => ! empty( $option['is_pro_preview'] ) ? $option['is_pro_preview'] : false, + 'depends_on' => ! empty( $option['depends_on'] ) ? $option['depends_on'] : '', ); add_settings_field( $section . '[' . $option['name'] . ']', $option['label'], (isset($option['callback']) ? $option['callback'] : array($this, 'callback_' . $type )), $section, $section, $args ); @@ -173,14 +174,17 @@ public function get_field_description( $args ) { * @param array $args settings field args */ function callback_text( $args ) { - $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) ); $size = isset( $args['size'] ) && !is_null( $args['size'] ) ? $args['size'] : 'regular'; $type = isset( $args['type'] ) ? $args['type'] : 'text'; $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"'; $disabled = ! empty( $args['is_pro_preview'] ) && $args['is_pro_preview'] ? 'disabled' : ''; + $depends_on = ! empty( $args['depends_on'] ) ? $args['depends_on'] : ''; - $html = sprintf( '', $type, $size, $args['section'], $args['id'], $value, $placeholder, $disabled ); + $html = sprintf( + '', + $type, $size, $args['section'], $args['id'], $value, $placeholder, $disabled, $depends_on + ); $html .= $this->get_field_description( $args ); if ( ! empty( $args['is_pro_preview'] ) && $args['is_pro_preview'] ) { @@ -703,6 +707,45 @@ function(){ // disable the pro preview checkboxes $('span.pro-icon-title').siblings('input[type="checkbox"]').prop('disabled', true); + + + var fields = $('table.form-table input, table.form-table select, table.form-table textarea'); + + // iterate over each field and check if it depends on another field + fields.each(function() { + var $this = $(this); + var data_depends_on = $this.data('depends-on'); + + if (!data_depends_on) { + return; + } + + var $depends_on = $("input[id*='"+ data_depends_on +"']"); + var $depends_on_type = $depends_on.attr('type'); + + if ($depends_on_type === 'checkbox') { + if ($depends_on.is(':checked')) { + $this.closest('tr').show(); + } else { + $this.closest('tr').hide(); + } + $depends_on.on('change', function() { + if ($(this).is(':checked')) { + $this.closest('tr').show(); + } else { + $this.closest('tr').hide(); + } + }); + } else { + $depends_on.on('keyup change', function() { + if ($(this).val() === $this.data('depends-on-value')) { + $this.closest('tr').show(); + } else { + $this.closest('tr').hide(); + } + }); + } + }); }); diff --git a/includes/functions/settings-options.php b/includes/functions/settings-options.php index 753748a83..b2915141e 100644 --- a/includes/functions/settings-options.php +++ b/includes/functions/settings-options.php @@ -165,6 +165,23 @@ function wpuf_settings_fields() { 'type' => 'toggle', 'default' => 'off', ], + [ + 'name' => 'turnstile_site_key', + 'label' => __( 'Turnstile Site Key', 'wp-user-frontend' ), + 'depends_on' => 'enable_turnstile', + ], + [ + 'name' => 'turnstile_secret_key', + 'label' => __( 'Turnstile Site Key', 'wp-user-frontend' ), + 'depends_on' => 'enable_turnstile', + 'desc' => sprintf( + // translators: %s is a link + __( + 'Register here to get Turnstile Site and Secret keys.', + 'wp-user-frontend' + ), esc_url( 'https://developers.cloudflare.com/turnstile/' ) + ), + ], [ 'name' => 'custom_css', 'label' => __( 'Custom CSS codes', 'wp-user-frontend' ), From 0dbd738ae68d0ab025b8168b4a88496ae3c21474 Mon Sep 17 00:00:00 2001 From: Sapayth Hossain Date: Wed, 30 Oct 2024 10:29:52 +0600 Subject: [PATCH 3/5] client side rendering and validation --- Lib/WeDevs_Settings_API.php | 32 +++++++++++++------------ includes/Assets.php | 5 +++- includes/Free/Simple_Login.php | 7 +++++- includes/functions/settings-options.php | 13 +++++++++- templates/login-form.php | 25 +++++++++++++++++-- 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/Lib/WeDevs_Settings_API.php b/Lib/WeDevs_Settings_API.php index 90b8638f7..eac841279 100644 --- a/Lib/WeDevs_Settings_API.php +++ b/Lib/WeDevs_Settings_API.php @@ -475,22 +475,24 @@ public function callback_toggle( $args ) { $name = $args['section'] . '[' . $args['id'] . ']'; ?>
- +
+ + '1.6.0', 'in_footer' => true, ], - 'admin-shortcode' => [ + 'admin-shortcode' => [ 'src' => WPUF_ASSET_URI . '/js/admin-shortcode.js', 'deps' => [ 'jquery' ], ], @@ -374,6 +374,9 @@ public function get_scripts() { 'headway' => [ 'src' => '//cdn.headwayapp.co/widget.js', ], + 'turnstile' => [ + 'src' => 'https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback', + ], ]; if ( ! empty( $api_key ) ) { diff --git a/includes/Free/Simple_Login.php b/includes/Free/Simple_Login.php index 200e7f638..d44f64ce0 100644 --- a/includes/Free/Simple_Login.php +++ b/includes/Free/Simple_Login.php @@ -339,7 +339,7 @@ public function login_form() { $reset = isset( $getdata['reset'] ) ? sanitize_text_field( $getdata['reset'] ) : ''; if ( false === $login_page ) { - return; + return ''; } ob_start(); @@ -394,6 +394,11 @@ public function login_form() { default: $loggedout = isset( $getdata['loggedout'] ) ? sanitize_text_field( $getdata['loggedout'] ) : ''; + $enable_turnstile = wpuf_get_option( 'enable_turnstile', 'wpuf_general', 'off' ); + + if ( 'on' === $enable_turnstile ) { + wp_enqueue_script( 'wpuf-turnstile' ); + } if ( $loggedout === 'true' ) { $this->messages[] = __( 'You are now logged out.', 'wp-user-frontend' ); diff --git a/includes/functions/settings-options.php b/includes/functions/settings-options.php index b2915141e..315862b35 100644 --- a/includes/functions/settings-options.php +++ b/includes/functions/settings-options.php @@ -172,7 +172,7 @@ function wpuf_settings_fields() { ], [ 'name' => 'turnstile_secret_key', - 'label' => __( 'Turnstile Site Key', 'wp-user-frontend' ), + 'label' => __( 'Turnstile Secret Key', 'wp-user-frontend' ), 'depends_on' => 'enable_turnstile', 'desc' => sprintf( // translators: %s is a link @@ -454,6 +454,17 @@ function wpuf_settings_fields() { 'type' => 'checkbox', 'default' => 'off', ], + [ + 'name' => 'login_form_turnstile', + 'label' => __( 'Turnstile in Login Form', 'wp-user-frontend' ), + 'desc' => __( + 'If enabled, users have to verify Cloudflare Turnstile in login page. Also, make sure that Turnstile is configured properly from General Options', + 'wp-user-frontend' + ), + 'type' => 'toggle', + 'default' => 'off', + 'depends_on' => 'enable_turnstile', + ], ] ), 'wpuf_payment' => apply_filters( 'wpuf_options_payment', [ [ diff --git a/templates/login-form.php b/templates/login-form.php index c23aaacb1..2b12921ea 100644 --- a/templates/login-form.php +++ b/templates/login-form.php @@ -30,8 +30,13 @@

- - + +

+ +
+ + +

From 89e7c2469dc2db1b0a3646449bfef04bdee8282d Mon Sep 17 00:00:00 2001 From: Sapayth Hossain Date: Wed, 30 Oct 2024 12:14:46 +0600 Subject: [PATCH 4/5] server side verification done --- assets/css/frontend-forms.css | 2 +- assets/less/frontend-forms.less | 2 +- includes/Free/Simple_Login.php | 71 ++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/assets/css/frontend-forms.css b/assets/css/frontend-forms.css index 0ff853676..39fb30fe9 100644 --- a/assets/css/frontend-forms.css +++ b/assets/css/frontend-forms.css @@ -84,7 +84,7 @@ body .wpuf-error { background-color: #f2dede; color: #a94442; border: 1px solid #ebccd1; - margin: 10px 10px 20px; + margin: 10px 0 20px 0; padding: 10px; -webkit-border-radius: 3px; -moz-border-radius: 3px; diff --git a/assets/less/frontend-forms.less b/assets/less/frontend-forms.less index 6954c3b8a..902907249 100644 --- a/assets/less/frontend-forms.less +++ b/assets/less/frontend-forms.less @@ -116,7 +116,7 @@ body { background-color: #f2dede; color: #a94442; border: 1px solid #ebccd1; - margin: 10px 10px 20px; + margin: 10px 0 20px 0; padding: 10px; .border-radius(3px); font-size: 13px; diff --git a/includes/Free/Simple_Login.php b/includes/Free/Simple_Login.php index d44f64ce0..2afac5da4 100644 --- a/includes/Free/Simple_Login.php +++ b/includes/Free/Simple_Login.php @@ -19,6 +19,13 @@ class Simple_Login { private $messages = []; + /** + * Cloudflare Turnstile messages + * + * @var array + */ + private $cf_messages = []; + private static $_instance; public function __construct() { @@ -415,6 +422,52 @@ public function login_form() { return ob_get_clean(); } + /** + * Verify if cloudflare turnstile request is successful + * + * @since WPUF_SINCE + * + * @return bool + */ + private function verify_cloudflare_turnstile_on_login() { + $nonce = isset( $_POST['wpuf-login-nonce'] ) ? sanitize_key( wp_unslash( $_POST['wpuf-login-nonce'] ) ) : ''; + + if ( isset( $nonce ) && ! wp_verify_nonce( $nonce, 'wpuf_login_action' ) ) { + return false; + } + + $secret = wpuf_get_option( 'turnstile_secret_key', 'wpuf_general', '' ); + + if ( empty( $secret ) ) { + return false; + } + + $remote_addr = ! empty( $_SERVER['REMOTE_ADDR'] ) ? sanitize_url( + wp_unslash( $_SERVER['REMOTE_ADDR'] ) + ) : ''; + + $cf_url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'; + $token = ! empty( $_POST['cf-turnstile-response'] ) ? sanitize_text_field( wp_unslash( $_POST['cf-turnstile-response'] ) ) : ''; + + // Request data + $data = [ + 'secret' => $secret, + 'response' => $token, + 'remoteip' => $remote_addr, + ]; + + $response = wp_remote_post( $cf_url, [ 'body' => $data ] ); + $body = json_decode( wp_remote_retrieve_body( $response ), true ); + + if ( ! empty( $body['success'] ) ) { + return true; + } else { + $this->cf_messages[] = ! empty( $body['error-codes'] ) ? $body['error-codes'] : ''; + + return false; + } + } + /** * Remove selected cookie to have consistency with the login nonce. * fixes WooCommerce Stripe Gateway plugin conflict @@ -452,10 +505,24 @@ public function process_login() { return; } - $log = isset( $_POST['log'] ) ? esc_attr( wp_unslash( $_POST['log'] ) ) : ''; - $pwd = isset( $_POST['pwd'] ) ? trim( $_POST['pwd'] ) : ''; + $log = isset( $_POST['log'] ) ? sanitize_text_field( wp_unslash( $_POST['log'] ) ) : ''; + $pwd = isset( $_POST['pwd'] ) ? sanitize_text_field( ( wp_unslash( $_POST['pwd'] ) ) ) : ''; // $g_recaptcha_response = isset( $_POST['g-recaptcha-response'] ) ? sanitize_text_field( wp_unslash( $_POST['g-recaptcha-response'] ) ) : ''; + if ( ! $this->verify_cloudflare_turnstile_on_login() ) { + $errors = ! empty( $this->cf_messages[0] ) ? $this->cf_messages[0] : ''; + $errors = implode( ', ', $errors ); + $this->login_errors[] = + sprintf( + // translators: %1$s and %2$s are strong tags, %3$s is the error message + __( '%1$sError%2$s: Cloudflare Turnstile verification failed. Reasons: [%3$s]', 'wp-user-frontend' ), + '', + '', + $errors + ); + '' . __( 'Error', 'wp-user-frontend' ) . ': ' . __( 'Cloudflare Turnstile verification failed. Reasons: [', 'wp-user-frontend' ); + } + $validation_error = new WP_Error(); $validation_error = apply_filters( 'wpuf_process_login_errors', $validation_error, $log, $pwd ); From 6aa3b3ffddf0bd035f325fdd3eaa43e1d6a8b5ec Mon Sep 17 00:00:00 2001 From: Sapayth Hossain Date: Thu, 31 Oct 2024 10:32:58 +0600 Subject: [PATCH 5/5] enhance: form builder field Cloudflare Turnstile --- Lib/WeDevs_Settings_API.php | 1 - .../form-cloudflare_turnstile/index.js | 36 ++++ .../form-cloudflare_turnstile/template.php | 12 ++ admin/form-builder/assets/js/mixins/global.js | 4 + .../cloudflare-placeholder-dark-compact.png | Bin 0 -> 7079 bytes assets/images/cloudflare-placeholder-dark.png | Bin 0 -> 8217 bytes .../cloudflare-placeholder-light-compact.png | Bin 0 -> 7476 bytes .../images/cloudflare-placeholder-light.png | Bin 0 -> 8228 bytes assets/js-templates/form-components.php | 15 ++ assets/js/wpuf-form-builder-components.js | 37 ++++ assets/js/wpuf-form-builder-mixins.js | 4 + includes/Admin/Forms/Admin_Form_Builder.php | 4 + includes/Admin/Forms/Field_Manager.php | 41 +++-- .../Form_Field_Cloudflare_Turnstile.php | 168 ++++++++++++++++++ 14 files changed, 302 insertions(+), 20 deletions(-) create mode 100644 admin/form-builder/assets/js/components/form-cloudflare_turnstile/index.js create mode 100644 admin/form-builder/assets/js/components/form-cloudflare_turnstile/template.php create mode 100644 assets/images/cloudflare-placeholder-dark-compact.png create mode 100644 assets/images/cloudflare-placeholder-dark.png create mode 100644 assets/images/cloudflare-placeholder-light-compact.png create mode 100644 assets/images/cloudflare-placeholder-light.png create mode 100755 includes/Fields/Form_Field_Cloudflare_Turnstile.php diff --git a/Lib/WeDevs_Settings_API.php b/Lib/WeDevs_Settings_API.php index eac841279..9f3098aa8 100644 --- a/Lib/WeDevs_Settings_API.php +++ b/Lib/WeDevs_Settings_API.php @@ -710,7 +710,6 @@ function(){ // disable the pro preview checkboxes $('span.pro-icon-title').siblings('input[type="checkbox"]').prop('disabled', true); - var fields = $('table.form-table input, table.form-table select, table.form-table textarea'); // iterate over each field and check if it depends on another field diff --git a/admin/form-builder/assets/js/components/form-cloudflare_turnstile/index.js b/admin/form-builder/assets/js/components/form-cloudflare_turnstile/index.js new file mode 100644 index 000000000..1de5a8a4b --- /dev/null +++ b/admin/form-builder/assets/js/components/form-cloudflare_turnstile/index.js @@ -0,0 +1,36 @@ +/** + * Field template: Cloudflare Turnstile + */ +Vue.component('form-cloudflare_turnstile', { + template: '#tmpl-wpuf-form-cloudflare_turnstile', + + mixins: [ + wpuf_mixins.form_field_mixin + ], + + computed: { + has_turnstile_api_keys: function () { + return wpuf_form_builder.turnstile_site && wpuf_form_builder.turnstile_secret; + }, + + no_api_keys_msg: function () { + return wpuf_form_builder.field_settings.turnstile.validator.msg; + }, + + turnstile_image: function () { + var base_url = wpuf_form_builder.asset_url + '/images/cloudflare-placeholder-'; + + if (this.field.turnstile_theme === 'dark') { + base_url += 'dark'; + } else { + base_url += 'light'; + } + + if (this.field.turnstile_size === 'compact') { + base_url += '-compact'; + } + + return base_url + '.png'; + } + } +}); diff --git a/admin/form-builder/assets/js/components/form-cloudflare_turnstile/template.php b/admin/form-builder/assets/js/components/form-cloudflare_turnstile/template.php new file mode 100644 index 000000000..6eb749161 --- /dev/null +++ b/admin/form-builder/assets/js/components/form-cloudflare_turnstile/template.php @@ -0,0 +1,12 @@ +

+ + + +
diff --git a/admin/form-builder/assets/js/mixins/global.js b/admin/form-builder/assets/js/mixins/global.js index 60ecffd03..0482a6834 100644 --- a/admin/form-builder/assets/js/mixins/global.js +++ b/admin/form-builder/assets/js/mixins/global.js @@ -44,6 +44,10 @@ Vue.mixin({ return (wpuf_form_builder.recaptcha_site && wpuf_form_builder.recaptcha_secret) ? true : false; }, + has_turnstile_api_keys: function () { + return wpuf_form_builder.turnstile_site && wpuf_form_builder.turnstile_secret; + }, + containsField: function(field_name) { var self = this, i = 0; diff --git a/assets/images/cloudflare-placeholder-dark-compact.png b/assets/images/cloudflare-placeholder-dark-compact.png new file mode 100644 index 0000000000000000000000000000000000000000..ed8eae74681c72e922a9eb8e105ec80eb13c5979 GIT binary patch literal 7079 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 I=jP%61^k?J82|tP literal 0 HcmV?d00001 diff --git a/assets/images/cloudflare-placeholder-dark.png b/assets/images/cloudflare-placeholder-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..417250f0e01c0457fdb4c4d8937569f3ba7dcfe4 GIT binary patch literal 8217 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 Sz3ze0S9z(SP$6d?^1lG{tY;el literal 0 HcmV?d00001 diff --git a/assets/images/cloudflare-placeholder-light-compact.png b/assets/images/cloudflare-placeholder-light-compact.png new file mode 100644 index 0000000000000000000000000000000000000000..be7012d1c82c431ad7e175c5300854f5f5d40734 GIT binary patch literal 7476 zcmdU!^;cBUzxU73-64X22m(3`-7ti7OE=Ozv~(&e64FQ`jifX~3?LHHEhRaml+@67 zyw7*tyPoGicz!ss_h;|-TKj#@T4%psCrV30k(l5i0RRBR%1UzD=xZ4I@WaDFpT+L4 z5C8zmcGNZWHdI#=vvzZZSlYN**+TqW-O+UbkdX3ox3qS)^=7uRwReO`vK+P|SePAc zBv}ju)p^w2U)VZ0Dg}7j>I7)$S_e2=i`uYAK?x-M#Lxn+w%(S^ey%PsFEKw!mjBij zL*M`F=4N63?;+mKk}QVmTFfupJZ+hUAUqHr7AOI;gr|+2n6{k4e*x5t>M*bWEFWzI_rD4^FNBBtzlZ;8iD^0d*}53XIl9`y zywIAGEWCU?|4-HM|Eh}oZ}o+ni<_qo+Du#YG#2iE%jEvgI?;x4|Bqwn#{YP33qu?2 ziFVYhIe!cNG(cY3in2h}2*VBl(90{!$>{ol_OtPmlc!Vq+_>7M4+#aLnKSX;a&f3g zn|`p$Dz%Jb&!ChTr^HWxOc(okqen#a)HHPYh3tc^eoE-!ARWQn~u-$Q#gN-?kTj?Fd*7yy!UmecyV~eoei6=DOS=Nr8vO zN=2Z|NjP2C>YIjg7r_ammJj?;BHoQ8keqdb<4*|0)PNFf>$8FpA;L zV8e6l?BvAS&sN}fu`9x|{mWqYX)D4yx~nyS6nMmd$p}aQ-tPF`M}rsOFx)T_NH|Hz zWe)ZcFxJI3*2TSC2QUKj78uZD$05;I7xeSFnSGDR@#|Z$r7wN1F6PF~wDkhD5Rv;S z{mku+`|RPbal@om(zY7GiS(PdTE$$!T2S#elOSj-_IQW^@@1R}#(o8UE(t4(_}Aw) z_X(1KvNdsbGSAEpQm05dp*OLP)MjWHGOITRnSCBScQ1K-ktrv3+LXVJd7U2we!2| zlr_G7_J^+x{DyI5?8}SsWz4K9X2X?8mdE~vq7vji?iB;|R^k}3T_>7~Y z!@uruG9BU2=b7H>SQWuz(3=vQSgXP2L|lW*EBCO>A9o;GI@1&&unN4W3^7pkDK)Oz z7FB?ILzIW^bq?4BUXc*u5*lLO?t5sSF6Q%fC|lgX zDQ-F|(ZJ=N-+!@Kurr;Zd3_i>JTj6>{an9)b2t-;D}@U8-k+a-EjZPF)J-_ie4(w)~G zd>{%gVZ9bI1Ese@D$Sc2&NkcZ{)COL_=4x%DjS|lGW(RwsDEICEW{deGj!NB|ng^fhaW0!d+}h7lsc30c z{ry``_a|o^R?LN5e!WVyTImeO>8YpyU$+Q$4*VQS)MKjPn?EWb_L){Jx9y6+uJ!n? z(BgOcBQZUJldXtt0$~w4@N>k;NNC^vDNpd#>9x4;0Yg)++-1*s?gCtE6BeqjQcGAQ zQpdw79FS-B{EW|e55wR8nqGna$^~CjPenz==I-WF=sNuvmxO_*3E+80M91<;^89n# z&BS10S}wa=+wr>=!rdmC{vxx%dG=?U{|Qk{7#?k% z`>JdmkMm4Lg4EsdCk*#@pB_K}Zt6(Ud9 z4pF>%rqIAwy>go?$w}MAW)Gn{YLxycSbGQJ8z-Z=lDr`z^aMy*SD4(ju)A8H=if}={OMKqjTKp#r)^H~O4f0G^B9apg zR-)ylN)zGCSd{rz=*zc8t#C0D)Hp7445Q>ckVmd-;zdP6tx|2?juq*Z6EfD%-Jb?2 zGIOEr{?iM059u3uq;0J2lvnWR2E>^cjU-0s(7awe&M(5YDglLkpt9Q>Kv;M-DS*BQ ztUBd9A&%zAjV;C2FR8)-*aYNiTx-7w`XRwE0 zRAU8-q%Hf63oiQnUg?)$nr}o0QoUl>^*y-QR%^JVj4lu?GGZp^qV!A_qsAiTDqsHW z%b5nXuV25ub!D50xX*2}?jym(TKN*!eFjJ$6f1Z~6LWzJ_2*hPQ4InIGrOAmrkOj# zKTvuy=>aCQv@^5?D%#_F$$1#hN;joGmZ0=|V({+=h-~-zx@$CZq35EW8%mTpcbX2F z9-o&=azo}T!tf2K>C1zt9?gsi)pf$DQpic>a({K`t@Gt}!Ka6nea_YGPe&y$vbezIB>DrCni7wn>sQ5#HOL*d zUB^kBobuO}SbYLLrel%f0y;&WF-)hzu~KNx$L*Z?aFAHlPD&pbBABE?+R}AtLO;Kv zny6FMygWwS`~rXHYFcFRT@G&In)-$9J+cE{YV{RC?FSAcjRyx2rMgVQ zP(Wi2_~s`(Z4M(NogjB{(bSnxy&|E7B6}`tU3`lv1Z8PLUt?|A?sJ2XGJS=<(A9!U}=RPhwcmE@#j-bD+l8y7rN+StN`YpLgx97E&!}XN$<(rU& zI6cNvfg;)s+6Nza@9`L!G%RB1ZbjeW5Nt&b=B+?^R>MAEuM!I{zWRt=-tc8!K`hpK zEYs|$x^mL%A(KeZcFj--tkEbU8Uj~(Fq-YV#JP;>72YV$gz>%NWkm7fRN$W^w@t++RT`FaPozNjhUOrFXPu97ZA3UrBg!y7yOt8{XU8oeLM~x?z4g6x068 zmoFPza$h#j>J=P;LHbC7755pbVGX{pwDO1d6P@#amYQZG^qaA0N{5`DYN{5AGP;7K zwZXufud{-kp}~A6IY##tG2@l1hkbYDL@NeTTxQBi0d~{Tx$O|r${@Mg+e<#LZp0v) znWDqCVv~-Cj-#x=rZb;|K;mSy6%H*mt)Q{^2wTq!$EnC&Fs#e?yV3AWaxTxOUQq58 z^Q!ABokYX1aQWaO-*JG>G$?!n2f;9a!Lj)FhiDHhHYSyz&_YIYCtFH76i*u*X>`^6 z@GKo4zhNhD{#d*?&F6(lv`&!8PJKftdbjeEc*nwaiF|-`Qy?SM9yGP)=qJpIR78xS zWa1hJsBf7t2;P;p@J|-UlDs8x(&g0=yDqS6sHELIb2Gyj!Ol7t8cVP*#yP8Ywo7;i zD;TdZMAk`OO{QLY-rg|%l;XM+zBTe|;d*CvU1!dLPoq?YsME)!t1eW*aD5FTq9V(x z--R)>KhqiZmp_A+Nf$YKO}rVe#e^Wp7}K z)l}z6=Ki*P%uOZJ4O4yPnw41dZ8#1-&2V-*jdd1q{1_S)br%Qu|HmJEOr*c-aSvF7>luMW$b<;~ZiT(wtg9)j&!GK>&{^EXm%h5<>nUfTtg8@k zQzn+eZ?I7Tj54&NxNE$xcVXRr-G*F~pAgFw}vrET)Bw0nN>k>~h3L9^uy zuf`miNNZ>Ee1qtpJ(9Zcbz!Hf4+Mncq#GL#N#o&MLb;4i`Dz4GYVUF z5KJkyZWQ*mC&kZNM`~`G6qaYm|w7;#%9at4%$Q`UqIT`mK=*RX@>2s8ecm+%Zv98M1W*M9S$Wz{A9X zpL%9{{7~sBy;FU1yz^x5R!_Vr(>ZrDVxdv<1JsOwMyjGG z;yCP&^>rZ(sdjv5R4}TfpHvm~oHa;}y+#aY2^-~~nh!ZJq|K5jIm^5x37nJwWwhlV zgiTcj%VL~0tZ~DoZ?3%0l}f5q6ix_!7=Oa5>c*7D=vFB$b3NAOoeum_GOB2Ib}(zI z#4&$<_OgBVMh`&g&HXuhGX5yc(cE6dXA@t5$)ouXMnYB)zAiXP`V0~kbdYv6N*f*8 zzrV))s7N=Wcio08JD}$`%h42{N;5V;MIFOjtA3MzH7DM)Y3K64)KtdKlnXS0UspJo zE8yXz&tfnlghJHGDfNZd=!3G0AMF&{$L$mtoDGyel)}@6#a{{Xv(|^EybbmtPNwhg zxm-006TznTs#^jD3Igu~)T_v$_g3WUaD1{LIw#DV49yRV z^5kZJ652ktNrP_$9E%YyAEsz8big($3MDL2F(~^ehCAKePfV%n*U-eF_C40-(8|r) zxiSG&pTc=z5S1VBL8s+dAlgAfs@^^uB~M|_QO zuB_pva(5S#qfZjec>={qJeL?T}h0~P2!LFrVG4(Xw{7f2mg$ZK* zVXDhGL8Sn*fWYebJXPI8xOnNp-&8Cdivj^*mAs&E*b^UOX%}gKBkg_Zb~vS8+cT-f z6=;lfmK!6mMx`q;td`K_QZ{;MDeT`p6d>TpuRUE<9^ACfzA+ec|JQrkNb@BjK*Pco z%%*L?c{aV^O>UTfM!?5B2|UQPs8nS(2+D5VDeJLAd>d!&Pnej{9@Lu+njy{bXJf<% z06V|nQUz)o<4-$wM`MTTduEg)p_f^o0GtSJLZ){W(9meGK&JrFt zccwaje6mFr{*H?xF|sCT!G_GCw|f>``@6%!%U}ajkI15cKy(5x@~!^;_pBTN@pq{{ z{gi(6JMhq`do%d@e86YcjD7iLQ<&@VX?bc7MW=&T;i-N8Z0u2H|(<+VBV z4QrzC0~_|Avsnwb0oDNm4XfQxQg^>lNn=-W;s@~|!Pf&i_ZP{w-1ZWzG2TBh481lb z?1N$LXZnM|YUr&qEP1ZZo=~}Z;F${4<|^^yUAj?dtp`8kr*Fr}qrptIVsFJJ+lE|` zb$w2Dr;)WMZ_jT|MhDG&m)J6eT=|gd>3s6$A(ys~$xjwryli)Bi&CqoCzWwVk%MW2 zpF&Qb_+Kpf+Fl$id7?Mgc+zDR70DONp%&EqiU1Dh@0Y!3GC-_ma~Xn;c504@8zeW9 z7J-VieZoFleQX4u((Y+Z_dosh^7172-sL8aN$NL;Z7I!PI7J9b8EgEp(oTK@z9 z0A254+lhw%$*^$jeRm`w*MNZQ7Z8f_WgC5`C??`uV)tu-k6_@lDjMTC(tOzwZ-pt4(FnXg(3U*P@nBI(e;o z`-jr`ksa3uNu*GebR%r(A+jL7ckt&=mqv@A;~x{PzHWPpp=nfNyREz@P#xA&g-?vG zbR#b%BE60>1soIAawO(@HM;Fh$?E;ai_x58MEtPLA;)r$?tVdZ3qy;BpXhOdW2W^k z8I^34W(uhfRRsXeef`;MF+zt=r6lKMNC0XUdWG?9*U8CA<7h0vp+HW%Yn`I1xJc1kM-X4eBv>J`ou&E zPELp;mVUneN)`y9jf+2?{YM3YE?Sobf8=%k%ldHNLl{A447W++&<)rwa6(EW@kgiy zxS1fxSzbQ!X4e2w`*tMF)H7-*Lr}F?Bio5{z13&WZU*aB=V7+*Z{Cp4?kHjgkug68 zXpkYS?O4H!{q#$6TG|4}-?EaN#950_GaTZFtWx)vqewJ_N+OlI8LQ1mnhRQJbp6|e zxE%DH$|tM7G40;&6F7S@w~aT>jln&Aj=y$X|m7I;Hz8H<`>1W=iuP=Ztk`t zSvpbALj3IrLI}@E(7&8i(Pd-x4D|hSE0_C;LQH(u8(hMVB-@M`bEiqUH$BOH`O!ig z1oA{oP*YufzMx<3_`BQzH542~MVhy(x|eqs2yT}W&cYyjqTA~W;n}X{8ir;{6efYg zBu>(Z%l+JF$kV3fkk;eD(a|OkBodkKk3h4dNawuM-Dy?0_l^}mqgdg$K5TccF`TSp zs^0G#4$E!f$1$t}uFX95-H&7Ok@8WMTjHDaNalLO$%Ea@iG0#mTHKcPSxmlXi?byp zO|o6sEpxvZxKPc!qB$^dkZfj-V==cS3k~6^UxON`-#GMXkM2Rn?uSVFWR^ zZK|lA;f>Nn5@#=BBvfZbb5)s52F&L%tE`I({UI(Y@(_Ha^T+o}HhllQa3%cIre;Gc0$lw3CQzqv~bD&6>twN+n+9 z#_*@UU#B0ne~$^sK3}=~1HI5!1i5rjl|0@PRQG zFN0nID;%%8hL)RyqsHCML-|{UMU#22g^)Sid*6yb<(#V1lHVY_^Y|@3Wd&mm`O=d{ zgzX?rozkM|+8wqBPBO6}!!KY6b-Yeov6$AG;eJ9uh_NK6`W_3YvtKxOeT@JtG^gUU zz`0nKsbC{3ehT66iTA|xb|6{|iA8|`9k+gW3D;Ad)+05xRm{Z1$x<{Tls1z-rbaV#dV zCaM;aF_M^m3o;gmmdJKhnw5(8smW~PF(D~C`1!D?n*SZd(h(N zJW{5M>_!G1#Z`$@fDVHB@R-ISE9uLMA692X+?)%)H1=mDnH6=yy5oO<$_KO(0kNCo zTndJVaF77`VU0AM-w6j-z-lZ4;#t_zB16W)(G=wRZLaA9>M4v1v}A02Cf3(NzC_&8 z(+@|BZ^i1dr48FgbY)%|#(Hx^xiL&yPW^t6_!LA6C{rTml>0F|=gOK2W9KoYC*=HJ zQ~U+oU+;1`7Bu#Q77{nlo0Qkr$W_GgMS|&p<}zt{mh1ldRu(sDeC1Agfj1o4AE>$r lSyaq-9#AloVdLE~jY=_(OK`CM`uDR_Szbe~O7>O6e*s@q8dm@S literal 0 HcmV?d00001 diff --git a/assets/images/cloudflare-placeholder-light.png b/assets/images/cloudflare-placeholder-light.png new file mode 100644 index 0000000000000000000000000000000000000000..b63cd087ca2fa9c85ccfb3735717f903c49b85ea GIT binary patch literal 8228 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 KlCG3A3Hm=LZIw;{ literal 0 HcmV?d00001 diff --git a/assets/js-templates/form-components.php b/assets/js-templates/form-components.php index ca68db439..93414ac83 100644 --- a/assets/js-templates/form-components.php +++ b/assets/js-templates/form-components.php @@ -438,6 +438,21 @@ class="option-chooser-radio"
+ + + + 'has_turnstile_api_keys', + 'button_class' => 'button-faded', + 'msg_title' => __( 'Site key and Secret key', 'wp-user-frontend' ), + 'msg' => sprintf( + // translators: %s: settings url + __( 'You need to set Site key and Secret key in Settings in order to use "Cloudflare Turnstile" field. Click here to get the these key.', 'wp-user-frontend' ), + admin_url( 'admin.php?page=wpuf-settings' ), + 'https://developers.cloudflare.com/turnstile/' + ), + ]; + } + + /** + * Get field options setting + * + * @since WPUF_SINCE + * + * @return array + */ + public function get_options_settings() { + $settings = [ + [ + 'name' => 'label', + 'title' => __( 'Title', 'wp-user-frontend' ), + 'type' => 'text', + 'section' => 'basic', + 'priority' => 10, + 'help_text' => __( 'Title of the section', 'wp-user-frontend' ), + ], + [ + 'name' => 'turnstile_theme', + 'title' => 'Turnstile Theme', + 'type' => 'radio', + 'options' => [ + 'light' => __( 'Light', 'wp-user-frontend' ), + 'dark' => __( 'Dark', 'wp-user-frontend' ), + ], + 'default' => 'light', + 'section' => 'basic', + 'priority' => 12, + 'help_text' => __( 'Select turnstile theme', 'wp-user-frontend' ), + ], + [ + 'name' => 'turnstile_size', + 'title' => 'Turnstile Size', + 'type' => 'radio', + 'options' => [ + 'normal' => __( 'Normal [Width: 300px, Height: 65px]', 'wp-user-frontend' ), + 'flexible' => __( 'Flexible [Width: 100% (min: 300px), Height: 65px]', 'wp-user-frontend' ), + 'compact' => __( 'Compact [Width: 150px, Height: 140px]', 'wp-user-frontend' ), + ], + 'default' => 'normal', + 'section' => 'basic', + 'priority' => 13, + 'help_text' => __( 'Select turnstile size', 'wp-user-frontend' ), + ], + [ + 'name' => 'turnstile_type', + 'title' => 'Turnstile type', + 'type' => 'radio', + 'options' => [ + 'managed' => __( 'Managed (recommended)', 'wp-user-frontend' ), + 'non_interactive' => __( 'Non-Interactive', 'wp-user-frontend' ), + 'invisible' => __( 'Invisible', 'wp-user-frontend' ), + ], + 'default' => 'managed', + 'section' => 'advanced', + 'priority' => 11, + 'help_text' => __( 'Select turnstile type', 'wp-user-frontend' ), + ], + ]; + + return $settings; + } + + /** + * Get the field props + * + * @since WPUF_SINCE + * + * @return array + */ + public function get_field_props() { + + $props = [ + 'input_type' => 'turnstile', + 'template' => $this->get_type(), + 'label' => '', + 'turnstile_type' => 'managed', + 'turnstile_theme' => 'light', + 'turnstile_size' => 'normal', + 'is_meta' => 'yes', + 'id' => 0, + 'wpuf_cond' => null, + ]; + + return $props; + } +}