HEX
Server: nginx/1.24.0
System: Linux DGT-WORDPRESS-VM-SERVER 6.14.0-1017-azure #17~24.04.1-Ubuntu SMP Mon Dec 1 20:10:50 UTC 2025 x86_64
User: ubuntu (1000)
PHP: 8.4.12
Disabled: NONE
Upload Files
File: /mnt/data/dreamssalon-wp/wp-content/plugins/dreamsalon-core/inc/init.php
<?php /**
 * Exclude all WooCommerce products from WordPress search results
 */
add_action( 'pre_get_posts', function( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_search() ) {
        // Exclude WooCommerce products
        $query->set( 'post_type', array( 'post' ) );
    }
});

function dreamsalon_hash_email( $email ) {
    return wp_hash( strtolower( trim( $email ) ) );
}

// Header style
function add_header_style_meta_box()
{
    add_meta_box(
        'header_style_meta_box',
        'Header Style',
        'render_header_style_meta_box',
        'page',
        'side',
        'default'
    );
}
add_action('add_meta_boxes', 'add_header_style_meta_box');

function render_header_style_meta_box($post)
{
    wp_nonce_field('header_style_meta_action', 'header_style_meta_nonce');
    $current_style = get_post_meta($post->ID, '_header_style', true);
?>
    <select name="header_style" id="header_style">
        <option value="default" <?php selected($current_style, 'default'); ?>><?php  echo  esc_html__('Default Header','dreamsalon-core'); ?></option>
        <option value="style1" <?php selected($current_style, 'style1'); ?>><?php  echo  esc_html__('Header Style 1','dreamsalon-core'); ?></option>
        <option value="style2" <?php selected($current_style, 'style2'); ?>><?php  echo  esc_html__('Header Style 2','dreamsalon-core'); ?></option>
        <option value="style3" <?php selected($current_style, 'style3'); ?>><?php  echo  esc_html__('Header Style 3','dreamsalon-core'); ?></option>
    </select>
    <?php
}

function save_header_style_meta($post_id)
{
    if (!isset($_POST['header_style_meta_nonce']) || 
        !wp_verify_nonce($_POST['header_style_meta_nonce'], 'header_style_meta_action')) {
        return $post_id;
    }
    
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (!current_user_can('edit_post', $post_id)) return;

    if (isset($_POST['header_style'])) {
        update_post_meta($post_id, '_header_style', sanitize_text_field($_POST['header_style']));
    }
}
add_action('save_post', 'save_header_style_meta');

function add_header_style_to_quick_edit($column_name, $post_type)
{
    if ($column_name === 'header_style' && $post_type === 'page') {
        wp_nonce_field('header_style_quick_edit', 'header_style_nonce');
    ?>
        <fieldset class="inline-edit-col-right">
            <div class="inline-edit-col">
                <label>
                    <span class="title"><?php  echo esc_html__('Header Style','dreamsalon-core'); ?></span>
                    <select name="_header_style">
                        <option value="default"><?php echo esc_html__('Default','dreamsalon-core'); ?></option>
                        <option value="style1"><?php echo esc_html__('Style 1','dreamsalon-core'); ?></option>
                        <option value="style2"><?php  echo esc_html__('Style 2','dreamsalon-core'); ?></option>
                        <option value="style3"><?php  echo esc_html__('Style 3','dreamsalon-core'); ?></option>
                    </select>
                </label>
            </div>
        </fieldset>
    <?php
    }
}
add_action('quick_edit_custom_box', 'add_header_style_to_quick_edit', 10, 2);

function save_quick_edit_header_style($post_id)
{
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (!isset($_POST['header_style_nonce']) || !wp_verify_nonce($_POST['header_style_nonce'], 'header_style_quick_edit')) return;
    if (!current_user_can('edit_post', $post_id)) return;

    if (isset($_POST['_header_style'])) {
        update_post_meta($post_id, '_header_style', sanitize_text_field($_POST['_header_style']));
    }
}
add_action('save_post', 'save_quick_edit_header_style');

