siteFeatures = Features::forSite();
$this->metaForm = new MetaForm();
$this->emailManager = new EmailManager();
$this->rateLimiter = new AjaxRateLimiter();
// Register default token handlers
$this->registerDefaultHandlers();
// Initialize magic link support if enabled
if ($this->siteFeatures->has('magicLink')) {
$this->initMagicLinkSupport();
}
// Create login page if it doesn't exist
$this->ensureLoginPageExists();
// Redirect wp-login.php to custom page
add_action('login_init', [$this, 'redirectToCustomLogin']);
add_action('template_include', [$this, 'renderLoginPage']);
add_action('wp_enqueue_scripts', [$this, 'enqueueScripts'], 15);
// Handle form submissions via AJAX
add_action('wp_ajax_nopriv_jvb_login', [$this, 'handleAjaxLogin']);
add_action('wp_ajax_nopriv_jvb_register', [$this, 'handleAjaxRegister']);
add_action('wp_ajax_nopriv_jvb_lostpassword', [$this, 'handleAjaxLostPassword']);
add_action('wp_ajax_nopriv_jvb_resetpass', [$this, 'handleAjaxResetPassword']);
// Login success handling
add_action('wp_login', [$this, 'handleSuccessfulLogin'], 10, 2);
// Allow other features to register handlers
do_action('jvbLoginManagerInit', $this);
}
/**************************************************************************
* SETUP & CONFIGURATION
**************************************************************************/
/**
* Redirect wp-login.php to custom login page
*/
public function redirectToCustomLogin(): void
{
// Don't redirect if AJAX or REST
if ((defined('DOING_AJAX') && DOING_AJAX) || (defined('REST_REQUEST') && REST_REQUEST)) {
return;
}
// Build custom login URL with all query args
$custom_login_page = home_url('/login');
$query_args = $_GET;
// Remove WordPress internal args
unset($query_args['interim-login'], $query_args['wp-auth-check']);
if (!empty($query_args)) {
$custom_login_page = add_query_arg($query_args, $custom_login_page);
}
wp_safe_redirect($custom_login_page);
exit;
}
protected function getRegistrationFormFields():array
{
$form = get_option(BASE.'registration_form_fields');
if (!$form) {
$form = [];
$select = [];
//Basic fields, for any
$fields = [
'name' => [
'type' => 'text',
'required' => true,
'label' => 'Your Name',
'placeholder'=> 'Mister Meseeks'
],
'email' => [
'type' => 'email',
'required' => true,
'label' => 'Your Email',
'placeholder'=> 'look@me.com'
]
];
if (count(JVB_USER) > 1) {
foreach (JVB_USER as $slug => $config) {
if (!array_key_exists('can_register', $config) || !$config['can_register']) {
continue;
}
$icon = $config['icon'] ?? '';
$icon = ($icon !== '') ? jvbIcon($icon) : '';
$select[$slug] = ''.$icon.$config['label'].''.$config['register']['text']??''.'';
if (!empty($config['register']['fields']??[])){
foreach ($config['register']['fields'] as $field) {
$field['condition'] = [
'field' => 'user_select',
'value' => $slug,
'operator' => '=='
];
$fields[] = $field;
}
}
}
if (!empty($select)) {
$select = array_merge(
[
'subscriber' => 'Subscriber',
],
$select
);
$form = array_merge(
[
'user_select' => [
'type' => 'radio',
'label' => 'Register as',
'options' => $select,
'required' => true,
'default' => 'subscriber'
]
],
$fields
);
}
}else {
$form = $fields;
}
update_option(BASE.'registration_form_fields', $form);
}
return $form;
}
protected function setupFields():void
{
$fields = [];
switch($this->action) {
case 'register':
$fields = $this->getRegistrationFormFields();
break;
case 'lostpassword':
$fields = [
'user_email' => [
'type' => 'email',
'label' => __('Email Address', 'jvb'),
'required' => true,
'placeholder' => 'look@me.com',
],
];
break;
case 'rp':
case 'resetpass':
$fields = [
'pass1' => [
'type' => 'text',
'subtype' => 'password',
'label' => __('New Password', 'jvb'),
'required' => true,
],
'pass2' => [
'type' => 'text',
'subtype' => 'password',
'label' => __('Confirm Password', 'jvb'),
'required' => true,
],
];
break;
case 'login':
$fields = [
'user_email' => [
'type' => 'email',
'label' => __('Email Address', 'jvb'),
'required' => true,
'placeholder' => 'look@me.com',
],
'user_password' => [
'type' => 'text',
'subtype'=> 'password',
'label' => __('Password', 'jvb'),
'required' => true,
],
'remember_me' => [
'type' => 'true_false',
'label' => __('Remember Me', 'jvb'),
'default' => true
]
];
break;
case 'postpass':
$fields = [
'post_password' => [
'type' => 'text',
'subtype' => 'password',
'label' => __('Password', 'jvb'),
'required' => true,
'hint' => 'This post is password protected. Please enter the password to view it.',
],
];
break;
case 'confirmaction':
break;
}
$this->fields = $fields;
}
/**
* Ensure login page exists
*/
protected function ensureLoginPageExists(): void
{
$login_page = $this->getLoginPage();
if (!$login_page || !is_int($login_page)) {
$page_id = get_page_by_path('login');
if (!$page_id) {
$page_id = wp_insert_post([
'post_title' => 'Login',
'post_name' => 'login',
'post_content' => '[jvb_login_form]',
'post_status' => 'publish',
'post_type' => 'page',
'post_author' => 1
]);
}
if ($page_id && !is_wp_error($page_id)) {
if (is_object($page_id)) {
$page_id = (int)$page_id->ID;
}
update_option(BASE.'login_page', $page_id);
// Hide from menus/search
update_post_meta($page_id, '_wp_page_template', 'default');
update_post_meta($page_id, BASE . 'exclude_from_search', true);
}
}
}
public function getLoginPage():int|false
{
return (int)get_option(BASE.'login_page');
}
public function isLoginPage():bool
{
return is_page($this->getLoginPage());
}
public static function isLogin():bool
{
$self = new self;
return $self->isLoginPage();
}
/**************************************************************************
TOKEN & MESSAGE HANDLERS
Extensible by other classes
**************************************************************************/
public function registerTokenHandler(string $token_key, callable $handler, int $priority = 10): void
{
if (!isset($this->tokenHandlers[$priority])) {
$this->tokenHandlers[$priority] = [];
}
$this->tokenHandlers[$priority][$token_key] = $handler;
ksort($this->tokenHandlers);
}
public function registerMessageHandler(string $type, callable $handler, ?callable $condition = null): void
{
$this->messageHandlers[$type] = [
'handler' => $handler,
'condition' => $condition
];
}
protected function registerDefaultHandlers(): void
{
// Invitation handler
if ($this->siteFeatures->has('invitations')) {
$this->registerTokenHandler('invite', function($token, $email, $user_id) {
if (isset($_POST['invite_token'])) {
JVB()->routes('invites')->acceptInvitation(
sanitize_text_field($_POST['invite_token']),
sanitize_email($_POST['invite_email']),
$user_id
);
}
});
$this->registerMessageHandler('invitation',
function() {
$data = JVB()->routes('invites')->verifyInvitation(
sanitize_text_field($_GET['invite']),
sanitize_email($_GET['email'])
);
$name = $data->name;
$inviters = json_decode($data->inviters, true);
$names = [];
foreach ($inviters as $inviter) {
$artist = jvbContentFromUser((int)$inviter['user_id']);
$names[] = ($artist['name'] === '') ? $artist['display_name'] : $artist['name'];
}
$message = (count($names) > 1)
? 'are already here, and have invited you to join in!'
: ' is already here, and invited you to join in!';
return '
Join the Scene, '.$name.'
'.jvbCommaList($names).$message.'
';
},
function() {
return isset($_GET['invite']) && isset($_GET['email']);
}
);
}
// List sharing handler (Favourites)
if ($this->siteFeatures->has('favourites')) {
$this->registerTokenHandler('list_token', function($token, $email, $user_id) {
if (!empty($_GET['list_token']) && !empty($_GET['email'])) {
JVB()->routes('favourites')->acceptListInvitation(
sanitize_text_field($_GET['list_token']),
sanitize_email($_GET['email']),
$user_id
);
}
});
$this->registerMessageHandler('favourites',
function() {
return ''.(JVB_LOGIN['login_from_favourite_header'] ?? 'Save your Favourites').'
';
},
function() {
return isset($_GET['type']) && $_GET['type'] === 'favourites';
}
);
}
// Referral handler - FIXED VERSION
$this->registerTokenHandler('referral_code', function($code, $email, $user_id) {
// $code is already sanitized from processTokenHandlers
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
$_SESSION[BASE . 'referral_code'] = $code;
setcookie(
BASE . 'referral_code',
$code,
time() + (86400 * 30),
'/'
);
}, 5);
}
protected function initMagicLinkSupport(): void
{
if (!Features::forSite()->has('magicLink')) {
return;
}
$this->magicLink = new MagicLinkManager();
}
/*********************************************************************
RENDERING
*********************************************************************/
public function renderLoginPage(string $template):string
{
if (!$this->isLoginPage()) {
return $template;
}
$this->setup();
ob_start();
jvbInlineStyles('nav');
jvbInlineStyles('dash');
jvbInlineStyles('forms');
$this->customStyles();
$this->renderHeader();
$this->renderForms();
$this->renderFooter();
echo ob_get_clean();
return '';
}
protected function setup():void
{
if (array_key_exists('action', $_GET)) {
switch ($_GET['action']){
case 'lostpassword':
case 'retrievepassword': // Alias
$action = 'lostpassword';
break;
case 'rp':
case 'resetpass':
$action = 'resetpass';
break;
default:
$action = $_GET['action'];
}
} else {
$action = 'login';
}
$this->action = $action;
$this->setupLabels();
$this->setupFields();
$this->setupTitle();
}
protected function setupTitle():void
{
switch ($this->action) {
case 'lostpassword':
$title = 'Lost Your Password?';
break;
case 'resetpass':
$title = 'Reset Your Password';
break;
case 'register':
$title = 'Create Your Account';
break;
default:
$title = 'Log In To Your Account';
}
$this->title = $title;
}
protected function customStyles():void
{
$logo = get_theme_mod('custom_logo');
$small = $large = '';
if ($logo) {
$small = wp_get_attachment_image_src($logo, 'medium')[0];
$large = wp_get_attachment_image_src($logo, 'large')[0];
}
echo '';
}
protected function renderForms():void
{
$form = $this->action.'form';
?>
=$this->labels['title']?>
= $this->labels['description'] ?>
labels['extra'])) {
echo '';
} else if ($this->labels['extra']!=='') {
echo '';
}
?>
>
= $this->title ?> | = get_bloginfo('name') ?>
tokenHandlers as $priority => $handlers) {
foreach ($handlers as $token_key => $handler) {
if (isset($_GET[$token_key])) {
$value = sanitize_text_field($_GET[$token_key]);
echo '';
}
}
}
if (isset($_GET['email'])) {
echo '';
}
}
/*************************************************************************
AJAX HANDLERS
*************************************************************************/
public function handleAjaxLogin(): void
{
check_ajax_referer('jvb_login', '_wpnonce');
// Rate limiting
if (!$this->checkAjaxRateLimit('login')) {
wp_send_json_error([
'message' => 'Too many attempts. Please wait a moment.',
'code' => 'rate_limit'
], 429);
}
// Duplicate submission check
if (!$this->checkRequestId()) {
wp_send_json_error([
'message' => 'Duplicate request detected',
'code' => 'duplicate_request'
], 409);
}
$email = sanitize_email($_POST['user_email'] ?? '');
$password = $_POST['user_password'] ?? '';
$remember = !empty($_POST['remember_me']);
if (empty($email) || empty($password)) {
wp_send_json_error([
'message' => 'Please fill in all fields',
'field' => empty($email) ? 'user_email' : 'user_password',
'code' => 'missing_fields'
]);
}
// Verify Turnstile if enabled
if (!$this->verifyTurnstile()) {
wp_send_json_error([
'message' => 'Security verification failed',
'code' => 'turnstile_failed'
]);
}
$user = get_user_by('email', $email);
if (!$user) {
wp_send_json_error([
'message' => 'Unknown email address',
'field' => 'user_email',
'code' => 'invalid_email'
]);
}
$user = wp_authenticate($user->user_login, $password);
if (is_wp_error($user)) {
wp_send_json_error([
'message' => $user->get_error_message(),
'field' => 'user_password',
'code' => $user->get_error_code()
]);
}
wp_clear_auth_cookie();
wp_set_current_user($user->ID);
wp_set_auth_cookie($user->ID, $remember);
do_action('wp_login', $user->user_login, $user);
$redirect = $_POST['redirect_to'] ?? home_url('/dash');
wp_send_json_success(['redirect' => $redirect]);
}
public function handleAjaxRegister(): void
{
check_ajax_referer('jvb_register', '_wpnonce');
// Rate limiting
if (!$this->checkAjaxRateLimit('register')) {
wp_send_json_error([
'message' => 'Too many attempts. Please wait a moment.',
'code' => 'rate_limit'
], 429);
}
// Duplicate submission check
if (!$this->checkRequestId()) {
wp_send_json_error([
'message' => 'Duplicate request detected',
'code' => 'duplicate_request'
], 409);
}
// Verify Turnstile
if (!$this->verifyTurnstile()) {
wp_send_json_error([
'message' => 'Security verification failed',
'code' => 'turnstile_failed'
]);
}
$name = sanitize_text_field($_POST['name'] ?? '');
$email = sanitize_email($_POST['email'] ?? '');
$user_type = sanitize_text_field($_POST['user_select'] ?? 'subscriber');
// Spam prevention - if subscriber is selected and there are other options
if ($user_type === 'subscriber' && count(JVB_USER) > 0) {
$registerable = array_filter(JVB_USER, fn($config) => $config['can_register'] ?? false);
if (!empty($registerable)) {
wp_send_json_error([
'message' => 'Please select a valid account type',
'field' => 'user_select',
'code' => 'invalid_user_type'
]);
}
}
// Validate fields
if (empty($name)) {
wp_send_json_error([
'message' => 'Name is required',
'field' => 'name',
'code' => 'missing_name'
]);
}
if (empty($email)) {
wp_send_json_error([
'message' => 'Email is required',
'field' => 'email',
'code' => 'missing_email'
]);
}
// Check if role can register
if ($user_type !== 'subscriber') {
if (!isset(JVB_USER[$user_type]) || empty(JVB_USER[$user_type]['can_register'])) {
wp_send_json_error([
'message' => 'Invalid account type',
'field' => 'user_select',
'code' => 'invalid_user_type'
]);
}
}
// Check if email exists
if (email_exists($email)) {
wp_send_json_error([
'message' => 'Email already registered',
'field' => 'email',
'code' => 'duplicate_email'
]);
}
// Create user
$user_id = wp_create_user($email, wp_generate_password(), $email);
if (is_wp_error($user_id)) {
wp_send_json_error([
'message' => $user_id->get_error_message(),
'code' => 'user_creation_failed'
]);
}
// Update user data
wp_update_user([
'ID' => $user_id,
'display_name' => $name,
'first_name' => $name
]);
// Set role
$user = new WP_User($user_id);
if ($user_type === 'subscriber') {
$user->set_role('subscriber');
} else {
$role = JVB_USER[$user_type]['role'] ?? 'subscriber';
$user->set_role($role);
// Check if needs approval
if (Features::forMembership()->has('memberVerified') &&
in_array($role, JVB_MEMBERSHIP['memberVerified'] ?? [])) {
$user->add_cap('skip_moderation', false);
update_user_meta($user_id, BASE . 'pending_approval', true);
}
}
// Save additional fields
update_user_meta($user_id, BASE . 'user_type', $user_type);
// Process additional fields from form
foreach ($_POST as $key => $value) {
if (in_array($key, ['name', 'email', 'action', '_wpnonce', 'request_id', 'user_select'])) {
continue;
}
update_user_meta($user_id, BASE . $key, sanitize_text_field($value));
}
// Handle token handlers
$this->processTokenHandlers($user_id, $email);
// Send welcome email with password setup link
$this->sendWelcomeEmail($user_id);
// Trigger registration action for other systems
do_action('jvbAfterUserRegistration', $user_id, $user_type, $_POST);
wp_send_json_success([
'message' => 'Registration successful! Check your email.',
'title' => $this->labels['successTitle'] ?? 'Success!',
'description' => $this->labels['successDescription'] ?? 'Check your email for next steps',
'user_id' => $user_id // Important for file upload dependencies!
]);
}
public function handleAjaxLostPassword(): void
{
check_ajax_referer('jvb_lostpassword', '_wpnonce');
// Rate limiting
if (!$this->checkAjaxRateLimit('lostpassword')) {
wp_send_json_error([
'message' => 'Too many attempts. Please wait a moment.',
'code' => 'rate_limit'
], 429);
}
$email = sanitize_email($_POST['user_email'] ?? '');
if (empty($email)) {
wp_send_json_error([
'message' => 'Email required',
'field' => 'user_email',
'code' => 'missing_email'
]);
}
// Verify Turnstile
if (!$this->verifyTurnstile()) {
wp_send_json_error([
'message' => 'Security verification failed',
'code' => 'turnstile_failed'
]);
}
// Use WordPress's built-in function
$result = retrieve_password($email);
if (is_wp_error($result)) {
wp_send_json_error([
'message' => $result->get_error_message(),
'code' => $result->get_error_code()
]);
}
wp_send_json_success(['message' => 'Check your email for reset link']);
}
public function handleAjaxResetPassword(): void
{
check_ajax_referer('jvb_resetpass', '_wpnonce');
// Rate limiting
if (!$this->checkAjaxRateLimit('resetpass')) {
wp_send_json_error([
'message' => 'Too many attempts. Please wait a moment.',
'code' => 'rate_limit'
], 429);
}
$key = sanitize_text_field($_POST['key'] ?? $_GET['key'] ?? '');
$login = sanitize_text_field($_POST['login'] ?? $_GET['login'] ?? '');
$pass1 = $_POST['pass1'] ?? '';
$pass2 = $_POST['pass2'] ?? '';
if (empty($key) || empty($login)) {
wp_send_json_error([
'message' => 'Invalid reset link',
'code' => 'invalid_key'
]);
}
if (empty($pass1) || empty($pass2)) {
wp_send_json_error([
'message' => 'Please enter a password',
'field' => empty($pass1) ? 'pass1' : 'pass2',
'code' => 'missing_password'
]);
}
if ($pass1 !== $pass2) {
wp_send_json_error([
'message' => 'Passwords do not match',
'field' => 'pass2',
'code' => 'password_mismatch'
]);
}
// Verify reset key
$user = check_password_reset_key($key, $login);
if (is_wp_error($user)) {
wp_send_json_error([
'message' => 'Invalid or expired reset link',
'code' => 'invalid_key'
]);
}
// Reset password
reset_password($user, $pass1);
wp_send_json_success([
'message' => 'Password reset successfully',
'redirect' => home_url('/login')
]);
}
/**********************************************************************
TOKEN PROCESSING
**********************************************************************/
protected function processTokenHandlers(int $user_id, string $email): void
{
foreach ($this->tokenHandlers as $priority => $handlers) {
foreach ($handlers as $token_key => $handler) {
if (isset($_POST[$token_key]) || isset($_GET[$token_key])) {
$token_value = $_POST[$token_key] ?? $_GET[$token_key];
call_user_func($handler, sanitize_text_field($token_value), $email, $user_id);
}
}
}
}
/***********************************************************************
EMAIL SENDING
***********************************************************************/
protected function sendWelcomeEmail(int $user_id): void
{
$user = get_userdata($user_id);
if (!$user) {
return;
}
// Generate password reset key
$key = get_password_reset_key($user);
if (is_wp_error($key)) {
error_log('Failed to generate password reset key: ' . $key->get_error_message());
return;
}
$reset_url = add_query_arg([
'action' => 'rp',
'key' => $key,
'login' => rawurlencode($user->user_login)
], home_url('/login'));
$subject = $this->labels['email'] ?? 'Welcome to ' . get_bloginfo('name');
$message = 'Welcome, ' . esc_html($user->display_name) . '!
';
$message .= 'Your account has been created. Click the button below to set your password and get started:
';
$message .= jvbMailButton($reset_url, 'Set Your Password');
$message .= 'This link expires in 24 hours.
';
$this->emailManager->sendEmail($user->user_email, $subject, $message);
}
/*************************************************************************
* SECURITY & VALIDATION
*************************************************************************/
protected function checkAjaxRateLimit(string $action): bool
{
return $this->rateLimiter->checkLimit($action);
}
protected function checkRequestId(): bool
{
$request_id = $_POST['request_id'] ?? '';
if (empty($request_id)) {
return true; // No request_id provided, allow (for backward compat)
}
$cache_key = 'request_' . $request_id;
if (get_transient($cache_key)) {
return false; // Duplicate request
}
// Store request ID for 1 minute to prevent duplicates
set_transient($cache_key, true, 60);
return true;
}
protected function maybeTurnstile(): void
{
if (!Features::hasIntegration('cloudflare')) {
return;
}
JVB()->connect('cloudflare')->renderTurnstile();
}
protected function maybeTurnstileScripts(): void
{
if (!Features::hasIntegration('cloudflare')) {
return;
}
JVB()->connect('cloudflare')->enqueueTurnstileScripts();
}
protected function verifyTurnstile(): bool
{
if (!Features::hasIntegration('cloudflare')) {
return true; // Not enabled, pass verification
}
$token = $_POST['cf-turnstile-response'] ?? '';
if (empty($token)) {
return false;
}
return JVB()->connect('cloudflare')->verifyTurnstile($token);
}
/************************************************************************
LABELS & UI
************************************************************************/
protected function setupLabels(): void
{
$default = $this->getDefaultLabels();
$this->labels = apply_filters('jvbLoginLabels', $default, $_GET);
foreach (['description', 'footer', 'extra'] as $location) {
$text = (!is_array($this->labels[$location])) ? [$this->labels[$location]] : $this->labels[$location];
if (!empty($text)) {
$this->labels[$location] = '';
foreach ($text as $d) {
$this->labels[$location] .= '
'.$d.'
';
}
$this->labels[$location] .= '
';
}
}
}
protected function getDefaultLabels(): array
{
switch ($this->action) {
case 'register':
return [
'title' => JVB_LOGIN['register']['title'] ?? 'Create Your Account',
'description' => JVB_LOGIN['register']['description'] ?? [],
'extra' => JVB_LOGIN['register']['extra'] ?? [],
'footer' => JVB_LOGIN['register']['footer'] ?? '',
'email' => JVB_LOGIN['register']['email']['subject'] ?? '['.get_bloginfo('name').'] Finish Creating Your Account',
'submit' => JVB_LOGIN['register']['submit'] ?? 'Create Account',
'successTitle' => JVB_LOGIN['register']['success']['title'] ?? 'Success!',
'successDescription' => JVB_LOGIN['register']['success']['description'] ?? ['See your email for next steps','(Check your spam folder if you cannot find it after a couple minutes.)'],
];
case 'lostpassword':
return [
'title' => JVB_LOGIN['forgot_password']['title'] ?? 'Reset Password',
'description' => JVB_LOGIN['forgot_password']['description'] ?? [],
'extra' => JVB_LOGIN['forgot_password']['extra'] ?? [],
'footer' => JVB_LOGIN['forgot_password']['footer'] ?? '',
'submit' => JVB_LOGIN['forgot_password']['submit'] ?? 'Send Reset Link',
'successTitle' => JVB_LOGIN['forgot_password']['success']['title'] ?? 'Success!',
'successDescription' => JVB_LOGIN['forgot_password']['success']['description'] ?? ['Check your email for reset instructions'],
];
case 'resetpass':
return [
'title' => JVB_LOGIN['reset_pass']['title'] ?? 'Reset Your Password',
'description' => JVB_LOGIN['reset_pass']['description'] ?? [],
'extra' => JVB_LOGIN['reset_pass']['extra'] ?? [],
'footer' => JVB_LOGIN['reset_pass']['footer'] ?? '',
'submit' => JVB_LOGIN['reset_pass']['submit'] ?? 'Reset Password',
];
case 'login':
default:
return [
'title' => JVB_LOGIN['login']['title'] ?? 'Sign in',
'description' => JVB_LOGIN['login']['description'] ?? [],
'extra' => JVB_LOGIN['login']['extra'] ?? [],
'footer' => JVB_LOGIN['login']['footer'] ?? '',
'submit' => JVB_LOGIN['login']['submit'] ?? 'Sign In',
];
}
}
protected function maybeMagicLink(): void
{
if (!$this->magicLink || !in_array($this->action, ['login', 'lostpassword'])) {
return;
}
?>
isLoginPage()) {
return;
}
$this->maybeTurnstileScripts();
wp_enqueue_script('jvb-form');
$script = "
document.addEventListener('DOMContentLoaded', () => {
const form = document.querySelector('.login form');
if (form && window.jvbForm) {
let controller = new window.jvbForm();
controller.registerForm(form, {
autosave: false,
endpoint: false
});
} else if (form && !window.jvbForm) {
console.error('jvbForm not loaded');
}
});";
wp_add_inline_script('jvb-form', $script);
}
/*************************************************************************
SUCCESS HANDLING
*************************************************************************/
public function handleSuccessfulLogin(string $username, WP_User $user): void
{
if (isOurPeople() && !user_can($user, 'manage_options')) {
wp_redirect(get_home_url(null, '/dash'));
exit;
}
}
/**
* Handle login errors
*/
protected function handleLoginError(WP_Error $error): void
{
$login_url = wp_login_url();
$login_url = add_query_arg('login_error', urlencode($error->get_error_code()), $login_url);
if (isset($_REQUEST['redirect_to'])) {
$login_url = add_query_arg('redirect_to', urlencode($_REQUEST['redirect_to']), $login_url);
}
wp_safe_redirect($login_url);
exit;
}
}
// Initialize the login manager
new LoginManager();