Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions assets/js/login-ajax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
(function($) {
'use strict';

/**
* AJAX Login Form Handler
*
* This script converts the standard WordPress login form to use AJAX
* to bypass caching issues and provide better feedback to users.
*/
$(document).ready(function() {

// Only run on the login form
if (!$('.wu-login-form').length) {
return;
}

// Add a class to identify our form
$('.wu-login-form form').addClass('wu-ajax-login-form');

// Handle form submission
$(document).on('submit', '.wu-ajax-login-form', function(e) {
e.preventDefault();

var $form = $(this);
var $submitButton = $form.find('input[type="submit"]');
var $errorContainer = $('<div class="wu-login-error wu-p-4 wu-bg-red-100 wu-text-red-700 wu-rounded wu-mb-4" style="display:none;"></div>');

// Remove any existing error messages
$('.wu-login-error').remove();

// Add the error container
$form.prepend($errorContainer);

// Disable the submit button and show loading state
$submitButton.prop('disabled', true).val('Logging in...');

// Get form data
var formData = $form.serialize();

// Add a nonce for security
formData += '&security=' + wu_login_ajax.nonce;

// Send the AJAX request
$.ajax({
type: 'POST',
dataType: 'json',
url: wu_login_ajax.ajax_url,
data: {
action: 'wu_ajax_login',
data: formData
},
success: function(response) {
if (response.success) {
// Login successful - redirect
window.location.href = response.data.redirect;
} else {
// Show error message
$errorContainer.html(response.data.message).slideDown();
$submitButton.prop('disabled', false).val('Log In');
}
},
error: function() {
// Show generic error message
$errorContainer.html('An error occurred. Please try again.').slideDown();
$submitButton.prop('disabled', false).val('Log In');
}
});
});
});

})(jQuery);
1 change: 1 addition & 0 deletions assets/js/login-ajax.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 54 additions & 0 deletions docs/emergency-login.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Emergency Login Feature

The Emergency Login feature provides a way to access the WordPress login page directly, bypassing any custom login page redirections or Single Sign-On (SSO) mechanisms. This is particularly useful for administrators who need to access the WordPress admin area when the custom login page is not working properly.

## How to Use

To use the Emergency Login feature, add the `emergency_login=1` parameter to your WordPress login URL:

```
https://example.com/wp-login.php?emergency_login=1
```

This will bypass:
- Redirections to the custom login page
- SSO authentication flows
- Caching mechanisms that might interfere with login

## When to Use

Use the Emergency Login feature in the following situations:

1. When you're unable to log in through the custom login page
2. When you need to troubleshoot login issues
3. When you're locked out of your site due to redirection loops
4. When caching plugins are interfering with the login process

## Security Considerations

The Emergency Login feature is designed for administrators and site owners. While it doesn't bypass WordPress authentication (you still need valid credentials), it does bypass custom login page redirections.

Consider implementing additional security measures:

1. Use strong passwords for administrator accounts
2. Implement two-factor authentication
3. Limit login attempts
4. Monitor login activity

## Troubleshooting

If you're experiencing login issues even with the Emergency Login feature:

1. Clear your browser cache and cookies
2. Try using a different browser
3. Disable caching plugins temporarily
4. Check for JavaScript errors in your browser console

## Related Settings

The Emergency Login feature works alongside the following WP Ultimo settings:

- **Custom Login Page**: Found under Settings > Login & Registration
- **Obfuscate Original Login URL**: Found under Settings > Login & Registration

Even when these settings are enabled, the Emergency Login parameter will allow direct access to the WordPress login page.
5 changes: 5 additions & 0 deletions inc/checkout/class-checkout-pages.php
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,11 @@ public function maybe_obfuscate_login_url(): void {
return;
}

// Emergency login bypass - allows direct access to wp-login.php
if (wu_request('emergency_login')) {
return;
}

$new_login_url = $this->get_page_url('login');