function add_header_style_column($columns)
{
    $columns['header_style'] = 'Header Style';
    return $columns;
}
add_filter('manage_pages_columns', 'add_header_style_column');

function display_header_style_column($column, $post_id)
{
    if ($column === 'header_style') {
        $header_style = get_post_meta($post_id, '_header_style', true) ?: 'default';
        echo '<span id="header_style-' . $post_id . '" data-value="' . esc_attr($header_style) . '">' . ucfirst($header_style) . '</span>';
    }
}
add_action('manage_pages_custom_column', 'display_header_style_column', 10, 2);

// 1. Add Meta Box for Footer Style
function add_footer_style_meta_box()
{
    add_meta_box(
        'footer_style_meta_box',
        'Footer Style',
        'render_footer_style_meta_box',
        'page',
        'side',
        'default'
    );
}
add_action('add_meta_boxes', 'add_footer_style_meta_box');

function render_footer_style_meta_box($post)
{
    $current_style = get_post_meta($post->ID, '_footer_style', true);
    ?>
    <select name="footer_style" id="footer_style">
        <option value="default" <?php selected($current_style, 'default'); ?>><?php  echo esc_html__('Default Footer','dreamsalon-core'); ?></option>
        <option value="style1" <?php selected($current_style, 'style1'); ?>><?php  echo esc_html__('Footer Style 1','dreamsalon-core'); ?></option>
        <option value="style2" <?php selected($current_style, 'style2'); ?>><?php  echo esc_html__('Footer Style 2','dreamsalon-core'); ?></option>
        <option value="style3" <?php selected($current_style, 'style3'); ?>><?php  echo esc_html__('Footer Style 3','dreamsalon-core'); ?></option>

    </select>
    <?php
}

// 2. Save Footer Style
function save_footer_style_meta($post_id)
{
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (!current_user_can('edit_post', $post_id)) return;

    if (isset($_POST['footer_style'])) {
        update_post_meta($post_id, '_footer_style', sanitize_text_field($_POST['footer_style']));
    }
}
add_action('save_post', 'save_footer_style_meta');

// 3. Add Footer Style to Quick Edit
function add_footer_style_to_quick_edit($column_name, $post_type)
{
    if ($column_name === 'footer_style' && $post_type === 'page') {
        wp_nonce_field('footer_style_quick_edit', 'footer_style_nonce');
    ?>
        <fieldset class="inline-edit-col-right">
            <div class="inline-edit-col">
                <label>
                    <span class="title"><?php  echo esc_html__('Footer Style','dreamsalon-core'); ?></span>
                    <select name="_footer_style">
                        <option value="default"><?php  echo esc_html__('Default','dreamsalon-core'); ?></option>
                        <option value="style1"><?php  echo esc_html__('Style 1','dreamsalon-core'); ?></option>
                        <option value="style2"><?php  echo esc_html__('Style 2','dreamsalon-core'); ?></option>
                        <option value="style3"><?php  echo esc_html__('Style 3','dreamsalon-core'); ?></option>
                    </select>
                </label>
            </div>
        </fieldset>
    <?php
    }
}
add_action('quick_edit_custom_box', 'add_footer_style_to_quick_edit', 10, 2);

// 4. Save Quick Edit Footer Style
function save_quick_edit_footer_style($post_id)
{
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (!isset($_POST['footer_style_nonce']) || !wp_verify_nonce($_POST['footer_style_nonce'], 'footer_style_quick_edit')) return;
    if (!current_user_can('edit_post', $post_id)) return;

    if (isset($_POST['_footer_style'])) {
        update_post_meta($post_id, '_footer_style', sanitize_text_field($_POST['_footer_style']));
    }
}
add_action('save_post', 'save_quick_edit_footer_style');

// 5. Add Footer Style Column to Admin
function add_footer_style_column($columns)
{
    $columns['footer_style'] = 'Footer Style';
    return $columns;
}
add_filter('manage_pages_columns', 'add_footer_style_column');

