--- a/woolentor-addons/classes/class.ajax_actions.php
+++ b/woolentor-addons/classes/class.ajax_actions.php
@@ -153,96 +153,161 @@
'error' => false,
];
+ // Verify nonce
if ( !isset( $_POST['woolentor_suggest_price_nonce_field'] ) || !wp_verify_nonce( $_POST['woolentor_suggest_price_nonce_field'], 'woolentor_suggest_price_nonce' ) ){
+ $response['error'] = true;
+ $response['message'] = esc_html__('Sorry, your nonce verification failed.','woolentor');
+ wp_send_json_error( $response );
+ }
+
+ // Get and validate form token (this links to server-stored recipient email)
+ $form_token = isset( $_POST['form_token'] ) ? sanitize_text_field( $_POST['form_token'] ) : '';
+ if ( empty( $form_token ) ) {
+ $response['error'] = true;
+ $response['message'] = esc_html__('Invalid form submission.','woolentor');
+ wp_send_json_error( $response );
+ }
+
+ // Retrieve recipient email from server-side storage (NOT from user input)
+ $stored_data = get_transient( 'woolentor_suggest_price_' . $form_token );
+ if ( false === $stored_data || !is_array( $stored_data ) ) {
+ $response['error'] = true;
+ $response['message'] = esc_html__('Form session expired. Please refresh and try again.','woolentor');
+ wp_send_json_error( $response );
+ }
+
+ // Get recipient from server-stored data (secure - not user controlled)
+ $allowed_recipient = isset( $stored_data['recipient_email'] ) ? sanitize_email( $stored_data['recipient_email'] ) : '';
+ $stored_product_id = isset( $stored_data['product_id'] ) ? absint( $stored_data['product_id'] ) : 0;
+
+ // Validate stored recipient
+ if ( empty( $allowed_recipient ) || ! is_email( $allowed_recipient ) ) {
+ // Fallback to admin email if stored email is invalid
+ $allowed_recipient = get_option( 'admin_email' );
+ }
+
+ // Get and validate product
+ $product_id = absint( $_POST['product_id'] ?? 0 );
+
+ // Verify product_id matches stored product_id (prevents manipulation)
+ if ( $product_id !== $stored_product_id ) {
+ $response['error'] = true;
+ $response['message'] = esc_html__('Invalid product.','woolentor');
+ wp_send_json_error( $response );
+ }
+
+ $product = wc_get_product( $product_id );
+ if ( ! $product ) {
+ $response['error'] = true;
+ $response['message'] = esc_html__('Invalid product.','woolentor');
+ wp_send_json_error( $response );
+ }
+ // Get user messages from widget settings (stored server-side)
+ $msg_success = isset( $stored_data['msg_success'] ) ? sanitize_text_field( $stored_data['msg_success'] ) : esc_html__('Thank you for contacting us.','woolentor');
+ $msg_error = isset( $stored_data['msg_error'] ) ? sanitize_text_field( $stored_data['msg_error'] ) : esc_html__('Something went wrong. Please try again.','woolentor');
+
+ // Validate sender's name
+ $name = isset( $_POST['wlname'] ) ? sanitize_text_field( $_POST['wlname'] ) : '';
+ if ( empty( $name ) ) {
$response['error'] = true;
- $response['message'] = esc_html__('Sorry, your nonce verification fail.','woolentor');
+ $response['message'] = esc_html__('Name is required.','woolentor');
+ wp_send_json_error( $response );
+ }
+ // Limit name length
+ if ( strlen( $name ) > 100 ) {
+ $name = substr( $name, 0, 100 );
+ }
+ // Validate sender's email (sanitize to prevent CRLF injection)
+ $email = isset( $_POST['wlemail'] ) ? sanitize_email( trim( $_POST['wlemail'] ) ) : '';
+ if ( empty( $email ) ) {
+ $response['error'] = true;
+ $response['message'] = esc_html__('Email is required.','woolentor');
wp_send_json_error( $response );
+ }
+ if ( ! is_email( $email ) ) {
+ $response['error'] = true;
+ $response['message'] = esc_html__('Invalid email address.','woolentor');
+ wp_send_json_error( $response );
+ }
- }else{
+ // Validate and sanitize message
+ $message = isset( $_POST['wlmessage'] ) ? wp_strip_all_tags( $_POST['wlmessage'] ) : '';
+ if ( empty( $message ) ) {
+ $response['error'] = true;
+ $response['message'] = esc_html__('Message is required.','woolentor');
+ wp_send_json_error( $response );
+ }
+ // Limit message length to prevent abuse
+ if ( strlen( $message ) > 1000 ) {
+ $message = substr( $message, 0, 1000 );
+ }
+
+ // Build subject from actual product name (not user input)
+ $subject = sprintf(
+ /* translators: %s: Product name */
+ esc_html__( 'Suggest Price For - %s', 'woolentor' ),
+ $product->get_name()
+ );
+
+ // Build email body with sender info
+ $email_body = sprintf(
+ /* translators: 1: Sender name, 2: Sender email, 3: Product name, 4: Message */
+ esc_html__( "Name: %1$snEmail: %2$snProduct: %3$snnMessage:n%4$s", 'woolentor' ),
+ $name,
+ $email,
+ $product->get_name(),
+ $message
+ );
+
+ // Set headers with Reply-To (sanitized email prevents header injection)
+ $headers = [
+ 'Reply-To: ' . $name . ' <' . $email . '>'
+ ];
+
+ // Send email to the server-stored recipient (NOT user-controlled)
+ $mail_sent_status = wp_mail( $allowed_recipient, $subject, $email_body, $headers );
- $sent_to = $_POST['send_to'];
- $send_to_mail = $_POST['send_to_mail'];
- $product_title = $_POST['product_title'];
- $msg_success = $_POST['msg_success'];
- $msg_error = $_POST['msg_error'];
- $name = $_POST['wlname'];
- $email = sanitize_email( trim( $_POST['wlemail'] ) );
- $message = wp_strip_all_tags($_POST['wlmessage']);
-
- if ( $email == '' ) {
- $response['error'] = true;
- $response['message'] = esc_html__('Email is required.','woolentor');
-
- wp_send_json_error( $response );
- }
- if ( ! is_email( $email ) ) {
- $response['error'] = true;
- $response['message'] = esc_html__('Invalid email address.','woolentor');
-
- wp_send_json_error( $response );
- }
-
- if( $sent_to == '' ){
- $response['error'] = true;
- $response['message'] = esc_html__('Recipient is required','woolentor');
-
- wp_send_json_error( $response );
- }
-
- if( !is_email( $send_to_mail ) ){
- $response['error'] = true;
- $response['message'] = esc_html__('Invalid recipient','woolentor');
-
- wp_send_json_error( $response );
- }
-
- $allowed_recipient = $send_to_mail;
- if ( $sent_to !== $allowed_recipient ) {
- $response['error'] = true;
- $response['message'] = esc_html__('Invalid recipient','woolentor');
- wp_send_json_error( $response );
- }
-
- if ( $message == '' ) {
- $response['error'] = true;
- $response['message'] = esc_html__('Message is required.','woolentor');
-
- wp_send_json_error( $response );
- }
- if ( strlen( $message ) > 1000 ) { // Add reasonable limit
- $message = substr( $message, 0, 1000 );
- }
-
- // Subject
- $product_id = absint( $_POST['product_id'] ); // Require actual product
- $product = wc_get_product( $product_id );
- if ( ! $product ) {
- wp_send_json_error( ['message' => 'Invalid product'] );
- }
- $subject = sprintf( 'Suggest Price For - %s', $product->get_name() );
-
- // Header
- $headers = [
- 'Reply-To: ' . $email
+ // Delete the old transient after use (one-time use token)
+ delete_transient( 'woolentor_suggest_price_' . $form_token );
+
+ if( $mail_sent_status ) {
+ $response['error'] = false;
+ $response['message'] = esc_html( $msg_success );
+
+ // Generate a new token for subsequent submissions (without page refresh)
+ $new_token = wp_generate_password( 32, false, false );
+
+ // Store the same data with new token
+ $new_transient_data = [
+ 'recipient_email' => $allowed_recipient,
+ 'product_id' => $product_id,
+ 'msg_success' => $msg_success,
+ 'msg_error' => $msg_error,
];
-
- // Here put your Validation and send mail
- $mail_sent_status = wp_mail( $allowed_recipient, $subject, $message, $headers );
-
- if( $mail_sent_status ) {
- $response['error'] = false;
- $response['message'] = esc_html( $msg_success );
- }
- else{
- $response['error'] = true;
- $response['message'] = esc_html( $msg_error );
- }
+ set_transient( 'woolentor_suggest_price_' . $new_token, $new_transient_data, HOUR_IN_SECONDS );
+
+ // Return new token to client for form update
+ $response['new_token'] = $new_token;
- wp_send_json_success( $response );
+ } else {
+ $response['error'] = true;
+ $response['message'] = esc_html( $msg_error );
+ // On error, regenerate token as well (old one is already deleted)
+ $new_token = wp_generate_password( 32, false, false );
+ $new_transient_data = [
+ 'recipient_email' => $allowed_recipient,
+ 'product_id' => $product_id,
+ 'msg_success' => $msg_success,
+ 'msg_error' => $msg_error,
+ ];
+ set_transient( 'woolentor_suggest_price_' . $new_token, $new_transient_data, HOUR_IN_SECONDS );
+ $response['new_token'] = $new_token;
}
+
+ wp_send_json_success( $response );
}
/**
--- a/woolentor-addons/includes/addons/wb_product_suggest_price.php
+++ b/woolentor-addons/includes/addons/wb_product_suggest_price.php
@@ -854,6 +854,24 @@
$product = wc_get_product( $post->ID );
}
+ // Generate a unique form token for this form instance
+ $form_token = wp_generate_password( 32, false, false );
+
+ // Get recipient email from widget settings (validated)
+ $recipient_email = ! empty( $settings['send_to_mail'] ) ? sanitize_email( $settings['send_to_mail'] ) : get_option( 'admin_email' );
+
+ // Store form data server-side (NOT exposed to client)
+ // This prevents attackers from manipulating the recipient
+ $transient_data = [
+ 'recipient_email' => $recipient_email,
+ 'product_id' => $product->get_id(),
+ 'msg_success' => ! empty( $settings['message_success'] ) ? $settings['message_success'] : __( 'Thank you for contacting us', 'woolentor' ),
+ 'msg_error' => ! empty( $settings['message_error'] ) ? $settings['message_error'] : __( 'Something went wrong. Please try again.', 'woolentor' ),
+ ];
+
+ // Store for 1 hour (form session timeout)
+ set_transient( 'woolentor_suggest_price_' . $form_token, $transient_data, HOUR_IN_SECONDS );
+
$this->add_render_attribute(
[
@@ -862,6 +880,7 @@
'name' => 'wlname',
'id' => 'wlname-' . esc_attr( $id ),
'placeholder' => $settings['name_placeholder_text'],
+ 'required' => 'required',
],
'user_email' => [
@@ -869,14 +888,17 @@
'name' => 'wlemail',
'id' => 'wlemail-' . esc_attr( $id ),
'placeholder' => $settings['email_placeholder_text'],
+ 'required' => 'required',
],
'user_message' => [
'name' => 'wlmessage',
'id' => 'wlmessage-' . esc_attr( $id ),
- 'rows' => '4',
- 'cols' => '50',
+ 'rows' => '4',
+ 'cols' => '50',
'placeholder' => $settings['message_placeholder_text'],
+ 'required' => 'required',
+ 'maxlength' => '1000',
],
'user_submit' => [
@@ -885,7 +907,7 @@
'id' => 'wlsubmit-' . esc_attr( $id ),
'value' => $settings['submit_button_txt'],
],
-
+
]
);
@@ -894,7 +916,7 @@
<p class="wlsendmessage"> </p>
<button id="wlopenform-<?php echo esc_attr( $id ); ?>" class="wlsugget-button wlopen"><?php echo esc_html( $settings['open_button_text'] ); ?></button>
<button id="wlcloseform-<?php echo esc_attr( $id ); ?>" class="wlsugget-button wlclose" style="display: none;"><?php echo esc_html( $settings['close_button_text'] ); ?></button>
- <form id="wlsuggestform-<?php echo esc_attr( $id ); ?>" action="<?php echo admin_url('admin-ajax.php'); ?>" method="post">
+ <form id="wlsuggestform-<?php echo esc_attr( $id ); ?>" action="<?php echo esc_url( admin_url('admin-ajax.php') ); ?>" method="post">
<div class="wl-suggest-form-input">
<input <?php echo $this->get_render_attribute_string( 'user_name' ); ?> >
</div>
@@ -907,7 +929,9 @@
<div class="wl-suggest-form-input">
<input <?php echo $this->get_render_attribute_string( 'user_submit' ); ?> >
</div>
- <input type="hidden" name="send_to_mail" value="<?php echo esc_attr($settings['send_to_mail']); ?>">
+ <!-- Security: Only pass the token, NOT the recipient email -->
+ <input type="hidden" name="form_token" value="<?php echo esc_attr( $form_token ); ?>">
+ <input type="hidden" name="product_id" value="<?php echo esc_attr( $product->get_id() ); ?>">
<input type="hidden" name="action" value="woolentor_suggest_price_action">
<?php wp_nonce_field( 'woolentor_suggest_price_nonce', 'woolentor_suggest_price_nonce_field' ); ?>
</form>
@@ -917,20 +941,15 @@
;jQuery(document).ready(function($) {
"use strict";
- // Declaire Variable
+ // Declare Variable
var openFormBtn = '#wlopenform-<?php echo esc_js($id); ?>',
closeFormBtn = '#wlcloseform-<?php echo esc_js($id); ?>',
tergetForm = 'form#wlsuggestform-<?php echo esc_js($id); ?>',
formSubmitBtn = '#wlsubmit-<?php echo esc_js($id); ?>',
- sendTo = '<?php echo esc_js($settings['send_to_mail']); ?>',
- messageSuccess = '<?php echo esc_js($settings['message_success']); ?>',
- messageError = '<?php echo esc_js($settings['message_error']); ?>',
- productID = '<?php echo esc_js($product->get_id()); ?>',
- productTitle = '<?php echo esc_js($product->get_title()); ?>',
submitText = $(formSubmitBtn).val(),
loadingText = '<?php echo esc_js($settings['submit_button_loading_txt']); ?>',
formSelector = $(tergetForm);
-
+
// Open Button
$( openFormBtn ).on('click', function(){
$(this).hide();
@@ -948,11 +967,11 @@
// Submit Using Ajax
$(tergetForm).on('submit', function(e) {
e.preventDefault();
-
+
$.ajax({
url: formSelector.attr('action'),
type: 'POST',
- data: `send_to=${sendTo}&product_id=${productID}&product_title=${productTitle}&msg_success=${messageSuccess}&msg_error=${messageError}&${formSelector.serialize()}`,
+ data: formSelector.serialize(),
beforeSend: function (response) {
$(tergetForm).siblings('.wlsendmessage').hide();
@@ -968,6 +987,18 @@
success: function (response) {
$(tergetForm).siblings('.wlsendmessage').show().html(response?.data?.message);
+
+ // Update form token for subsequent submissions (without page refresh)
+ if (response?.data?.new_token) {
+ $(tergetForm).find('input[name="form_token"]').val(response.data.new_token);
+ }
+
+ // Clear form fields after successful submission
+ if (response?.success && !response?.data?.error) {
+ $(tergetForm).find('input[name="wlname"]').val('');
+ $(tergetForm).find('input[name="wlemail"]').val('');
+ $(tergetForm).find('textarea[name="wlmessage"]').val('');
+ }
},
});
--- a/woolentor-addons/includes/admin-panel/includes/classes/Admin.php
+++ b/woolentor-addons/includes/admin-panel/includes/classes/Admin.php
@@ -33,6 +33,9 @@
if ( !class_exists( __NAMESPACE__ . 'AdminDiagnostic_Data' ) ) {
require_once __DIR__ . '/Admin/Diagnostic_Data.php';
}
+ if ( !class_exists( __NAMESPACE__ . 'AdminDeactivation_Feedback' ) ) {
+ require_once __DIR__ . '/Admin/Deactivation_Feedback.php';
+ }
}
/**
@@ -43,6 +46,7 @@
public function init() {
(new AdminMenu())->init();
(new AdminDashboard_Widget())->init();
+ (new AdminDeactivation_Feedback())->init();
}
/**
--- a/woolentor-addons/includes/admin-panel/includes/classes/Admin/Deactivation_Feedback.php
+++ b/woolentor-addons/includes/admin-panel/includes/classes/Admin/Deactivation_Feedback.php
@@ -0,0 +1,384 @@
+<?php
+namespace WoolentorOptionsAdmin;
+
+// If this file is accessed directly, exit.
+if ( ! defined( 'ABSPATH' ) ) {
+ exit;
+}
+
+class Deactivation_Feedback {
+
+ public $PROJECT_NAME = 'ShopLentor';
+ public $PROJECT_TYPE = 'wordpress-plugin';
+ public $PROJECT_VERSION = WOOLENTOR_VERSION;
+ public $PROJECT_SLUG = 'woolentor-addons'; // Without plugin main file.
+ public $PROJECT_PRO_SLUG = 'woolentor-addons-pro/woolentor_addons_pro.php';
+ public $PROJECT_PRO_ACTIVE;
+ public $PROJECT_PRO_INSTALL;
+ public $PROJECT_PRO_VERSION;
+ public $DATA_CENTER = 'https://exit-feedback.hasthemes.com/w/46df05fb-d342-4d1f-975b-b0f5bb316367';
+ public $WEBHOOK_SECRET = '5e257224ca07abad5299d028349b655099a5a8d88d3b526f713010aa64b6945a';
+
+ public function init() {
+ $this->PROJECT_PRO_ACTIVE = $this->is_pro_plugin_active();
+ $this->PROJECT_PRO_INSTALL = $this->is_pro_plugin_installed();
+ $this->PROJECT_PRO_VERSION = $this->get_pro_version();
+
+ add_action( 'admin_footer', [ $this, 'deactivation_feedback' ] );
+ add_action( 'wp_ajax_woolentor_deactivation_feedback', [ $this, 'handle_feedback' ] );
+ }
+
+ public function deactivation_feedback() {
+ // Only show on plugins page
+ $screen = get_current_screen();
+ if ($screen->id !== 'plugins') {
+ return;
+ }
+
+ $this->deactivation_form_html();
+ }
+
+ /**
+ * Handle AJAX feedback submission
+ */
+ public function handle_feedback() {
+ // Add nonce verification
+ if ( !check_ajax_referer('woolentor_deactivation_nonce', 'nonce', false) ) {
+ wp_send_json_error('Invalid nonce');
+ return;
+ }
+
+ if(!current_user_can( 'administrator' )) {
+ wp_send_json_error('Permission denied');
+ return;
+ }
+
+ // Sanitize and prepare data
+ $reason = sanitize_text_field($_POST['reason']);
+ $message = sanitize_textarea_field($_POST['message']);
+
+ // Prepare data for Pabbly
+ $data = array_merge(
+ [
+ 'deactivate_reason' => $reason,
+ 'deactivate_message' => $message,
+ ],
+ $this->get_data(),
+ );
+
+ $body = wp_json_encode( $data );
+
+ $site_url = wp_parse_url( home_url(), PHP_URL_HOST );
+ $headers = [
+ 'user-agent' => $this->PROJECT_NAME . '/' . md5( $site_url ) . ';',
+ 'Content-Type' => 'application/json',
+ ];
+
+ $signature = $this->generate_signature( $body );
+ if ( ! empty( $signature ) ) {
+ $headers['X-Webhook-Signature'] = $signature;
+ }
+
+ // Send data to Pabbly
+ $response = wp_remote_post($this->DATA_CENTER, [
+ 'method' => 'POST',
+ 'timeout' => 30,
+ 'redirection' => 5,
+ 'httpversion' => '1.0',
+ 'blocking' => false,
+ 'sslverify' => false,
+ 'headers' => $headers,
+ 'body' => $body,
+ 'cookies' => []
+ ]);
+
+ // Check for errors
+ if (!is_wp_error($response)) {
+ wp_send_json_success('Feedback submitted successfully');
+ } else {
+ wp_send_json_error('Failed to submit feedback: ' . $response->get_error_message());
+ }
+ }
+
+ public function get_data() {
+
+ // Get plugin specific information
+ $project = [
+ 'name' => $this->PROJECT_NAME,
+ 'type' => $this->PROJECT_TYPE,
+ 'version' => $this->PROJECT_VERSION,
+ 'pro_active' => $this->PROJECT_PRO_ACTIVE,
+ 'pro_installed' => $this->PROJECT_PRO_INSTALL,
+ 'pro_version' => $this->PROJECT_PRO_VERSION,
+ ];
+
+ $site_title = get_bloginfo( 'name' );
+ $site_url = wp_parse_url( home_url(), PHP_URL_HOST );
+ $admin_email = get_option( 'admin_email' );
+
+ $admin_first_name = '';
+ $admin_last_name = '';
+ $admin_display_name = '';
+
+ $users = get_users( array(
+ 'role' => 'administrator',
+ 'orderby' => 'ID',
+ 'order' => 'ASC',
+ 'number' => 1,
+ 'paged' => 1,
+ ) );
+
+ $admin_user = ( is_array ( $users ) && isset ( $users[0] ) && is_object ( $users[0] ) ) ? $users[0] : null;
+
+ if ( ! empty( $admin_user ) ) {
+ $admin_first_name = ( isset( $admin_user->first_name ) ? $admin_user->first_name : '' );
+ $admin_last_name = ( isset( $admin_user->last_name ) ? $admin_user->last_name : '' );
+ $admin_display_name = ( isset( $admin_user->display_name ) ? $admin_user->display_name : '' );
+ }
+
+ $ip_address = $this->get_ip_address();
+
+ $data = [
+ 'project' => $project,
+ 'site_title' => $site_title,
+ 'site_address' => $site_url,
+ 'site_url' => $site_url,
+ 'admin_email' => $admin_email,
+ 'admin_first_name' => $admin_first_name,
+ 'admin_last_name' => $admin_last_name,
+ 'admin_display_name' => $admin_display_name,
+ 'server_info' => $this->get_server_info(),
+ 'wordpress_info' => $this->get_wordpress_info(),
+ 'plugins_count' => $this->get_plugins_count(),
+ 'ip_address' => $ip_address,
+ 'country_name' => $this->get_country_from_ip( $ip_address ),
+ 'plugin_list' => $this->get_active_plugins(),
+ ];
+
+ return $data;
+ }
+
+ /**
+ * Get server info.
+ */
+ private function get_server_info() {
+ global $wpdb;
+
+ $software = ( isset ( $_SERVER['SERVER_SOFTWARE'] ) && !empty ( $_SERVER['SERVER_SOFTWARE'] ) ) ? $_SERVER['SERVER_SOFTWARE'] : '';
+ $php_version = function_exists ( 'phpversion' ) ? phpversion () : '';
+ $mysql_version = method_exists ( $wpdb, 'db_version' ) ? $wpdb->db_version () : '';
+
+ $server_info = array(
+ 'software' => $software,
+ 'php_version' => $php_version,
+ 'mysql_version' => $mysql_version,
+ );
+
+ return $server_info;
+ }
+
+ /**
+ * Get wordpress info.
+ */
+ private function get_wordpress_info() {
+ $wordpress_info = [];
+
+ $debug_mode = ( defined ( 'WP_DEBUG' ) && WP_DEBUG ) ? 'yes' : 'no';
+ $locale = get_locale();
+ $version = get_bloginfo( 'version' );
+ $theme_slug = get_stylesheet();
+
+ $wordpress_info = [
+ 'debug_mode' => $debug_mode,
+ 'locale' => $locale,
+ 'version' => $version,
+ 'theme_slug' => $theme_slug,
+ ];
+
+ $theme = wp_get_theme( $wordpress_info['theme_slug'] );
+
+ if ( is_object( $theme ) && ! empty( $theme ) && method_exists( $theme, 'get' ) ) {
+ $theme_name = $theme->get( 'Name' );
+ $theme_version = $theme->get( 'Version' );
+ $theme_uri = $theme->get( 'ThemeURI' );
+ $theme_author = $theme->get( 'Author' );
+
+ $wordpress_info = array_merge( $wordpress_info, [
+ 'theme_name' => $theme_name,
+ 'theme_version' => $theme_version,
+ 'theme_uri' => $theme_uri,
+ 'theme_author' => $theme_author,
+ ] );
+ }
+
+ return $wordpress_info;
+ }
+
+ /**
+ * Get users count.
+ */
+ private function get_users_count() {
+ $users_count = [];
+
+ $users_count_data = count_users();
+
+ $total_users = isset ( $users_count_data['total_users'] ) ? $users_count_data['total_users'] : 0;
+ $avail_roles = isset ( $users_count_data['avail_roles'] ) ? $users_count_data['avail_roles'] : [];
+
+ $users_count['total'] = $total_users;
+
+ if ( is_array( $avail_roles ) && ! empty( $avail_roles ) ) {
+ foreach ( $avail_roles as $role => $count ) {
+ $users_count[ $role ] = $count;
+ }
+ }
+
+ return $users_count;
+ }
+
+ /**
+ * Get plugins count.
+ */
+ private function get_plugins_count() {
+ $total_plugins_count = 0;
+ $active_plugins_count = 0;
+ $inactive_plugins_count = 0;
+
+ $plugins = get_plugins();
+ $plugins = is_array ( $plugins ) ? $plugins : [];
+
+ $active_plugins = get_option( 'active_plugins', [] );
+ $active_plugins = is_array ( $active_plugins ) ? $active_plugins : [];
+
+ if ( ! empty( $plugins ) ) {
+ foreach ( $plugins as $key => $data ) {
+ if ( in_array( $key, $active_plugins, true ) ) {
+ $active_plugins_count++;
+ } else {
+ $inactive_plugins_count++;
+ }
+
+ $total_plugins_count++;
+ }
+ }
+
+ $plugins_count = [
+ 'total' => $total_plugins_count,
+ 'active' => $active_plugins_count,
+ 'inactive' => $inactive_plugins_count,
+ ];
+
+ return $plugins_count;
+ }
+
+ /**
+ * Get active plugins.
+ */
+ private function get_active_plugins() {
+ $active_plugins = get_option('active_plugins');
+ $all_plugins = get_plugins();
+ $active_plugin_string = '';
+ foreach($all_plugins as $plugin_path => $plugin) {
+ if ( ! in_array($plugin_path, $active_plugins) ) {
+ continue;
+ }
+ $active_plugin_string .= sprintf(
+ "%s (v%s) - %s | ",
+ $plugin['Name'],
+ $plugin['Version'],
+ 'Active'
+ );
+ }
+ $active_plugin_string = rtrim($active_plugin_string, ' | ');
+ return $active_plugin_string;
+ }
+
+ /**
+ * Get IP Address
+ */
+ private function get_ip_address() {
+ $response = wp_remote_get( 'https://icanhazip.com/' );
+
+ if ( is_wp_error( $response ) ) {
+ return '';
+ }
+
+ $ip_address = wp_remote_retrieve_body( $response );
+ $ip_address = trim( $ip_address );
+
+ if ( ! filter_var( $ip_address, FILTER_VALIDATE_IP ) ) {
+ return '';
+ }
+
+ return $ip_address;
+ }
+
+ /**
+ * Get Country Form ID Address
+ */
+ private function get_country_from_ip( $ip_address ) {
+ $api_url = 'http://ip-api.com/json/' . $ip_address;
+
+ // Fetch data from the API
+ $response = wp_remote_get( $api_url );
+
+ if ( is_wp_error( $response ) ) {
+ return 'Error';
+ }
+
+ // Decode the JSON response
+ $data = json_decode( wp_remote_retrieve_body($response) );
+
+ if ($data && $data->status === 'success') {
+ return $data->country;
+ } else {
+ return 'Unknown';
+ }
+ }
+
+ /**
+ * Generate HMAC-SHA256 signature for webhook payload.
+ */
+ private function generate_signature( $payload ) {
+ if ( empty( $this->WEBHOOK_SECRET ) ) {
+ return '';
+ }
+ return 'sha256=' . hash_hmac( 'sha256', $payload, $this->WEBHOOK_SECRET );
+ }
+
+ /**
+ * Is pro active.
+ */
+ private function is_pro_plugin_active() {
+ $result = is_plugin_active( $this->PROJECT_PRO_SLUG );
+ $result = ( true === $result ) ? 'yes' : 'no';
+ return $result;
+ }
+
+ /**
+ * Is pro installed.
+ */
+ private function is_pro_plugin_installed() {
+ $plugins = get_plugins();
+ $result = isset ( $plugins[$this->PROJECT_PRO_SLUG] ) ? 'yes' : 'no';
+ return $result;
+ }
+
+ /**
+ * Get pro version.
+ */
+ private function get_pro_version() {
+ $plugins = get_plugins();
+ $data = ( isset ( $plugins[$this->PROJECT_PRO_SLUG] ) && is_array ( $plugins[$this->PROJECT_PRO_SLUG] ) ) ? $plugins[$this->PROJECT_PRO_SLUG] : [];
+ $version = isset ( $data['Version'] ) ? sanitize_text_field ( $data['Version'] ) : '';
+ return $version;
+ }
+
+ /**
+ * Deactivation form html.
+ */
+ public function deactivation_form_html() {
+ require_once( WOOLENTOROPT_INCLUDES . '/templates/deactive-feedback.php' );
+ }
+
+}
--- a/woolentor-addons/includes/admin-panel/includes/classes/Admin/Options_field.php
+++ b/woolentor-addons/includes/admin-panel/includes/classes/Admin/Options_field.php
@@ -113,7 +113,7 @@
'header' => false,
'column' => 1,
'title' => __( 'Style Tabs', 'woolentor' ),
- 'desc' => __( 'Style Settings for Universal Product Layput', 'woolentor' ),
+ 'desc' => __( 'Style Settings for Universal Product Layout', 'woolentor' ),
],
],
--- a/woolentor-addons/includes/admin-panel/includes/templates/deactive-feedback.php
+++ b/woolentor-addons/includes/admin-panel/includes/templates/deactive-feedback.php
@@ -0,0 +1,674 @@
+<?php
+ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
+
+ $ajaxurl = admin_url('admin-ajax.php');
+ $nonce = wp_create_nonce('woolentor_deactivation_nonce');
+?>
+
+<div id="woolentor-deactivation-dialog" class="wl-deactivate-overlay" style="display: none;">
+ <div class="wl-deactivate-modal">
+ <!-- Header -->
+ <div class="wl-deactivate-header">
+ <button type="button" class="wl-close-btn woolentor-close-dialog" aria-label="Close">
+ <svg viewBox="0 0 24 24" fill="none">
+ <path d="M18 6L6 18M6 6l12 12" stroke-linecap="round" stroke-linejoin="round"/>
+ </svg>
+ </button>
+ <div class="wl-header-content">
+ <div class="wl-header-icon">
+ <img src="<?php echo esc_url( WOOLENTOROPT_ASSETS . '/images/logo.png' ); ?>" alt="<?php esc_attr_e('ShopLentor Logo', 'woolentor-addons'); ?>">
+ </div>
+ <div class="wl-header-text">
+ <h3><?php esc_html_e("We're Sorry to See You Go!", 'woolentor-addons') ?></h3>
+ <p><?php esc_html_e('Your feedback helps us improve ShopLentor for everyone.', 'woolentor-addons') ?></p>
+ </div>
+ </div>
+ </div>
+
+ <!-- Body -->
+ <div class="wl-deactivate-body">
+ <p class="wl-body-title"><?php esc_html_e('Please share why you're deactivating ShopLentor:', 'woolentor-addons') ?></p>
+
+ <form id="woolentor-deactivation-feedback-form">
+ <div class="wl-reasons-list">
+ <!-- Reason 1: Temporary -->
+ <div class="wl-reason-item">
+ <input type="radio" name="reason" id="reason_temporary" data-id="" value="<?php esc_attr_e("It's a temporary deactivation", 'woolentor-addons') ?>">
+ <label for="reason_temporary" class="wl-reason-label">
+ <span class="wl-reason-radio"></span>
+ <span class="wl-reason-icon">
+ <svg viewBox="0 0 24 24">
+ <circle cx="12" cy="12" r="10"/>
+ <polyline points="12 6 12 12 16 14"/>
+ </svg>
+ </span>
+ <span class="wl-reason-text">
+ <span><?php esc_html_e("It's a temporary deactivation", 'woolentor-addons') ?></span>
+ </span>
+ </label>
+ </div>
+
+ <!-- Reason 2: No longer need -->
+ <div class="wl-reason-item">
+ <input type="radio" name="reason" id="reason_no_need" data-id="" value="<?php esc_attr_e('I no longer need the plugin', 'woolentor-addons') ?>">
+ <label for="reason_no_need" class="wl-reason-label">
+ <span class="wl-reason-radio"></span>
+ <span class="wl-reason-icon">
+ <svg viewBox="0 0 24 24">
+ <path d="M18 6L6 18M6 6l12 12"/>
+ </svg>
+ </span>
+ <span class="wl-reason-text">
+ <span><?php esc_html_e('I no longer need the plugin', 'woolentor-addons') ?></span>
+ </span>
+ </label>
+ </div>
+
+ <!-- Reason 3: Found better -->
+ <div class="wl-reason-item">
+ <input type="radio" name="reason" id="reason_better" data-id="found_better" value="<?php esc_attr_e('I found a better plugin', 'woolentor-addons') ?>">
+ <label for="reason_better" class="wl-reason-label">
+ <span class="wl-reason-radio"></span>
+ <span class="wl-reason-icon">
+ <svg viewBox="0 0 24 24">
+ <circle cx="11" cy="11" r="8"/>
+ <path d="M21 21l-4.35-4.35"/>
+ </svg>
+ </span>
+ <span class="wl-reason-text">
+ <span><?php esc_html_e('I found a better plugin', 'woolentor-addons') ?></span>
+ </span>
+ </label>
+ </div>
+ <div id="woolentor-found_better-reason-text" class="wl-additional-input woolentor-deactivation-reason-input">
+ <textarea name="found_better_reason" placeholder="<?php esc_attr_e('Which plugin are you switching to? We'd love to know...', 'woolentor-addons') ?>"></textarea>
+ </div>
+
+ <!-- Reason 4: Not working -->
+ <div class="wl-reason-item">
+ <input type="radio" name="reason" id="reason_not_working" data-id="stopped_working" value="<?php esc_attr_e('The plugin suddenly stopped working', 'woolentor-addons') ?>">
+ <label for="reason_not_working" class="wl-reason-label">
+ <span class="wl-reason-radio"></span>
+ <span class="wl-reason-icon">
+ <svg viewBox="0 0 24 24">
+ <path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/>
+ <line x1="12" y1="9" x2="12" y2="13"/>
+ <line x1="12" y1="17" x2="12.01" y2="17"/>
+ </svg>
+ </span>
+ <span class="wl-reason-text">
+ <span><?php esc_html_e('The plugin suddenly stopped working', 'woolentor-addons') ?></span>
+ </span>
+ </label>
+ </div>
+ <div id="woolentor-stopped_working-reason-text" class="wl-additional-input woolentor-deactivation-reason-input">
+ <textarea name="stopped_working_reason" placeholder="<?php esc_attr_e('Please describe the issue you're experiencing...', 'woolentor-addons') ?>"></textarea>
+ </div>
+
+ <!-- Reason 5: Bug -->
+ <div class="wl-reason-item">
+ <input type="radio" name="reason" id="reason_bug" data-id="found_bug" value="<?php esc_attr_e('I encountered an error or bug', 'woolentor-addons') ?>">
+ <label for="reason_bug" class="wl-reason-label">
+ <span class="wl-reason-radio"></span>
+ <span class="wl-reason-icon">
+ <svg viewBox="0 0 24 24">
+ <path d="M14.7 6.3a1 1 0 000 1.4l1.6 1.6a1 1 0 001.4 0l3.77-3.77a6 6 0 01-7.94 7.94l-6.91 6.91a2.12 2.12 0 01-3-3l6.91-6.91a6 6 0 017.94-7.94l-3.76 3.76z"/>
+ </svg>
+ </span>
+ <span class="wl-reason-text">
+ <span><?php esc_html_e('I encountered an error or bug', 'woolentor-addons') ?></span>
+ </span>
+ </label>
+ </div>
+ <div id="woolentor-found_bug-reason-text" class="wl-additional-input woolentor-deactivation-reason-input">
+ <textarea name="found_bug_reason" placeholder="<?php esc_attr_e('Please describe the error/bug. This will help us fix it...', 'woolentor-addons') ?>"></textarea>
+ </div>
+
+ <!-- Reason 6: Other -->
+ <div class="wl-reason-item">
+ <input type="radio" name="reason" id="reason_other" data-id="other" value="<?php esc_attr_e('Other', 'woolentor-addons') ?>">
+ <label for="reason_other" class="wl-reason-label">
+ <span class="wl-reason-radio"></span>
+ <span class="wl-reason-icon">
+ <svg viewBox="0 0 24 24">
+ <path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/>
+ </svg>
+ </span>
+ <span class="wl-reason-text">
+ <span><?php esc_html_e('Other', 'woolentor-addons') ?></span>
+ </span>
+ </label>
+ </div>
+ <div id="woolentor-other-reason-text" class="wl-additional-input woolentor-deactivation-reason-input">
+ <textarea name="other_reason" placeholder="<?php esc_attr_e('Please share the reason...', 'woolentor-addons') ?>"></textarea>
+ </div>
+ </div>
+
+ <!-- Footer -->
+ <div class="wl-deactivate-footer">
+ <a href="#" class="wl-btn wl-btn-skip woolentor-skip-feedback"><?php esc_html_e('Skip & Deactivate', 'woolentor-addons') ?></a>
+ <button type="submit" class="wl-btn wl-btn-submit">
+ <span><?php esc_html_e('Submit & Deactivate', 'woolentor-addons') ?></span>
+ </button>
+ </div>
+ </form>
+ </div>
+ </div>
+</div>
+
+<script>
+ ;jQuery(document).ready(function($) {
+ let pluginToDeactivate = '';
+
+ function closeDialog() {
+ $('#woolentor-deactivation-dialog').animate({
+ opacity: 0
+ }, 'slow', function() {
+ $(this).css('display', 'none');
+ });
+ pluginToDeactivate = '';
+ }
+
+ // Open dialog when deactivate is clicked
+ $('[data-slug="<?php echo esc_attr($this->PROJECT_SLUG); ?>"] .deactivate a').on('click', function(e) {
+ e.preventDefault();
+ pluginToDeactivate = $(this).attr('href');
+ $('#woolentor-deactivation-dialog').css({'display': 'flex', 'opacity': '1'});
+ });
+
+ // Close dialog on X button click
+ $('.woolentor-close-dialog').on('click', closeDialog);
+
+ // Close dialog on overlay click
+ $('#woolentor-deactivation-dialog').on('click', function(e) {
+ if (e.target === this) {
+ closeDialog();
+ }
+ });
+
+ // Prevent close when clicking modal content
+ $('.wl-deactivate-modal').on('click', function(e) {
+ e.stopPropagation();
+ });
+
+ // Handle radio button change - show/hide textarea
+ $('input[name="reason"]').on('change', function() {
+ $('.woolentor-deactivation-reason-input').removeClass('active').hide();
+
+ const id = $(this).data('id');
+ if (['other', 'found_better', 'stopped_working', 'found_bug'].includes(id)) {
+ $(`#woolentor-${id}-reason-text`).addClass('active').show();
+ $(`#woolentor-${id}-reason-text textarea`).focus();
+ }
+ });
+
+ // Handle form submission
+ $('#woolentor-deactivation-feedback-form').on('submit', function(e) {
+ e.preventDefault();
+
+ const $submitButton = $(this).find('button[type="submit"]');
+ const $buttonText = $submitButton.find('span');
+ const originalText = $buttonText.text();
+
+ $buttonText.text('<?php esc_html_e('Submitting...', 'woolentor-addons') ?>');
+ $submitButton.prop('disabled', true);
+
+ const reason = $('input[name="reason"]:checked').val() || 'No reason selected';
+ const message = $('.woolentor-deactivation-reason-input.active textarea').val() || '';
+
+ const data = {
+ action: 'woolentor_deactivation_feedback',
+ reason: reason,
+ message: message,
+ nonce: '<?php echo esc_js($nonce); ?>'
+ };
+
+ $.post('<?php echo esc_url_raw($ajaxurl); ?>', data)
+ .done(function(response) {
+ if (response.success) {
+ window.location.href = pluginToDeactivate;
+ } else {
+ console.error('Feedback submission failed:', response.data);
+ $buttonText.text(originalText);
+ $submitButton.prop('disabled', false);
+ }
+ })
+ .fail(function(xhr) {
+ console.error('Feedback submission failed:', xhr.responseText);
+ $buttonText.text(originalText);
+ $submitButton.prop('disabled', false);
+ });
+ });
+
+ // Skip feedback and deactivate
+ $('.woolentor-skip-feedback').on('click', function(e) {
+ e.preventDefault();
+ window.location.href = pluginToDeactivate;
+ });
+ });
+</script>
+
+<style>
+ /* Overlay */
+ #woolentor-deactivation-dialog.wl-deactivate-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.6);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 999999;
+ animation: wlFadeIn 0.3s ease;
+ }
+
+ @keyframes wlFadeIn {
+ from { opacity: 0; }
+ to { opacity: 1; }
+ }
+
+ @keyframes wlFadeOut {
+ from { opacity: 1; }
+ to { opacity: 0; }
+ }
+
+ @keyframes wlSlideUp {
+ from {
+ opacity: 0;
+ transform: translateY(30px) scale(0.95);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+ }
+
+ @keyframes wlSlideDown {
+ from {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+ to {
+ opacity: 0;
+ transform: translateY(30px) scale(0.95);
+ }
+ }
+
+ /* Closing animation classes */
+ #woolentor-deactivation-dialog.wl-deactivate-overlay.wl-closing {
+ animation: wlFadeOut 0.25s ease forwards;
+ }
+
+ #woolentor-deactivation-dialog.wl-closing .wl-deactivate-modal {
+ animation: wlSlideDown 0.25s ease forwards;
+ }
+
+ /* Modal Container */
+ .wl-deactivate-modal {
+ background: #ffffff;
+ border-radius: 8px;
+ width: 480px;
+ max-width: 95%;
+ overflow: hidden;
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
+ animation: wlSlideUp 0.4s ease;
+ }
+
+ /* Header */
+ .wl-deactivate-header {
+ background: linear-gradient(135deg, #E8573F 0%, #F05C4E 50%, #F26A52 100%);
+ padding: 20px 28px;
+ position: relative;
+ overflow: hidden;
+ }
+
+ .wl-deactivate-header::before {
+ content: '';
+ position: absolute;
+ top: -50%;
+ right: -20%;
+ width: 200px;
+ height: 200px;
+ background: rgba(255, 255, 255, 0.1);
+ border-radius: 50%;
+ }
+
+ .wl-deactivate-header::after {
+ content: '';
+ position: absolute;
+ bottom: -30%;
+ left: 10%;
+ width: 120px;
+ height: 120px;
+ background: rgba(255, 255, 255, 0.08);
+ border-radius: 50%;
+ }
+
+ .wl-header-content {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ }
+
+ .wl-header-icon {
+ width: 40px;
+ height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .wl-header-icon img{
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+
+ .wl-header-text h3 {
+ color: #ffffff;
+ font-size: 16px;
+ font-weight: 600;
+ margin: 0 0 2px 0;
+ }
+
+ .wl-header-text p {
+ color: rgba(255, 255, 255, 0.85);
+ font-size: 12px;
+ font-weight: 400;
+ margin: 0;
+ }
+
+ /* Close Button */
+ .wl-close-btn {
+ position: absolute;
+ top: 16px;
+ right: 16px;
+ width: 28px;
+ height: 28px;
+ background: rgba(255, 255, 255, 0.15);
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.2s ease;
+ z-index: 2;
+ padding: 0;
+ }
+
+ .wl-close-btn:hover {
+ background: rgba(255, 255, 255, 0.25);
+ transform: rotate(90deg);
+ }
+
+ .wl-close-btn svg {
+ width: 16px;
+ height: 16px;
+ stroke: #ffffff;
+ stroke-width: 2;
+ }
+
+ /* Body Content */
+ .wl-body-title {
+ font-size: 14px;
+ color: #374151;
+ font-weight: 500;
+ margin: 20px 0 0 0;
+ padding: 0 25px;
+ }
+
+ /* Reason Options */
+ .wl-reasons-list {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ padding: 20px 25px;
+ }
+
+ .wl-reason-item {
+ position: relative;
+ }
+
+ .wl-reason-item input[type="radio"] {
+ position: absolute;
+ opacity: 0;
+ width: 0;
+ height: 0;
+ }
+
+ .wl-reason-label {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 10px 14px;
+ background: #ffffff;
+ border: 1px solid #e5e5e5;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: all 0.25s ease;
+ }
+
+ .wl-reason-label:hover {
+ border-color: #F05C4E;
+ background: #FEF5F4;
+ }
+
+ .wl-reason-item input[type="radio"]:checked + .wl-reason-label {
+ border-color: #F05C4E;
+ background: #FEF5F4;
+ box-shadow: 0 2px 8px rgba(240, 92, 78, 0.15);
+ }
+
+ .wl-reason-radio {
+ width: 14px;
+ height: 14px;
+ min-width: 14px;
+ border: 2px solid #d1d5db;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.25s ease;
+ }
+
+ .wl-reason-item input[type="radio"]:checked + .wl-reason-label .wl-reason-radio {
+ border-color: #F05C4E;
+ background: #F05C4E;
+ }
+
+ .wl-reason-radio::after {
+ content: '';
+ width: 6px;
+ height: 6px;
+ background: #ffffff;
+ border-radius: 50%;
+ transform: scale(0);
+ transition: transform 0.2s ease;
+ }
+
+ .wl-reason-item input[type="radio"]:checked + .wl-reason-label .wl-reason-radio::after {
+ transform: scale(1);
+ }
+
+ .wl-reason-icon {
+ width: 30px;
+ height: 30px;
+ min-width: 30px;
+ background: #FDEAE8;
+ border-radius: 6px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.25s ease;
+ }
+
+ .wl-reason-item input[type="radio"]:checked + .wl-reason-label .wl-reason-icon {
+ background: #F05C4E;
+ }
+
+ .wl-reason-icon svg {
+ width: 15px;
+ height: 15px;
+ stroke: #F05C4E;
+ stroke-width: 2;
+ fill: none;
+ transition: all 0.25s ease;
+ }
+
+ .wl-reason-item input[type="radio"]:checked + .wl-reason-label .wl-reason-icon svg {
+ stroke: #ffffff;
+ }
+
+ .wl-reason-text {
+ flex: 1;
+ }
+
+ .wl-reason-text span {
+ font-size: 13px;
+ font-weight: 500;
+ color: #374151;
+ display: block;
+ line-height: 1.3;
+ }
+
+ /* Additional Input Field */
+ .wl-additional-input.woolentor-deactivation-reason-input {
+ margin-top: 6px;
+ margin-bottom: 6px;
+ display: none;
+ animation: wlSlideDown 0.3s ease;
+ }
+
+ .wl-additional-input.woolentor-deactivation-reason-input.active {
+ display: block;
+ }
+
+ @keyframes wlSlideDown {
+ from {
+ opacity: 0;
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+
+ .wl-additional-input textarea {
+ width: 100%;
+ min-height: 70px;
+ padding: 12px 14px;
+ border: 1px solid #e5e5e5;
+ border-radius: 8px;
+ font-size: 13px;
+ font-family: inherit;
+ resize: vertical;
+ transition: all 0.25s ease;
+ background: #ffffff;
+ box-sizing: border-box;
+ }
+
+ .wl-additional-input textarea:focus {
+ outline: none;
+ border-color: #F05C4E;
+ background: #ffffff;
+ box-shadow: 0 0 0 3px rgba(240, 92, 78, 0.1);
+ }
+
+ .wl-additional-input textarea::placeholder {
+ color: #94a3b8;
+ }
+
+ /* Footer */
+ .wl-deactivate-footer {
+ padding: 16px 28px 20px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ border-top: 1px solid #e5e5e5;
+ margin-top: 10px;
+ }
+
+ .wl-btn {
+ padding: 10px 20px;
+ border-radius: 6px;
+ font-size: 13px;
+ cursor: pointer;
+ transition: all 0.25s ease;
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ text-decoration: none;
+ }
+
+ .wl-btn-skip {
+ background: transparent;
+ color: #6B7280;
+ padding: 10px 0;
+ }
+
+ .wl-btn-skip:hover {
+ color: #F05C4E;
+ }
+
+ .wl-btn-submit {
+ background: #F05C4E;
+ border: 1px solid #F05C4E;
+ color: #ffffff;
+ }
+
+ .wl-btn-submit:hover {
+ background: #E8573F;
+ border-color: #E8573F;
+ color: #ffffff;
+ }
+
+ .wl-btn-submit:active {
+ background: #D94D35;
+ }
+
+ .wl-btn-submit:disabled {
+ opacity: 0.7;
+ cursor: not-allowed;
+ }
+
+ .wl-btn-submit svg {
+ width: 14px;
+ height: 14px;
+ stroke: currentColor;
+ stroke-width: 2;
+ fill: none;
+ }
+
+ /* Responsive */
+ @media (max-width: 600px) {
+ .wl-deactivate-modal {
+ margin: 16px;
+ }
+
+ .wl-deactivate-header {
+ padding: 16px 20px;
+ }
+
+ .wl-deactivate-body {
+ padding: 16px 20px;
+ }
+
+ .wl-deactivate-footer {
+ padding: 14px 20px 18px;
+ flex-direction: column;
+ }
+
+ .wl-btn {
+ width: 100%;
+ justify-content: center;
+ }
+ }
+</style>
+
No newline at end of file
--- a/woolentor-addons/includes/base.php
+++ b/woolentor-addons/includes/base.php
@@ -367,6 +367,7 @@
*/
public function plugin_deactivation_hook() {
delete_metadata( 'user', 0, 'hastech-notice-id-wlagency-bundle-promo-banner', null, true );
+ update_option( 'woolentor_plugin_permalinks_flushed', 'no' );
}
/**
--- a/woolentor-addons/includes/modules/currency-switcher/includes/widgets/wl_currency_switcher.php
+++ b/woolentor-addons/includes/modules/currency-switcher/includes/widgets/wl_currency_switcher.php
@@ -57,7 +57,7 @@
$this->add_control(
'show_flags',
[
- 'label' => __( 'Show Currency flags ?', 'woolentor' ),
+ 'label' => __( 'Show Currency flags?', 'woolentor' ),
'type' => Controls_Manager::SWITCHER,
'label_on' => __( 'Yes', 'woolentor' ),
'label_off' => __( 'No', 'woolentor' ),
@@ -86,7 +86,7 @@
$this->add_control(
'show_flags_pro',
[
- 'label' => __( 'Show Currency flags ?', 'woolentor' ) .' <i class="eicon-pro-icon"></i>',
+ 'label' => __( 'Show Currency flags?', 'woolentor' ) .' <i class="eicon-pro-icon"></i>',
'type' => Controls_Manager::SWITCHER,
'label_on' => __( 'Yes', 'woolentor' ),
'label_off' => __( 'No', 'woolentor' ),
--- a/woolentor-addons/includes/modules/flash-sale/flash-sale.php
+++ b/woolentor-addons/includes/modules/flash-sale/flash-sale.php
@@ -243,7 +243,7 @@
$apply_only_for_registered_customers = !empty($deal['apply_discount_only_for_registered_customers']) ? $deal['apply_discount_only_for_registered_customers'] : '';
$allowed_user_roles = !empty($deal['allowed_user_roles']) ? explode(',', $deal['allowed_user_roles']) : array();
- if( $apply_only_for_registered_customers ){
+ if( $apply_only_for_registered_customers == 'on' ){
if( is_user_logged_in() && !$allowed_user_roles ){
$validity = true;
}
--- a/woolentor-addons/woolentor-blocks/build/blocks/suggest-price/index.php
+++ b/woolentor-addons/woolentor-blocks/build/blocks/suggest-price/index.php
@@ -35,23 +35,45 @@
if ( ! isset( $_POST['woolentor_suggest_price_nonce_field'] ) || ! wp_verify_nonce( $_POST['woolentor_suggest_price_nonce_field'], 'woolentor_suggest_price_action' ) ){
echo '<p class="wlsendmessage">'.esc_html__('Sorry, your nonce verification fail.','woolentor').'</p>';
}else{
- $name = $_POST['wlname'];
- $email = $_POST['wlemail'];
- $message = $_POST['wlmessage'];
-
- //php mailer variables
- $sentto = $settings['sendToMail'];
- $subject = esc_html__("Suggest Price For - ".$product->get_title(), 'woolentor');
- $headers = esc_html__('From: ','woolentor'). esc_html( $email ) . "rn" . esc_html__('Reply-To: ', 'woolentor') . esc_html( $email ) . "rn";
+ $name = sanitize_text_field( $_POST['wlname'] );
+ $email = sanitize_email( trim( $_POST['wlemail'] ) );
+ $message = wp_strip_all_tags( $_POST['wlmessage'] );
- //Here put your Validation and send mail
- $sent = wp_mail( $sentto, $subject, wp_strip_all_tags($message), $headers );
+ // Validate email (sanitize_email strips CRLF, is_email confirms format)
+ if ( ! is_email( $email ) ) {
+ echo '<p class="wlsendmessage">'.esc_html__('Invalid email address.','woolentor').'</p>';
+ } else {
+ // Limit message length to prevent abuse
+ if ( strlen( $message ) > 1000 ) {
+ $message = substr( $message, 0, 1000 );
+ }
- if( $sent ) {
- echo '<p class="wlsendmessage">'.esc_html( $settings['messageSuccess'] ).'</p>';
- }
- else{
- echo '<p class="wlsendmessage">'.esc_html($settings['messageError']).'</p>';
+ // Validate recipient
+ $sentto = ! empty( $settings['sendToMail'] ) ? sanitize_em