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
zcmds6^;=Y5zhxM@MLLECshOc;NI|+3qxI^4M82gI9RCjuO{9y
zG&Df2y^g-8zPg$?+|?OuVdZLR4fb_*L*>!XB&2=aEZ~mTo{W~(w)QTP%*U;r%#8L{
zlFWKS>QHqzIcqz6C4UcVZGR0NxW6M@%!*lB3QxjU90lNP?P+Ix$5cid2{uiz|
z>i(a{5N5`IHSu(mWY$;LVw7|Bux1nnL%~pHDLh6A4=Wq-SMmz~?u?2gne9A1-NYdf
zA0HpEj{w-!!xq9PCME`f@V77QVbL2$p{!{u@Ky8UgpPck{G&bz%Gm
z)56l#%Ttn>8I@=JH@LO0{r{l5ApSjl6cLbrG7vs66!Nd;|3uBV+9)!uQQep!|4b9|?|GsKgZzgvRPZ0ptzA$=d!QJ7
zw9P(3RRe%{rT84JVw`Rd4UM`-PF}L*#sJN>UQZI|6=DMuB&Nf};4{
zKx{kSyjoE*;@k6ssiTUcsaGSo?=K|3_NI7%pBz|p9!0v)4SS>6x}lSirOC=aVSSbw
zDbo*YJ1@72QY9Etckw`|k89)xj4#+8*Iybu8ah_C{}?jp@H^e^6O2w@B*sP$3ytWp
z!0ou%FRO7~?YKbf9NuYsnk?Pi+#LK_4QFeD4-hRhBT9T1SEY*3a}Wr`R+_d(a>43x
zx;b<=Y*ngCB!}--Dqr*Na5Jy{*S9x7(3KbTbGwz_S|erAL6au&op{ESX^q6+U-(mA
zOC{LB^lJ7H1JKnW=AQV`G_aGXxGtTC`0gUylm0T3<}b_3$9Y=Wc6@*7
zC-_3tx)t}di{eVJ&I-fRr=o!0Km1V1dkSG^dyWz%B+O&$7S)Bks!
zk=kj{O$^#111AZt51w)pYAwkl#Zr@e8QN2Ld&4$`%mz;1G1JF!atfWC{N!4ivbdH#
zp;TZ)*uKRe`YK;4)1;?Zg~msZ%S>9&p(d3-{Lz-e5NAI>MIG-hBVpaT2d30FsD@hs
zPW^NKUc5pN;H16>?=eqS+WkaIj+fty9_7PG@r3i>X%ey)$*QH#xxnz@U1zu4qZ_z>
z$-u*A^*FWWrI?4CCw6qg=zDzy`YwC?>VoZg^gJWv9s#5HGsWS$;JrOR(jj#f3Zn#7
z=QIzGCEe8A=9^H%TcQ?7s=js397k7GDV}D3|Es-;9*z!r2cejrck<{$?aX7}!-~2t
zIeqEpKB&&Mc+6V9Ri|(1XWhr{EKgc`oW6PaP3{1AY-+oqPD#4sBwBXPwi54Hsupx^
zv|)JflO~ghrWNFi39=E>1Bb=v%8xio1{9V?cLCM>{F>#N_how7(uto%v+rBk*r+@s
ztKq5uAGe+CYX@<{V82Y`zgDWXn5fbOwia5EH$JsQ-
z!>{#B*xLQiRo?APJVzY29!oVNhq(#=w6#ez@8kt+7Dj}kZQ4JKG>wiGr1HGB!~F{!~YI}8YO*^
z<9x+jCZ~4s;O0=Ovu`N)Jd&8fWh?lybyYcEDk!4x_Xi`FC*xm;%Uh2-jPUUAzKy|-
z+qA(qm$Ba8j|NapZ0iOS^DG!eo?TO!WW&aVB*ZnVOa<7lfA!x_K-L{
zI_+9lsaJN~AgV)>R->Hz`6DBHE|G%gdTHA*-VBS89q;1(^-ezRQ@wISHh6zra(nCL
zFlqr>{j9RUnka8vaWI70O)zE(*e2lOQG`G0qUVfdi_kKTV^kW{Dwz6hkpo?imYQD~
z8ymwdD0mI6%t2l=FKv!;GqEKi&>hdtrZq=sUE7%211>)dFoYPBC@m^%xVG%EI}#Tf
zR+)#%cPDSZEHIRC-mQDNR;#iD!Bf4keNVbanmplsSXaI~`$j`fva}=N2Ll&4c{HBs
z#AleS6O5fLBP2s(1NVb&&71h-+Cvu`EVuADxw!bZ8G_CxJ#G&h=i|;pKji1TZU1n|NnJjn59|H5;6Nv9AW-mW$;c3Gd-QbmvJ1sGUB+
z==a%0lX#?mn;81KAOt5@gS}kb>uLSRC7+rvFV_UHu!&-fiIz)!8WT%SCv_vQ_{D
zRi!VES0UVb6=?^Rou+vB_-`L&F{(7Bu6wtSu7Gwd@MEEQV|bRP36-h`0j8jEtH|er
zidOy%4;zXBIz(LH#e%KSTsI)n?Ink)z#ewNdbTPb=T&Tk%2v7B@Gx~c0-dCWPoE|Pxz1uZroaCs$Ug`5Wvz+zt-ln&q%ka$bTl0)nT7K-#q%;?UnPAl7=8aSlUY>t^>;;x~pgFF`SHPf>3{I(1}<`jCBx{|&k14E0`_
z#*iL4>0-HR(X1%@6yH{+JZwMCUH=2d<^G@b0~Pw?r(gVhGv%q#mB6zVPeaDuN3SAs
zF&XM8Ye5jfdi%clSm{VCM*d&BbLH8*7)(hsK7vb99i}D&gy)SF;+roaeq(x4NRRFB
zxPGsM*`GC+eN3so!hZ3py%U4{X9*1hD4Cm$a{HZYBEQdy=}8$0tKsUhxi;10Pw~+3
z?cdy@QB|CWaIcG_Wyf)jbFoCt_(Q$G<$e&uiU-^QScNCEt&tlZNSX9=d`fN`mY49s
zf|s#hyL0h*;ZAjsc*7B%s(Dn_DzX=oqa#{}9_Wu?4UF(qQpYw6_yO}V7>Qwp&jL=~
z_p*|l<0o!yXbYB(Yjb$%66vUv8fTW!Y_|Dz3KzaGm`t`%1T2W)jU&n2RnE
zE2fm>iQ)`=&Wk#4MA7dP3;2bv*KHjgC-v%!=d{F1C6uv!X2ol|=^NIXz7h!*MF`uTr`1^^jXZUzdohR=rr2G?%RDvO+7+E90G&|M9GP43HNm
zxSn3G&F^aC^Vvpdl*)}oN)5kfmBuvL|hpH@MsRaic|d0VN|H&>gz6|!PnWzS={EoYJ4p2W5kJfemrocX8eV$M{DS6J=*U=RR;Dq+`*24y7Lo$6ejDso
zC9fX%7G1yC%#y*U&8z}81X(CldQJAK^)+v_-_Axv%a_1Xh!&?FL3tWJ)_(eE_}I0@
zE!T>FmRVmE#WkiXVLr<}l7+v;R_6I+RbaIUyI#(2Y63M)ux_WmLm2m0twyu?ClTz$
z$wT*H8OGv*j3Yks)&~z?8A;N@gsqj-?@cSQgUKHaHz^P4ed5eqV0|1xr#%=N$2*95>AsSHD6>n|3^oi4)7Et%K=BK!%%o!FMa;K0A;Ozu`2@-MVLGqO_{5)XFb#G?jVS`Rc;O
z#%EC7th8dH#}%NWlN5e4>BxQkl$6lMcTHsQV?U)#?1*RF@f;IRy8xPAyKk%@VOq#HKj8xzgzG`BQ1v+;r*A%
zG$`ugIN{n8p$Q-!z2()`-s$)*uM
z@%UO_u~{?5_(8fFMO;!rzx|{^WSl+yN~wy!aG(TR7d{2A5HU{nQ4fUOT=pU8GCp
zdw4}%lC`Qj5b}IhQSfX$>4+)Q+a_%3u^YrW+gB+6$+PJwU=60h+CJ|}z+F0@NHkpc
zorYgw;}|+_^s3+ujk(2rUcoo6IF(GS_oXuy1;&$eLwPz51mCM1AT;#xk)95vOpf(O
zS(5K-K8dRGf6S~2yicS#EYrC;_{Jm+Q5~1!GgCMx8tRqJwVJHCNA_J-RQI~}0;Sze
zXN_LLUkpN8t~Zz9Ggf7|=DJ5}?fZ>@Ul0gS5K^!^)DW#s@N18p8YZv=Vt9Cd^4cR1
zWArhl@;S0gCEh%1Fa1%xvN1=9QL#oS7#`_=v(U0ld#0x%I}my{kcke;GSeolTGo|V?pDx;^Jm&A=2_HjFfqf?Ti=rK@3-ZFfYE!8k|BdOKh?^
z;ya#nj807|If7~2tICld8rM6qk%N<-R!CS;?S6zD@jMI;L4A?{8cgLs^1Q=a7&k7T
zQm2+hrF`1ib;DeIzsN2S_6~#%q-llfkiSkvo<(DPiHp-33o^6`mv+VqZ0wNqLt2SF
z-ktJ#Y)LwzG|5WcpJ_8;e8qoVBbK)BHDX=dY)~jZbSzJM&%ct`>v=w^CHWUvL4fo_ntxV_O6s;4K6+f`jPt
z)7Uq=;o`8C=(Qi7HR`N&0Gs>kA0Z8c={=EzsRN*Z(e7MZYisH*3>NRvLWwTvtF<>%
zm1fd=EA6eQ9g-rudX|+g{A_m;ea%klxy&Df?)+37w|};`M(qZ*HbeOjXB~xR@+DWs5YGh9JkM-bM&Mlksk20T9VBt
z6*-Jko%e^XTQS@fRX7U~d;@rBp|qqVWc%9lVT!OBCjQH-lMQuWV_2*AVG4>)L)}VK
z=VXCBv%uR5;)xeOV`5{=|M>0X+J>Xk@4E#}etd!K#)o9E$-YxM!}n+X7>H76r&S#b
zZ!v-wBNlu@3otW`L>dru#8d>BI>MwocHTBN#r9kqBJ-s{USuKW^n!NYX4e}j>p>ry
z!TOc<0NQ0^dMxOCMMxS@>tcdM7-C33*xd||zPUVhMF-OJ476V^ap$&re(1d0g4iq$
zMS5Vz2{?49kj+F^ncFND4kR)2n0BkxXs
zjMUjre@noBN6?P46pS8FHU3;$I@tB`es8*D#O(1#&!V&-C$cgfWsp!E(!;!|oUUjz
zsG2KpA8w@#I)mHE$jE+5CPj6T#$`Sv&+j$4xirQUKpTSX;VTa1^V8uc@@22W93&vDG
z@KiGaI<0>-IB!c><`#5@JO=+Nc;RMaOHR{Gy3Y5g_!)v#*sr24M_4!K)h}lo4w%gh
z770e=<@L-AioSWQwfuqna;pj#3Dp;)K7Xy74rm(@|bI%;D}
z)#E#q5hLbR{Jv(>f_HF0r%}h_P%hv5x4OS-y#eL2H?~w4Ke27X7#(%xa@hD;rD7te
z#_!Yy(T|2@VSXHe$)2(k(QD#!O^8c4pZRee=oZIvH72r}flywhqlcBAZ!EHAKWKFp
zUN|I+{;4wwBkn;Wkxm_Bf|Z*2QpiQe%7qz%0b)g>l32+DEY>>GViu~=g_A+fY?M7v
z=BQ63m>C~>NI!A%Rajw*G|WbkqOrPFBs0oip$?X!iKbTjY7Pw4i%cg#*3)oNk(8
zcE7J@Bc}gTRw*Ndh3ea$07Ov+t=FC-KqQTkuCfgoLnwmNkJ7@MH6!5E@#|dcRpMJG
zjUQ8jj+o;r)vpHm!J(bk+u6deH~fHg`e~L4t7$Vf6n>=5ei`vLr(KcQ(h}4GJGnki
z%ID2H`L!i(8CDc<->NB;Q?*cMuRRtRGML1a@;=kLU_4)XRgfZ{u2gd^LF&fN$mKKm
z5RIU2dr5i#17rFqBCKOdc#EV3_bK~eF+@1??_bs=kC5A6t5#Qk*V!@pZeyL_8Mb7}};ypC&+r8&OFE
zUi*kqxc~~kf{~=I7?#B1JxX*e`e9+=dhW3(F(_WY*8K)8|4b;{@3!)!tCJA`Is~w0#mX=R#%;+(
z5tdhz7?((&g>gjaQ#PiJP-!lwYKSX)AFnu%On>7N537x&xpL1sc61zRJzo~tCSwH9
z0^A6Iq9u}P>ok6>C1GiOZQY`cGcmfq@zrw0U$6LX5I!ZF+c7cOA8=$HKpRW?y$C0k
z+~M&!y6IZMC8%5C^UPt1`D`BR8damHlIB=D(yG{Ek8F0&;b?Ql4h-6Q+8hb}%T65r
zU0Wtcrpxn;-n=46W;=}N{P)u!gxBxW1DN;on77JgcfS6I!@r^oB);^diRgK#VT%fj
z2qCUd4hv@6nyLe@k?djQnj`dbslwSQS-NGMyq}fnF+$7hNzubEO5_}TR)WQ$k|sB6
zVfkRCy64goe~rTS_NI!kgIgFU@$Ub2xndTVsHVzNkY=RM2?;5uYxv*WNfCt##A^L{
z^G&nWc4TZmLXp!%EVQOpVw71s>5-JFNA)lY_zm&5ZS4`@%4Zs8nN$J$=l`1W3k~^-
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
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
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;
+ }
+}