// 6. Display Footer Style Column
function display_footer_style_column($column, $post_id)
{
    if ($column === 'footer_style') {
        $footer_style = get_post_meta($post_id, '_footer_style', true) ?: 'default';
        echo '<span id="footer_style-' . $post_id . '" data-value="' . esc_attr($footer_style) . '">' . ucfirst($footer_style) . '</span>';
    }
}
add_action('manage_pages_custom_column', 'display_footer_style_column', 10, 2);

/*custom code */

// Add "Hide Breadcrumb" option to Page Attributes
function custom_add_hide_breadcrumb_meta_box() {
    add_meta_box(
        'hide_breadcrumb_meta_box',           // ID
        'Breadcrumb Options',                 // Title
        'custom_hide_breadcrumb_meta_box_cb', // Callback
        'page',                               // Screen (post type)
        'side',                               // Context (same as Page Attributes)
        'default'                             // Priority
    );
}
add_action('add_meta_boxes', 'custom_add_hide_breadcrumb_meta_box');

// Meta box HTML
function custom_hide_breadcrumb_meta_box_cb($post) {
    $value = get_post_meta($post->ID, '_hide_breadcrumb', true);
    wp_nonce_field('hide_breadcrumb_nonce_action', 'hide_breadcrumb_nonce');
    ?>
    <p>
        <label>
            <input type="checkbox" name="hide_breadcrumb" value="1" <?php checked($value, '1'); ?> />
            <?php esc_html_e('Hide Breadcrumb on this Page', 'textdomain'); ?>
        </label>
    </p>
    <?php
}

// Save meta box data
function custom_save_hide_breadcrumb_meta_box($post_id) {
    if (!isset($_POST['hide_breadcrumb_nonce']) || 
        !wp_verify_nonce($_POST['hide_breadcrumb_nonce'], 'hide_breadcrumb_nonce_action')) {
        return;
    }

    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;

    if (isset($_POST['hide_breadcrumb'])) {
        update_post_meta($post_id, '_hide_breadcrumb', '1');
    } else {
        delete_post_meta($post_id, '_hide_breadcrumb');
    }
}
add_action('save_post_page', 'custom_save_hide_breadcrumb_meta_box');

/**
 * Complete SVG support solution
 */
function complete_svg_support() {
    
    // Allow SVG upload
    function cc_mime_types($mimes) {
        $mimes['svg'] = 'image/svg+xml';
        return $mimes;
    }
    add_filter('upload_mimes', 'cc_mime_types');
    
    // Fix MIME type detection
    function fix_svg_mime_type($data = null, $file = null, $filename = null, $mimes = null) {
        $ext = $data['ext'] ?? '';
        $type = $data['type'] ?? '';
        
        if ($ext === 'svg' || $type === 'image/svg+xml') {
            $data['ext'] = 'svg';
            $data['type'] = 'image/svg+xml';
        }
        
        return $data;
    }
    add_filter('wp_check_filetype_and_ext', 'fix_svg_mime_type', 75, 4);
    
    // Fix admin display
    function svg_admin_display_fix() {
        echo '<style>
            .media-icon img[src$=".svg"],
            .wp-admin .thumbnail img[src$=".svg"],
            .wp-admin .attachment img[src$=".svg"] {
                width: 100% !important;
                height: auto !important;
                max-width: 150px !important;
            }
        </style>';
    }
    add_action('admin_head', 'svg_admin_display_fix');
    
    // Generate dimensions for SVG
    function svg_dimensions($metadata, $attachment_id) {
        $mime_type = get_post_mime_type($attachment_id);
        
        if ($mime_type === 'image/svg+xml') {
            $file_path = get_attached_file($attachment_id);
            $svg_content = file_get_contents($file_path);
            
            // Extract width and height from SVG
            preg_match('/width="([^"]+)"/', $svg_content, $width_matches);
            preg_match('/height="([^"]+)"/', $svg_content, $height_matches);
            
            $width = isset($width_matches[1]) ? intval($width_matches[1]) : 100;
            $height = isset($height_matches[1]) ? intval($height_matches[1]) : 100;
            
            $metadata['width'] = $width;
            $metadata['height'] = $height;
            $metadata['sizes'] = [];
        }
        
        return $metadata;
    }
    add_filter('wp_generate_attachment_metadata', 'svg_dimensions', 10, 2);
}