if ( ! $new_login_url) {
Expand Down
58 changes: 58 additions & 0 deletions inc/class-ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public function __construct() {
* Load search endpoints.
*/
add_action('wp_ajax_wu_list_table_fetch_ajax_results', [$this, 'refresh_list_table']);

/*
* AJAX Login handler
*/
add_action('wp_ajax_nopriv_wu_ajax_login', [$this, 'handle_ajax_login']);
}

/**
Expand Down Expand Up @@ -414,4 +419,57 @@ public function render_selectize_templates(): void {
wu_get_template('ui/selectize-templates');
}
}

/**
* Handles AJAX login requests.
*
* @since 2.0.0
* @return void
*/
public function handle_ajax_login(): void {
// Check nonce
if (!check_ajax_referer('wu-ajax-login-nonce', 'security', false)) {
wp_send_json_error(array(
'message' => __('Security check failed. Please refresh the page and try again.', 'wp-multisite-waas')
));
}

// Parse the form data
$form_data = array();
parse_str($_POST['data'], $form_data);

// Check for required fields
if (empty($form_data['log']) || empty($form_data['pwd'])) {
wp_send_json_error(array(
'message' => __('Username and password are required.', 'wp-multisite-waas')
));
}

// Prevent caching
wu_no_cache();

// Attempt to log the user in
$credentials = array(
'user_login' => $form_data['log'],
'user_password' => $form_data['pwd'],
'remember' => isset($form_data['rememberme'])
);

$user = wp_signon($credentials, is_ssl());

// Check for errors
if (is_wp_error($user)) {
wp_send_json_error(array(
'message' => $user->get_error_message()
));
}

// Determine redirect URL
$redirect_to = !empty($form_data['redirect_to']) ? $form_data['redirect_to'] : admin_url();

// Success response
wp_send_json_success(array(
'redirect' => $redirect_to
));
}
}
6 changes: 6 additions & 0 deletions inc/class-wp-ultimo.php
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ public function load_public_apis(): void {
require_once wu_path('inc/functions/generator.php');
require_once wu_path('inc/functions/color.php');
require_once wu_path('inc/functions/danger.php');
require_once wu_path('inc/functions/transients.php');

/*
* Admin helper functions
Expand Down Expand Up @@ -908,6 +909,11 @@ protected function load_managers(): void {
*/
WP_Ultimo\Managers\Cache_Manager::get_instance();

/*
* Loads the Transient manager.
*/
WP_Ultimo\Managers\Transient_Manager::get_instance();

/**
* Loads views overrides
*/
Expand Down
95 changes: 95 additions & 0 deletions inc/functions/transients.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/**
* Transient Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/

// Exit if accessed directly
defined('ABSPATH') || exit;

/**
* Sets a transient and registers it with the transient manager.
*
* @since 2.0.0
* @param string $transient_name The name of the transient.
* @param mixed $value The value to store.
* @param int $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
* @param string $group Optional. The group the transient belongs to. Default 'general'.
* @return bool True if the transient was set, false otherwise.
*/
function wu_set_transient($transient_name, $value, $expiration = 0, $group = 'general') {

return \WP_Ultimo\Managers\Transient_Manager::get_instance()->set_transient($transient_name, $value, $expiration, $group);
}

/**
* Gets a transient value.
*
* @since 2.0.0
* @param string $transient_name The name of the transient.
* @return mixed The value of the transient or false if it doesn't exist.
*/
function wu_get_transient($transient_name) {

return \WP_Ultimo\Managers\Transient_Manager::get_instance()->get_transient($transient_name);
}

/**
* Deletes a transient.
*
* @since 2.0.0
* @param string $transient_name The name of the transient.
* @return bool True if the transient was deleted, false otherwise.
*/
function wu_delete_transient($transient_name) {

return \WP_Ultimo\Managers\Transient_Manager::get_instance()->delete_transient($transient_name);
}

/**
* Deletes all transients in a group.
*
* @since 2.0.0
* @param string $group The group of transients to delete.
* @return bool True if all transients were deleted, false otherwise.
*/
function wu_delete_transients_by_group($group) {

return \WP_Ultimo\Managers\Transient_Manager::get_instance()->delete_transients_by_group($group);
}

/**
* Deletes all transients.
*
* @since 2.0.0
* @return bool True if all transients were deleted, false otherwise.
*/
function wu_delete_transients() {

return \WP_Ultimo\Managers\Transient_Manager::get_instance()->delete_transients();
}

/**
* Gets all registered transients.
*
* @since 2.0.0
* @return array The list of registered transients.
*/
function wu_get_registered_transients() {

return \WP_Ultimo\Managers\Transient_Manager::get_instance()->get_registered_transients();
}

/**
* Gets all registered transients in a group.
*
* @since 2.0.0
* @param string $group The group of transients to get.
* @return array The list of registered transients in the group.
*/
function wu_get_registered_transients_by_group($group) {

return \WP_Ultimo\Managers\Transient_Manager::get_instance()->get_registered_transients_by_group($group);
}
Loading