File: /mnt/data/dreamsai-wp/wp-content/dreams-ai/templates/login-form.php
<?php
/**
* Template Name: Dreams Login Template
* Description: Standalone login page with secure login handling.
*
* @package Dreamssalon
* @version 1.0.0
* @author Dreamssalon Team
* @since 1.0.0
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
// Redirect logged in users to dashboard
if (is_user_logged_in()) {
wp_safe_redirect(home_url('/'));
exit;
}
// Get logo URLs using Dreams Theme Options Framework
$main_logo_url = '';
$logo_dark_url = '';
// Function to check if Dreams Theme Options Framework is active
function dtof_is_active()
{
return has_filter('dtof_register_theme_options') ||
function_exists('dtof_get_option') ||
defined('DTOF_VERSION');
}
// Function to get options from Dreams Theme Options Framework
function dtof_get_options($option_id, $default = '', $theme_slug = '')
{
// If theme slug is not provided, try to get it from the current theme
if (empty($theme_slug)) {
$current_theme = wp_get_theme();
$theme_slug = $current_theme->get('TextDomain') ?: sanitize_title($current_theme->get('Name'));
}
// Try multiple option names for compatibility
$option_names = [
'dtof_' . $theme_slug . '_options',
'dtof_options_' . $theme_slug,
'dtof_theme_options',
'dreams_theme_options',
$theme_slug . '_options'
];
foreach ($option_names as $option_name) {
$options = get_option($option_name, array());
if (isset($options[$option_id])) {
return $options[$option_id];
}
}
// Also try aipresentation theme specifically
$aipresentation_options = get_option('dtof_aipresentation_options', array());
if (isset($aipresentation_options[$option_id])) {
return $aipresentation_options[$option_id];
}
return $default;
}
// Check if DTOF is active and get logo options
if (dtof_is_active()) {
// Get dark logo (logo_dark)
$main_logo = dtof_get_option('logo_dark');
if (!empty($main_logo)) {
// Handle both string URL and array format
if (is_string($main_logo)) {
$main_logo_url = $main_logo;
} elseif (is_array($main_logo) && isset($main_logo['url'])) {
$main_logo_url = $main_logo['url'];
}
}
// Get light logo (logo_light)
$logo_dark = dtof_get_option('logo_light');
if (!empty($logo_dark)) {
// Handle both string URL and array format
if (is_string($logo_dark)) {
$logo_dark_url = $logo_dark;
} elseif (is_array($logo_dark) && isset($logo_dark['url'])) {
$logo_dark_url = $logo_dark['url'];
}
}
} else {
// Fallback to Redux Framework check (for backward compatibility)
if (in_array('dreams-theme-options-framework/dreams-theme-options-framework.php', apply_filters('active_plugins', get_option('active_plugins')), true)) {
$main_logo = dtof_get_option('logo_dark');
if (!empty($main_logo) && isset($main_logo['url'])) {
$main_logo_url = $main_logo['url'];
}
$logo_dark = dtof_get_option('frontend_light');
if (!empty($logo_dark) && isset($logo_dark['url'])) {
$logo_dark_url = $logo_dark['url'];
}
}
}
// Fallback to default images if no logos set
if (empty($main_logo_url)) {
$main_logo_url = get_template_directory_uri() . '/assets/images/logo_default.svg';
}
if (empty($logo_dark_url)) {
$logo_dark_url = get_template_directory_uri() . '/assets/images/dark-logo.svg';
}
// Get page links using DTOF or fallback
function get_login_page_link($option_id, $default_url = '')
{
// Try DTOF first
if (dtof_is_active()) {
$page_id = dtof_get_option($option_id);
} else {
// Fallback to Redux
$page_id = function_exists('dreamssalon_fl_framework_getoptions') ?
dreamssalon_fl_framework_getoptions($option_id) : '';
}
if (!empty($page_id)) {
// Handle comma-separated multiple selections
if (strpos($page_id, ',') !== false) {
$page_ids = explode(',', $page_id);
$page_id = trim($page_ids[0]);
}
$page_url = get_permalink($page_id);
if ($page_url) {
return $page_url;
}
}
return !empty($default_url) ? $default_url : home_url('/');
}
// Get register page URL
$register_page_url = get_login_page_link('header_register_link', home_url('/register'));
// Get forgot password page URL
$forgot_page_url = get_login_page_link('header_forget_link', wp_lostpassword_url());
// Login logic variables
$error_message = '';
$success_message = '';
$is_otp_mode = false;
$otp_sent = false;
// Handle form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['dreamssalon_login_nonce']) && wp_verify_nonce($_POST['dreamssalon_login_nonce'], 'dreamssalon_login_action')) {
// Check if it's OTP login or password login
$is_otp_login = isset($_POST['otp_login']) && $_POST['otp_login'] === '1';
if ($is_otp_login) {
// OTP-based login
$username = sanitize_text_field($_POST['username'] ?? '');
$otp = sanitize_text_field($_POST['otp'] ?? '');
$remember = isset($_POST['remember']);
if (empty($username) || empty($otp)) {
$error_message = esc_html__('Email/Username and OTP are required.', 'dreams-salon');
$is_otp_mode = true;
$otp_sent = true;
} else {
global $wpdb;
// Get user from wp_users
$user = $wpdb->get_row($wpdb->prepare(
"SELECT ID, user_login, user_pass, user_status
FROM {$wpdb->users}
WHERE user_login = %s OR user_email = %s",
$username,
$username
));
if (!$user) {
$error_message = esc_html__('No account found with this email or username.', 'dreams-salon');
$is_otp_mode = true;
$otp_sent = true;
} else {
// Placeholder for OTP verification - you'll need to implement this function
$verification_result = dreamssalon_verify_otp_login($user->ID, $otp);
if ($verification_result === true) {
// Login the user
wp_set_current_user($user->ID);
wp_set_auth_cookie($user->ID, $remember);
update_user_meta($user->ID, 'last_login', current_time('mysql'));
update_user_meta($user->ID, 'last_otp_login', current_time('mysql'));
$wp_user = get_userdata($user->ID);
if (in_array('administrator', (array) $wp_user->roles)) {
wp_redirect(admin_url());
} else {
wp_redirect(home_url('/'));
}
exit;
} else {
$error_message = $verification_result ?: esc_html__('Invalid OTP code.', 'dreams-salon');
$is_otp_mode = true;
$otp_sent = true;
}
}
}
} else {
// Password-based login (original working code)
$username = sanitize_text_field($_POST['username'] ?? '');
$password = sanitize_text_field($_POST['password'] ?? '');
$remember = isset($_POST['remember']);
if (empty($username) || empty($password)) {
$error_message = esc_html__('Both fields are required.', 'dreams-salon');
} else {
global $wpdb;
// Get user from wp_users
$user = $wpdb->get_row($wpdb->prepare(
"SELECT ID, user_login, user_pass, user_status
FROM {$wpdb->users}
WHERE user_login = %s OR user_email = %s",
$username,
$username
));
if (!$user) {
$error_message = esc_html__('Invalid username or email.', 'dreams-salon');
} elseif ($user->user_status != 0) {
$error_message = esc_html__('Account is not active.', 'dreams-salon');
} elseif (!wp_check_password($password, $user->user_pass, $user->ID)) {
$error_message = esc_html__('Incorrect password.', 'dreams-salon');
} else {
// Login the user
wp_set_current_user($user->ID);
wp_set_auth_cookie($user->ID, $remember);
update_user_meta($user->ID, 'last_login', current_time('mysql'));
$wp_user = get_userdata($user->ID);
if (class_exists('WooCommerce')) {
$cart = WC()->cart;
if ($cart && !$cart->is_empty()) {
wp_redirect(wc_get_checkout_url());
exit;
}
}
if (in_array('administrator', (array) $wp_user->roles)) {
wp_redirect(admin_url());
} else {
wp_redirect(home_url('/'));
}
exit;
}
}
}
}
// Handle OTP request via AJAX
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'send_login_otp') {
if (!wp_verify_nonce($_POST['security'], 'otp_nonce')) {
wp_die('Security verification failed.');
}
$username = sanitize_text_field($_POST['username'] ?? '');
if (empty($username)) {
wp_send_json_error('Email or username is required.');
}
global $wpdb;
$user = $wpdb->get_row($wpdb->prepare(
"SELECT ID, user_email
FROM {$wpdb->users}
WHERE user_login = %s OR user_email = %s",
$username,
$username
));
if (!$user) {
wp_send_json_error('No account found with this email or username.');
}
}
// Get OTP settings
$otp_enabled = false;
$otp_expiry_minutes = 5;
if (dtof_is_active()) {
// Try to get OTP settings from DTOF
$otp_enabled = dtof_get_option('login_otp_switch', false);
$otp_expiry_minutes = intval(dtof_get_option('otp_expiration_time', 5));
} else {
// Fallback to old theme options
$options = get_option('dreamssalon_theme_options', array());
$otp_enabled = !empty($options['login_otp_switch']);
$otp_expiry_minutes = !empty($options['otp_expiration_time']) ?
intval($options['otp_expiration_time']) : 5;
}
$otp_expiry_seconds = $otp_expiry_minutes * 60;
get_template_part('templates/header/header', 'none');
?>
<div class="bg-light-2001">
<!-- Main Wrapper -->
<div class="main-wrapper login-page-bg">
<div class="container-fluid position-relative z-1">
<div class="w-100 overflow-hidden position-relative flex-wrap d-block vh-100">
<div class="row justify-content-center align-items-center vh-100 overflow-auto flex-wrap py-3">
<div class="col-md-8 col-lg-6 col-xl-4 mx-auto">
<!-- Alert Container for Dynamic Messages -->
<div id="alert-container">
<?php if (!empty($error_message)): ?>
<div class="alert alert-danger text-center mb-4">
<?php echo wp_kses_post($error_message); ?>
</div>
<?php endif; ?>
<?php if (!empty($success_message)): ?>
<div class="alert alert-success text-center mb-4">
<?php echo wp_kses_post($success_message); ?>
</div>
<?php endif; ?>
</div>
<form method="post" action="" class="d-flex justify-content-center align-items-center"
id="login-form">
<?php wp_nonce_field('dreamssalon_login_action', 'dreamssalon_login_nonce'); ?>
<input type="hidden" name="otp_login" id="otp_login"
value="<?php echo $is_otp_mode ? '1' : '0'; ?>">
<div class="d-flex flex-column justify-content-lg-center p-4 p-lg-0 pb-0 flex-fill">
<div class="mx-auto mb-4 text-center">
<a href="<?php echo esc_url(home_url('/')); ?>">
<?php if (!empty($main_logo_url)): ?>
<img src="<?php echo esc_url($main_logo_url); ?>" class="img-fluid dreams-header-logo"
alt="<?php esc_attr_e('Logo', 'dreams-salon'); ?>">
<?php else: ?>
<img src="<?php echo esc_url(get_template_directory_uri() . '/assets/images/logo_default.svg'); ?>"
class="img-fluid" alt="<?php esc_attr_e('Logo', 'dreams-salon'); ?>">
<?php endif; ?>
</a>
</div>
<div class="login-item">
<h2 class="text-xl font-semibold text-gray-900 mb-1 text-start mb-3"><?php echo esc_html__('Welcome Back', 'dreams-salon'); ?></h2>
<p class="text-start mb-3">Sign in to continue exploring our tools.</p>
<!-- Email/Username Field (Always visible) -->
<div class="mb-3">
<label class="form-label" for="username">
<?php echo esc_html__('Email or Username', 'dreams-salon'); ?>
<span class="text-danger ms-1">*</span>
</label>
<input type="text" class="form-control form-control-lg" id="username" name="username" placeholder="<?php esc_attr_e('Your Email Address', 'dreams-salon'); ?>" value="<?php echo isset($_POST['username']) ? esc_attr($_POST['username']) : ''; ?>" required>
</div>
<!-- Password Login Section -->
<div class="password-section" id="password-section">
<div class="mb-3">
<div class="mb-3">
<label class="form-label" for="password">
<?php echo esc_html__('Password', 'dreams-salon'); ?>
<span class="text-danger ms-1">*</span>
</label>
<div class="position-relative">
<input type="password" class="form-control form-control-lg pe-5"
id="password" name="password"
placeholder="<?php esc_attr_e('Your Password', 'dreams-salon'); ?>"
required>
<button type="button"
class="btn btn-link position-absolute top-50 end-0 translate-middle-y password-visible"
id="togglePassword"
aria-label="<?php esc_attr_e('Show password', 'dreams-salon'); ?>">
<i class="fas fa-eye"></i>
</button>
</div>
</div>
</div>
<div class="mb-4">
<button type="submit" class="btn btn-lg btn-primary w-100 sign-in-btn"
id="password-login-btn">
<?php echo esc_html__('Sign In', 'dreams-salon'); ?>
</button>
</div>
<?php if ($otp_enabled): ?>
<div class="login-or mb-4">
<span class="span-or">OR</span>
</div>
<div class="mb-3">
<div
class="d-flex align-items-center justify-content-center flex-wrap gap-2">
<div class="text-center flex-fill">
<button type="button" class="btn btn-outline-primary w-100"
id="login-with-otp-btn">
<?php echo esc_html__('Login with OTP', 'dreams-salon'); ?>
</button>
</div>
</div>
</div>
<?php endif; ?>
</div>
<!-- OTP Login Section -->
<div class="otp-section" id="otp-section">
<div class="mb-3">
<button type="button" id="send-otp-btn"
class="btn btn-lg btn-primary w-100">
<?php echo esc_html__('Send OTP', 'dreams-salon'); ?>
</button>
</div>
<div class="mb-3" id="otp-field-container" style="display: none;">
<label class="form-label" for="otp">
<?php echo esc_html__('OTP Code', 'dreams-salon'); ?>
<span class="text-danger ms-1">*</span>
</label>
<input type="text" class="form-control form-control-lg text-center" id="otp"
name="otp"
placeholder="<?php esc_attr_e('Enter 6-digit OTP', 'dreams-salon'); ?>"
maxlength="6" pattern="[0-9]{6}" inputmode="numeric">
<div id="otp-timer" class="text-muted small mt-2 text-center"></div>
</div>
<div class="mb-4">
<button type="button" class="btn btn-lg btn-primary w-100"
id="verify-otp-btn" style="display: none;">
<?php echo esc_html__('Verify OTP', 'dreams-salon'); ?>
</button>
</div>
<div class="login-or mb-4">
<span class="span-or"><?php esc_html_e('OR', 'dreams-salon'); ?></span>
</div>
<div class="mb-3">
<div
class="d-flex align-items-center justify-content-center flex-wrap gap-2">
<div class="text-center flex-fill">
<button type="button" class="btn btn-outline-primary w-100"
id="back-to-password-btn">
<?php echo esc_html__('Login with Password', 'dreams-salon'); ?>
</button>
</div>
</div>
</div>
</div>
<div class="text-center mt-3">
<p class="mb-0">
<?php echo esc_html__('Don\'t have an account?', 'dreams-salon'); ?>
<a href="<?php echo esc_url($register_page_url); ?>"
class="register-btn text-primary fw-bold">
<?php echo esc_html__('Sign Up', 'dreams-salon'); ?>
</a>
</p>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- /Main Wrapper -->
<!-- Cursor -->
<div class="xb-cursor tx-js-cursor">
<div class="xb-cursor-wrapper">
<div class="xb-cursor--follower xb-js-follower"></div>
</div>
</div>
<!-- /Cursor -->
</div>
<?php get_template_part('templates/footer/footer', 'none'); ?>
<style>
.otp-section {
display: none;
}
.password-section {
display: block;
}
#otp-timer {
font-size: 12px;
margin-top: 5px;
display: none;
}
.alert-success {
background-color: #d1e7dd;
border-color: #badbcc;
color: #0f5132;
}
.login-or {
position: relative;
text-align: center;
margin: 20px 0;
}
.sign-in-btn {
background:linear-gradient(135deg, #fb64b6 0%, #ff6900 100%) !important;
border-color: #0f4f45 !important;
color: #ffffff !important;
transition: all 0.3s ease !important;
border-radius: 15px !important;
}
.login-page-bg {
background: linear-gradient(135deg, #fb64b6 0%, #ff6900 100%) !important;
}
.password-visible {
border: none !important;
padding: 10px;
color: #d1cdcd ;
}
.login-item {
border-radius: 20px !important;
background-color: #e0dedeff !important;
}
.login-or .span-or {
display: inline-block;
background: #fff;
padding: 0 15px;
position: relative;
z-index: 1;
color: #6c757d;
font-size: 14px;
}
.login-or:before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: #dee2e6;
transform: translateY(-50%);
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.alert {
border-radius: 8px;
padding: 12px 16px;
margin-bottom: 16px;
}
</style>
<script>
jQuery(document).ready(function ($) {
let otpTimer;
let timeLeft = <?php echo esc_js($otp_expiry_seconds); ?>;
// Function to show alert message
function showAlert(message, type = 'danger') {
const alertContainer = $('#alert-container');
// Clear existing alerts
alertContainer.empty();
// Create new alert
const alert = $(`
<div class="alert alert-${type} text-center mb-4">
${message}
</div>
`);
// Add to container
alertContainer.append(alert);
// Auto-hide after 5 seconds
setTimeout(() => {
alert.fadeOut(300, function () {
$(this).remove();
});
}, 5000);
return alert;
}
// Switch to OTP login
$('#login-with-otp-btn').on('click', function () {
$('#password-section').hide();
$('#otp-section').show();
$('#otp_login').val('1');
$('#password').prop('required', false);
$('#username').focus();
});
// Switch back to password login
$('#back-to-password-btn').on('click', function () {
$('#otp-section').hide();
$('#password-section').show();
$('#otp_login').val('0');
$('#password').prop('required', true);
resetOTPTimer();
$('#otp-field-container').hide();
$('#verify-otp-btn').hide();
$('#send-otp-btn').show();
$('#password').focus();
});
// Toggle password visibility
$('#togglePassword').on('click', function () {
const passwordInput = $('#password');
const type = passwordInput.attr('type') === 'password' ? 'text' : 'password';
passwordInput.attr('type', type);
// Toggle eye icon
const eyeIcon = $(this).find('i');
if (type === 'text') {
eyeIcon.removeClass('fa-eye').addClass('fa-eye-slash');
$(this).attr('aria-label', '<?php esc_attr_e("Hide password", "dreams-salon"); ?>');
} else {
eyeIcon.removeClass('fa-eye-slash').addClass('fa-eye');
$(this).attr('aria-label', '<?php esc_attr_e("Show password", "dreams-salon"); ?>');
}
});
// Send OTP
$('#send-otp-btn').on('click', function () {
const username = $('#username').val().trim();
if (!username) {
showAlert('Please enter your email or username.', 'danger');
$('#username').focus();
return;
}
const sendBtn = $(this);
sendBtn.prop('disabled', true).text('Sending OTP...');
$.ajax({
url: '<?php echo admin_url('admin-ajax.php'); ?>',
type: 'POST',
data: {
action: 'send_login_otp',
username: username,
security: '<?php echo wp_create_nonce("otp_nonce"); ?>'
},
success: function (response) {
if (response.success) {
showAlert(response.data, 'success');
$('#otp-field-container').show();
$('#verify-otp-btn').show();
$('#send-otp-btn').hide();
$('#otp').prop('required', true);
$('#otp').focus();
startOTPTimer();
} else {
showAlert(response.data, 'danger');
sendBtn.prop('disabled', false).text('Send OTP');
}
},
error: function () {
showAlert('Failed to send OTP. Please try again.', 'danger');
sendBtn.prop('disabled', false).text('Send OTP');
}
});
});
// Verify OTP
$('#verify-otp-btn').on('click', function () {
const otp = $('#otp').val().trim();
if (!otp) {
showAlert('Please enter the OTP code.', 'danger');
$('#otp').focus();
return;
}
if (otp.length !== 6) {
showAlert('Please enter a valid 6-digit OTP.', 'danger');
$('#otp').focus();
return;
}
$(this).prop('disabled', true).text('Verifying...');
$('#login-form').submit();
});
// Auto-focus logic
$('#otp').on('input', function () {
if ($(this).val().length === 6) {
$('#verify-otp-btn').focus();
}
});
// Timer Functions
function startOTPTimer() {
timeLeft = <?php echo esc_js($otp_expiry_seconds); ?>;
$('#otp-timer').show();
updateTimerDisplay();
otpTimer = setInterval(function () {
timeLeft--;
updateTimerDisplay();
if (timeLeft <= 0) {
clearInterval(otpTimer);
$('#otp-timer').html('<span class="text-danger">OTP expired. Please request a new one.</span>');
$('#send-otp-btn').show().prop('disabled', false).text('Send OTP');
$('#otp-field-container').hide();
$('#verify-otp-btn').hide();
$('#otp').prop('required', false);
showAlert('OTP has expired. Please request a new one.', 'warning');
}
}, 1000);
}
function resetOTPTimer() {
if (otpTimer) {
clearInterval(otpTimer);
}
$('#otp-timer').hide();
$('#otp').prop('required', false);
}
function updateTimerDisplay() {
const minutes = Math.floor(timeLeft / 60);
const seconds = timeLeft % 60;
$('#otp-timer').text('OTP expires in: ' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds);
}
// Initialize from server-side state
<?php if ($is_otp_mode): ?>
$('#password-section').hide();
$('#otp-section').show();
$('#otp_login').val('1');
$('#password').prop('required', false);
<?php if ($otp_sent): ?>
$('#otp-field-container').show();
$('#verify-otp-btn').show();
$('#send-otp-btn').hide();
$('#otp').prop('required', true);
<?php endif; ?>
<?php endif; ?>
});
</script>