complete_svg_support();





//OTP_Function




// Enqueue OTP scripts
function dreamsalon_enqueue_otp_scripts() {
    if (is_page_template('registerform.php')) {
        wp_enqueue_script('jquery');
    }
}
add_action('wp_enqueue_scripts', 'dreamsalon_enqueue_otp_scripts');

// OTP Functions using transients

 



function mark_email_verified($email) {
    // Store verification status in options table
    $verification_data = array(
        'email' => $email,
        'verified' => true,
        'verified_at' => time()
    );
    update_option('dreamsalon_verified_' . dreamsalon_hash_email($email), $verification_data, 30 * MINUTE_IN_SECONDS); // Keep for 30 minutes
}

function is_email_verified($email) {
    $verification_data = get_option('dreamsalon_verified_' . dreamsalon_hash_email($email));
    return !empty($verification_data['verified']);
}

// AJAX handler for verifying OTP
function verify_otp_ajax() {
    // Check nonce
    if (!check_ajax_referer('otp_nonce', 'security', false)) {
        wp_send_json_error('Security verification failed.');
    }
    
    $email = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';
    $otp = isset($_POST['otp']) ? sanitize_text_field($_POST['otp']) : '';
    
    if (empty($email) || empty($otp)) {
        wp_send_json_error('Email and OTP are required.');
    }
    
    if (verify_otp($email, $otp)) {
        // Mark email as verified
        mark_email_verified($email);
        // Clear OTP data after successful verification
        clear_otp_data($email);
        wp_send_json_success('OTP verified successfully! You can now complete your registration.');
    } else {
        wp_send_json_error('Invalid or expired OTP. Please try again.');
    }
}
add_action('wp_ajax_nopriv_verify_otp', 'verify_otp_ajax');
add_action('wp_ajax_verify_otp', 'verify_otp_ajax');

// Registration form handler




// OTP Login Functions
function dreamsalon_generate_login_otp($user_id) {
    // Generate 6-digit OTP
    $otp = str_pad(rand(0, 999999), 6, '0', STR_PAD_LEFT);
    $otp_expiry = time() + (15 * 60); // 15 minutes
    
    // Store OTP in user meta
    update_user_meta($user_id, 'login_otp', $otp);
    update_user_meta($user_id, 'login_otp_expiry', $otp_expiry);
    update_user_meta($user_id, 'login_otp_attempts', 0);
    
    return $otp;
}

function dreamsalon_send_login_otp_email($user_id, $otp) {
    $user = get_userdata($user_id);
    $email = $user->user_email;
    
    // Get theme options
    $options = get_option('dreamsalon_theme_options');
    
    // Get email subject from Redux or use default
    $subject = !empty($options['otp_login_subject_from_email']) 
        ? $options['otp_login_subject_from_email'] 
        : 'Your Login Confirmation Code';
    
    // Get email content from Redux or use default template
    $email_content = !empty($options['login_otp_content']) 
        ? $options['login_otp_content'] 
        : "
        <p>Enter the code below and verify the user email</p>              
        <p>{otp}</p>
        <p>This code will expire in {expiration_time} minutes.</p>
        <p>Use the above code to proceed with Login</p>";
    
    // Get OTP expiration time from Redux
   // $otp_expiry_minutes = !empty($options['otp_expiration_time']) ? intval($options['otp_expiration_time']) : 15;
    $otp_expiry_minutes =  dreamsalon_fl_framework_getoptions('otp_expiration_time');
    // Replace template tags with actual values
    $message = str_replace(
        array(
            '{otp}',
            '{user_email}',
            '{expiration_time}',
            '{user_name}'
        ),
        array(
            $otp,
            $email,
            $otp_expiry_minutes,
            $user->display_name
        ),
        $email_content
    );
    
    // Get email logo from Redux
    $email_logo_url = '';
    if (!empty($options['otp_login_email_logo']['url'])) {
        $email_logo_url = $options['otp_login_email_logo']['url'];
    } elseif (function_exists('dreamsalon_fl_framework_getoptions')) {
        $main_logo = dreamsalon_fl_framework_getoptions('frontend_logo');
        if (!empty($main_logo['url'])) {
            $email_logo_url = $main_logo['url'];
        }
    }
    
    // Wrap message in email template
    $full_message = "
    <html>
    <head>
        <title>" . esc_html($subject) . "</title>
        <style>
            body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
            .container { max-width: 600px; margin: 0 auto; padding: 20px; }
            .header { text-align: center; margin-bottom: 30px; }
            .logo { max-width: 200px; height: auto; }
            .otp-code { 
                font-size: 32px; 
                font-weight: bold; 
                color: #007cba; 
                text-align: center; 
                margin: 30px 0; 
                padding: 15px;
                background: #f8f9fa;
                border-radius: 8px;
                letter-spacing: 5px;
            }
            .content { background: #fff; padding: 30px; border-radius: 8px; border: 1px solid #e9ecef; }
            .footer { margin-top: 30px; padding-top: 20px; border-top: 1px solid #ddd; color: #666; text-align: center; }
            .note { background: #fff3cd; padding: 15px; border-radius: 5px; border: 1px solid #ffeaa7; margin: 20px 0; }
        </style>
    </head>
    <body>
        <div class='container'>
            <div class='header'>";
    
    // Add logo if available
    if ($email_logo_url) {
        $full_message .= "<img src='" . esc_url($email_logo_url) . "' alt='" . esc_attr(get_bloginfo('name')) . "' class='logo'>";
    } else {
        $full_message .= "<h1>" . get_bloginfo('name') . "</h1>";
    }
    
    $full_message .= "
            </div>
            <div class='content'>
                " . $message . "
            </div>
            <div class='footer'>
                <p>" . sprintf(__('Best regards,<br><strong>%s</strong> Team', 'dreamsalon-core'), get_bloginfo('name')) . "</p>
            </div>
        </div>
    </body>
    </html>";
    
    $headers = array(
        'Content-Type: text/html; charset=UTF-8',
        'From: ' . get_bloginfo('name') . ' <' . get_option('admin_email') . '>'
    );
    
    return wp_mail($email, $subject, $full_message, $headers);
}


function dreamsalon_verify_otp_login($user_id, $entered_otp) {

    $stored_otp = get_user_meta($user_id, 'login_otp', true);
    $otp_expiry = (int) get_user_meta($user_id, 'login_otp_expiry', true);
    $attempts   = (int) get_user_meta($user_id, 'login_otp_attempts', true);

    // OTP Not Found
    if (empty($stored_otp)) {
        return 'No OTP found. Please request a new OTP.';
    }

    // OTP Expired
    if ($otp_expiry < time()) {
        dreamsalon_clear_login_otp($user_id);
        return 'OTP has expired. Please request a new OTP.';
    }

    // Attempt Limit
    if ($attempts >= 5) {
        dreamsalon_clear_login_otp($user_id);
        return 'Too many failed attempts. Please request a new OTP.';
    }

    // Validate format (only 4–6 digits allowed)
    if (!preg_match('/^[0-9]{4,6}$/', $entered_otp)) {
        update_user_meta($user_id, 'login_otp_attempts', $attempts + 1);
        return 'Invalid OTP format.';
    }

    // OTP Match
    if ((string)$stored_otp === (string)$entered_otp) {

        // Clear OTP after successful login
        dreamsalon_clear_login_otp($user_id);

        update_user_meta($user_id, 'last_otp_verified', current_time('mysql'));

        return true;
    }

    // Wrong OTP – increase attempts
    $remaining = max(0, 4 - $attempts); // remaining attempts before lock
    update_user_meta($user_id, 'login_otp_attempts', $attempts + 1);

    return "Invalid OTP. {$remaining} attempts remaining.";
}



function dreamsalon_clear_login_otp($user_id) {
    delete_user_meta($user_id, 'login_otp');
    delete_user_meta($user_id, 'login_otp_expiry');
    delete_user_meta($user_id, 'login_otp_attempts');
}

// AJAX handler for sending login OTP
function send_login_otp_ajax() {
    // Check nonce
    if (!check_ajax_referer('otp_nonce', 'security', false)) {
        wp_send_json_error('Security verification failed.');
    }
    
    $username = isset($_POST['username']) ? sanitize_text_field($_POST['username']) : '';
    
    if (empty($username)) {
        wp_send_json_error('Email or username is required.');
    }
    
    // Check if user exists by email or username
    $user = get_user_by('email', $username);
    if (!$user) {
        $user = get_user_by('login', $username);
    }
    
    if (!$user) {
        wp_send_json_error('No account found with this email or username.');
    }
    
    // Generate and store OTP
    $otp = dreamsalon_generate_login_otp($user->ID);
    
    // Send OTP email
    $sent = dreamsalon_send_login_otp_email($user->ID, $otp);
    
    // if ($sent) {
        wp_send_json_success('OTP has been sent to your registered email.');
    // } else {
    //     // Even if email fails, don't show OTP - just show error
    //     wp_send_json_error('Failed to send OTP. Please try again.');
    // }
}
add_action('wp_ajax_nopriv_send_login_otp', 'send_login_otp_ajax');
add_action('wp_ajax_send_login_otp', 'send_login_otp_ajax');

// Configure SMTP for email sending

// Clean up old OTP data (optional - can be run as cron)
function dreamsalon_cleanup_expired_login_otp() {
    global $wpdb;
    
    $current_time = time();
    $users_with_otp = $wpdb->get_results(
        "SELECT user_id, meta_value as expiry 
         FROM $wpdb->usermeta 
         WHERE meta_key = 'login_otp_expiry' AND meta_value < $current_time"
    );
    
    foreach ($users_with_otp as $user_otp) {
        dreamsalon_clear_login_otp($user_otp->user_id);
    }
}

// AJAX handler for verifying OTP
function verify_registration_otp_ajax() {
    // Check nonce
    if (!check_ajax_referer('otp_nonce', 'security', false)) {
        wp_send_json_error('Security verification failedddd.');
    }

    $email = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';
    $otp = isset($_POST['otp']) ? sanitize_text_field($_POST['otp']) : '';

    if (empty($email) || empty($otp)) {
        wp_send_json_error('Email and OTP are required.');
    }

    $verification_result = verify_registration_otp($email, $otp);
    
    if ($verification_result === true) {
        wp_send_json_success('OTP verified successfully!');
    } else {
        wp_send_json_error($verification_result);
    }
}
add_action('wp_ajax_nopriv_verify_registration_otp', 'verify_registration_otp_ajax');
add_action('wp_ajax_verify_registration_otp', 'verify_registration_otp_ajax');

// Send OTP via AJAX
function send_otp_ajax() {
    global $dreamsalon_theme_options;
    
    // Verify nonce
    if (!check_ajax_referer('otp_nonce', 'security', false)) {
        wp_send_json_error('Security verification failed.');
    }

    // Sanitize Email
    $email = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';

    // Validate email
    if (empty($email)) {    
        wp_send_json_error('Email is required.');
    }

    if (!is_email($email)) {
        wp_send_json_error('Please enter a valid email address.');
    }

    // Check if email already registered
    if (email_exists($email)) {
        wp_send_json_error('This email is already registered. Please login.');
    }

    $hash = dreamsalon_hash_email($email);

    // Check send attempt limit (rate-limit - 60 seconds)
    $last_sent = get_transient('otp_last_sent_' . $hash);
    if ($last_sent) {
        wp_send_json_error('OTP already sent. Please wait 60 seconds.');
    }

    // Generate 6-digit OTP
    $otp = wp_rand(100000, 999999);
    
    // Store OTP for 10 minutes
    set_transient('registration_otp_' . $hash, $otp, 10 * MINUTE_IN_SECONDS);
    set_transient('registration_otp_email_' . $hash, $email, 10 * MINUTE_IN_SECONDS);

    // Set resend limit 60 seconds
    set_transient('otp_last_sent_' . $hash, true, 60);

    // Get email settings from dreamsalon theme options
    $otp_emails_name = $dreamsalon_theme_options['otp_emails_name'] ?? 'Dreamsalon';
    $otp_emails_from_email = $dreamsalon_theme_options['otp_emails_from_email'] ?? get_bloginfo('admin_email');
    $otp_subject_from_email = $dreamsalon_theme_options['otp_subject_from_email'] ?? 'Your Verification OTP';
    $otp_content_from_email = $dreamsalon_theme_options['otp_content_from_email'] ?? 'Your OTP code is {otp}.';
    $otp_email_logo = $dreamsalon_theme_options['otp_email_logo'] ?? '';
    $otp_email_logo_url = is_array($otp_email_logo) && isset($otp_email_logo['url']) ? $otp_email_logo['url'] : '';

    // Replace placeholders in the email content
    $email_content = str_replace(
        ['{user_email}', '{otp}', '{site_name}', '{admin_email}'],
        [$email, $otp, get_bloginfo('name'), get_bloginfo('admin_email')],
        $otp_content_from_email
    );

    // Use the email content directly from theme options (no custom HTML wrapper)
    $subject = $otp_subject_from_email;
    $message = $email_content;
    
    // Set email headers
    $headers = array(
        'Content-Type: text/html; charset=UTF-8',
        'From: ' . $otp_emails_name . ' <' . $otp_emails_from_email . '>',
        'Reply-To: ' . $otp_emails_from_email
    );

    // Send email
    $sent = wp_mail($email, $subject, $message, $headers);

    if (!$sent) {
        // Clean up on failure
        $hash = dreamsalon_hash_email($email);

        delete_transient('registration_otp_' . $hash);
        delete_transient('registration_otp_email_' . $hash);
       
    }

    // FOR TESTING/DEBUGGING - Return OTP in development environment
    $response_data = 'OTP has been sent to your email address.';

    wp_send_json_success($response_data);
}
// add_action('wp_ajax_nopriv_send_otp', 'send_otp_ajax');
// add_action('wp_ajax_send_otp', 'send_otp_ajax');

// Verify OTP for registration
function verify_registration_otp($email = '', $otp = '') {
    // If called via AJAX
    if (wp_doing_ajax()) {
        if (!check_ajax_referer('otp_nonce', 'security', false)) {
            wp_send_json_error('Security verification failed.');
        }

        $email = sanitize_email($_POST['email']);
        $otp = sanitize_text_field($_POST['otp']);
    }

    if (empty($email) || empty($otp)) {
        if (wp_doing_ajax()) {
            wp_send_json_error('Email and OTP are required.');
        }
        return 'Email and OTP are required.';
    }

    $hash = dreamsalon_hash_email($email);

    $transient_key = 'registration_otp_' . $hash;
    $stored_otp = get_transient($transient_key);
    $stored_email = get_transient('registration_otp_email_' . $hash);

    // Verify OTP exists
   

    // Verify OTP matches
    if ($stored_otp == $otp) {
        if (wp_doing_ajax()) {
            wp_send_json_error('verified.');
        }
        return 'verified.';
    }

    // Verify email matches
    if ($stored_email == $email) {
        if (wp_doing_ajax()) {
            wp_send_json_error('Email mismatch. Please use the same email you requested OTP for.');
        }
        return 'Email mismatch. Please use the same email you requested OTP for.';
    }

    // OTP verified successfully - mark as verified
    set_transient('registration_otp_verified_' . dreamsalon_hash_email($email), true, 10 * MINUTE_IN_SECONDS);
    
    if (wp_doing_ajax()) {
        wp_send_json_success('OTP verified successfully!');
    }
    
    return true;
}
add_action('wp_ajax_nopriv_verify_registration_otp', 'verify_registration_otp');
add_action('wp_ajax_verify_registration_otp', 'verify_registration_otp');

// Check if OTP is verified
function is_otp_verified($email) {
    return get_transient('registration_otp_verified_' . dreamsalon_hash_email($email)) === true;
}

// Clean up OTP data after registration
function cleanup_otp_after_registration($email) {
    $email_hash = dreamsalon_hash_email($email);
    delete_transient('registration_otp_' . $email_hash);
    delete_transient('registration_otp_email_' . $email_hash);
    delete_transient('registration_otp_verified_' . $email_hash);
    delete_transient('otp_last_sent_' . $email_hash);
}

// Get stored OTP for testing/debugging
function get_stored_otp($email) {
    if (empty($email) || !is_email($email)) {
        return false;
    }
    
    $otp = get_transient('registration_otp_' . dreamsalon_hash_email($email));
    return $otp;
}
// Add email availability check AJAX handler
add_action('wp_ajax_check_email_availability', 'check_email_availability');
add_action('wp_ajax_nopriv_check_email_availability', 'check_email_availability');

function check_email_availability() {
    // Verify nonce
    if (!wp_verify_nonce($_POST['security'], 'email_check_nonce')) {
        wp_send_json_error('Security verification failed.');
    }

    $email = sanitize_email($_POST['email']);
    
    if (empty($email) || !is_email($email)) {
        wp_send_json_error('Invalid email address.');
    }

    // Check if email exists
    $email_exists = email_exists($email);
    $username_exists = username_exists($email);

    wp_send_json_success(array(
        'available' => !$email_exists && !$username_exists,
        'message' => $email_exists || $username_exists ? 'Email already registered' : 'Email available'
    ));
}



/**
 * Custom registration form handler for DreamSalon Register template
 */
function dreamsalon_handle_registration_form() {

    if ($_SERVER['REQUEST_METHOD'] === 'POST' 
        && isset($_POST['email'], $_POST['password'], $_POST['name'])) {

        global $wpdb;

        $name     = sanitize_text_field($_POST['name']);
        $email    = sanitize_email($_POST['email']);
        $password = $_POST['password'];

        $user_login = sanitize_user($name, true);

        // Ensure username is unique
        $original_login = $user_login;
        $suffix = 1;
        while (username_exists($user_login)) {
            $user_login = $original_login . $suffix;
            $suffix++;
        }

        if (empty($name) || empty($email) || empty($password)) {
            wc_add_notice(__('All fields are required.', 'dreamsalon-core'), 'error');
            return;
        }

        if (email_exists($email)) {
            wc_add_notice(__('Email already registered.', 'dreamsalon-core'), 'error');
            return;
        }

        $hashed_password = wp_hash_password($password);

        $inserted = $wpdb->insert(
            $wpdb->users,
            [
                'user_login'      => $user_login,
                'user_pass'       => $hashed_password,
                'user_nicename'   => sanitize_title($name),
                'user_email'      => $email,
                'user_registered' => current_time('mysql'),
                'user_status'     => 0,
                'display_name'    => $name
            ],
            ['%s','%s','%s','%s','%s','%d','%s']
        );

        if ($inserted) {

            $user_id = $wpdb->insert_id;

            // Assign role
            $user = new WP_User($user_id);
            $user->set_role('customer');

            // SAVE USER META → verification status
            update_user_meta($user_id, 'ds_email_verified', 'yes');  // or "no" if waiting OTP

            //wc_add_notice(__('Registration successful! Please login with your credentials.', 'dreamsalon-core'), 'success');


            $creds = array(
    'user_login'    => $email,     // or username
    'user_password' => $_POST['password'],   // the password user entered
    'remember'      => true,
);

$user = wp_signon($creds);
 

		
 if (!is_wp_error($user)) {
    // Check if cart has items
    if (WC()->cart && WC()->cart->get_cart_contents_count() > 0) {
        // Redirect to checkout page
        wp_safe_redirect(wc_get_checkout_url());
    } else {
        // Redirect to homepage or account page
        wp_safe_redirect(site_url('/'));
    }
    exit;
} else {
    // Handle login error
    wp_safe_redirect(site_url('/login/?login=failed'));
    exit;
}


           // wp_safe_redirect(site_url('/'));
            exit;
        } 
        else {
            wc_add_notice(__('Error creating account. Please try again.', 'dreamsalon-core'), 'error');
        }
    }
}
add_action('template_redirect', 'dreamsalon_handle_registration_form');