Escape everything that should be escaped. Add nonce checks where needed. Sanitize all inputs. Apply Code style changes across the codebase. Correct many deprecation notices. Optimize load order of many filters.
659 lines
17 KiB
PHP
659 lines
17 KiB
PHP
<?php
|
|
/**
|
|
* Handles registration pages and such.
|
|
*
|
|
* @package WP_Ultimo
|
|
* @subpackage Checkout
|
|
* @since 2.0.0
|
|
*/
|
|
|
|
namespace WP_Ultimo\Checkout;
|
|
|
|
// Exit if accessed directly
|
|
defined('ABSPATH') || exit;
|
|
|
|
/**
|
|
* Handles registration pages and such.
|
|
*
|
|
* @since 2.0.0
|
|
*/
|
|
class Checkout_Pages {
|
|
|
|
use \WP_Ultimo\Traits\Singleton;
|
|
|
|
/**
|
|
* Initializes the Checkout_Pages singleton and adds hooks.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function init(): void {
|
|
|
|
add_filter('display_post_states', [$this, 'add_wp_ultimo_status_annotation'], 10, 2);
|
|
|
|
add_action('wu_thank_you_site_block', [$this, 'add_verify_email_notice'], 10, 3);
|
|
|
|
add_shortcode('wu_confirmation', [$this, 'render_confirmation_page']);
|
|
|
|
add_filter('lostpassword_redirect', [$this, 'filter_lost_password_redirect']);
|
|
|
|
if (is_main_site()) {
|
|
add_action('before_signup_header', [$this, 'redirect_to_registration_page']);
|
|
|
|
$use_custom_login = wu_get_setting('enable_custom_login_page', false);
|
|
|
|
if ( ! $use_custom_login) {
|
|
return;
|
|
}
|
|
|
|
add_filter('login_url', [$this, 'filter_login_url'], 10, 3);
|
|
|
|
add_filter('lostpassword_url', [$this, 'filter_login_url'], 10, 3);
|
|
|
|
add_filter('retrieve_password_message', [$this, 'replace_reset_password_link'], 10, 4);
|
|
|
|
add_filter('network_site_url', [$this, 'maybe_change_wp_login_on_urls']);
|
|
|
|
add_action('login_init', [$this, 'maybe_obfuscate_login_url'], 9);
|
|
|
|
add_action('template_redirect', [$this, 'maybe_redirect_to_admin_panel']);
|
|
|
|
add_action('after_password_reset', [$this, 'maybe_redirect_to_confirm_screen']);
|
|
|
|
add_action('lost_password', [$this, 'maybe_handle_password_reset_errors']);
|
|
|
|
add_action('validate_password_reset', [$this, 'maybe_handle_password_reset_errors']);
|
|
|
|
/**
|
|
* Adds the force elements controls.
|
|
*/
|
|
add_action('post_submitbox_misc_actions', [$this, 'render_compat_mode_setting']);
|
|
|
|
add_action('save_post', [$this, 'handle_compat_mode_setting']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filters the lost password redirect URL.
|
|
*
|
|
* @param string $redirect_to The redirect URL.
|
|
*/
|
|
public function filter_lost_password_redirect(string $redirect_to): string {
|
|
|
|
if ( ! empty($redirect_to)) {
|
|
return $redirect_to;
|
|
}
|
|
|
|
$redirect_to = add_query_arg('checkemail', 'confirm', wp_login_url());
|
|
|
|
return $redirect_to;
|
|
}
|
|
|
|
/**
|
|
* Renders the compat mode option for pages and posts.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function render_compat_mode_setting(): void {
|
|
|
|
$post_id = get_the_ID();
|
|
|
|
$value = get_post_meta($post_id, '_wu_force_elements_loading', true);
|
|
|
|
wp_nonce_field('_wu_force_compat_' . $post_id, '_wu_force_compat');
|
|
|
|
// phpcs:disable
|
|
?>
|
|
|
|
<div class="misc-pub-section misc-pub-section-last" style="margin-top: 12px; margin-bottom: 6px; display: flex; align-items: center;">
|
|
<label for="wu-compat-mode">
|
|
<span style="display: block; font-weight: 600; margin-bottom: 3px;"><?php esc_html_e('WP Multisite WaaS Compatibility Mode', 'wp-multisite-waas'); ?></span>
|
|
<small style="display: block; line-height: 1.8em;"><?php esc_html_e('Toggle this option on if WP Multisite WaaS elements are not loading correctly or at all.', 'wp-multisite-waas'); ?></small>
|
|
</label>
|
|
<div style="margin-left: 6px;">
|
|
<input id="wu-compat-mode" type="checkbox" value="1" <?php checked($value, true, true); ?> name="_wu_force_elements_loading" />
|
|
</div>
|
|
</div>
|
|
|
|
<?php
|
|
|
|
// phpcs:enable
|
|
}
|
|
|
|
/**
|
|
* Handles saving the compat mode switch on posts.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param int $post_id The id of the post being saved.
|
|
* @return void
|
|
*/
|
|
public function handle_compat_mode_setting($post_id): void {
|
|
|
|
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
|
|
return;
|
|
}
|
|
|
|
if ( ! isset($_POST['_wu_force_compat']) || ! wp_verify_nonce($_POST['_wu_force_compat'], '_wu_force_compat_' . $post_id)) {
|
|
return;
|
|
}
|
|
|
|
if ( ! current_user_can('edit_post', $post_id)) {
|
|
return;
|
|
}
|
|
|
|
if (isset($_POST['_wu_force_elements_loading'])) {
|
|
update_post_meta($post_id, '_wu_force_elements_loading', $_POST['_wu_force_elements_loading']);
|
|
} else {
|
|
delete_post_meta($post_id, '_wu_force_elements_loading');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Replace wp-login.php in email URLs.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param string $url The URL to filter.
|
|
* @return string
|
|
*/
|
|
public function maybe_change_wp_login_on_urls($url) {
|
|
/*
|
|
* Only perform computational-heavy tasks if the URL has
|
|
* wp-login.php in it to begin with.
|
|
*/
|
|
if (! str_contains($url, 'wp-login.php')) {
|
|
return $url;
|
|
}
|
|
|
|
$post_id = wu_get_setting('default_login_page', 0);
|
|
|
|
$post = get_post($post_id);
|
|
|
|
if ($post) {
|
|
$url = str_replace('wp-login.php', $post->post_name, $url);
|
|
}
|
|
|
|
return $url;
|
|
}
|
|
|
|
/**
|
|
* Get an error message.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param string $error_code The error code.
|
|
* @param string $username The username.
|
|
* @return string
|
|
*/
|
|
public function get_error_message($error_code, $username = '') {
|
|
|
|
$messages = [
|
|
'incorrect_password' => sprintf(__('<strong>Error:</strong> The password you entered is incorrect.', 'wp-multisite-waas')),
|
|
// From here we are using the same messages as WordPress core.
|
|
'expired' => __('Your session has expired. Please log in to continue where you left off.'),
|
|
'confirm' => sprintf(__('Check your email for the confirmation link, then visit the <a href="%s">login page</a>.'), wp_login_url()),
|
|
'registered' => sprintf(__('Registration complete. Please check your email, then visit the <a href="%s">login page</a>.'), wp_login_url()),
|
|
'loggedout' => __('You are now logged out.'),
|
|
'registerdisabled' => __('<strong>Error:</strong> User registration is currently not allowed.'),
|
|
'empty_username' => __('<strong>Error:</strong> The username field is empty.'),
|
|
'empty_password' => __('<strong>Error:</strong> The password field is empty.'),
|
|
'invalid_email' => __('Unknown email address. Check again or try your username.'),
|
|
'invalid_username' => sprintf(__('<strong>Error:</strong> The username <strong>%s</strong> is not registered on this site. If you are unsure of your username, try your email address instead.'), $username),
|
|
'invalidcombo' => __('<strong>Error:</strong> There is no account with that username or email address.'),
|
|
'password_reset_empty_space' => __('The password cannot be a space or all spaces.'),
|
|
'password_reset_mismatch' => __('<strong>Error:</strong> The passwords do not match.'),
|
|
'invalidkey' => __('<strong>Error:</strong> Your password reset link appears to be invalid. Please request a new link below.'),
|
|
'expiredkey' => __('<strong>Error:</strong> Your password reset link has expired. Please request a new link below.'),
|
|
];
|
|
|
|
/**
|
|
* Filter the error messages.
|
|
*
|
|
* @since 2.1.1
|
|
* @param array $messages The error messages.
|
|
* @return array
|
|
*/
|
|
$messages = apply_filters('wu_checkout_pages_error_messages', $messages);
|
|
|
|
return wu_get_isset($messages, $error_code, __('Something went wrong', 'wp-multisite-waas'));
|
|
}
|
|
|
|
/**
|
|
* Handle password reset errors.
|
|
*
|
|
* We redirect users to our custom login URL,
|
|
* so we can add an error message.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param \WP_Error $errors The error object.
|
|
* @return void
|
|
*/
|
|
public function maybe_handle_password_reset_errors($errors): void {
|
|
|
|
if ($errors->has_errors()) {
|
|
$url = add_query_arg(
|
|
[
|
|
'action' => wu_request('action', ''),
|
|
'user_login' => wu_request('user_login', ''),
|
|
'error' => $errors->get_error_code(),
|
|
],
|
|
wp_login_url()
|
|
);
|
|
|
|
wp_safe_redirect($url);
|
|
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Maybe redirects users to the confirm screen.
|
|
*
|
|
* If we are successful in resetting a password,
|
|
* we need to prevent the user from reaching the empty
|
|
* wp-login.php message, so we redirect them to the passed
|
|
* redirect_to query argument.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function maybe_redirect_to_confirm_screen(): void {
|
|
|
|
if (wu_request('redirect_to')) {
|
|
wp_safe_redirect(wu_request('redirect_to'));
|
|
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Replace the reset password link, if necessary.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param string $message The email message.
|
|
* @param string $key The reset key.
|
|
* @param string $user_login The user login.
|
|
* @param array $user_data The user data array.
|
|
* @return string
|
|
*/
|
|
public function replace_reset_password_link($message, $key, $user_login, $user_data) {
|
|
|
|
if ( ! is_main_site()) {
|
|
return $message;
|
|
}
|
|
|
|
$results = [];
|
|
|
|
preg_match_all('/.*\/wp-login\.php.*/', $message, $results);
|
|
|
|
$switched_locale = false;
|
|
|
|
if (isset($results[0][0])) {
|
|
|
|
// Localize password reset message content for user.
|
|
$locale = get_user_locale($user_data);
|
|
|
|
$switched_locale = switch_to_locale($locale);
|
|
|
|
$new_url = add_query_arg(
|
|
[
|
|
'action' => 'rp',
|
|
'key' => $key,
|
|
'login' => rawurlencode($user_login),
|
|
'wp_lang' => $locale,
|
|
],
|
|
wp_login_url()
|
|
);
|
|
|
|
$new_url = set_url_scheme($new_url, null);
|
|
|
|
$message = str_replace($results[0], $new_url, $message);
|
|
}
|
|
|
|
if ($switched_locale) {
|
|
restore_previous_locale();
|
|
}
|
|
|
|
return $message;
|
|
}
|
|
|
|
/**
|
|
* Redirect logged users when they reach the login page.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function maybe_redirect_to_admin_panel(): void {
|
|
|
|
global $post;
|
|
|
|
if ( ! is_user_logged_in()) {
|
|
return;
|
|
}
|
|
|
|
$custom_login_page = $this->get_signup_page('login');
|
|
|
|
if (empty($custom_login_page) || empty($post)) {
|
|
return;
|
|
}
|
|
|
|
if ($custom_login_page->ID !== $post->ID) {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Create an exclusion list of parameters that prevent the auto-redirect.
|
|
*
|
|
* This is needed because otherwise page builder won't be able to
|
|
* edit the login page once it is defined.
|
|
*
|
|
* @since 2.0.4
|
|
* @return array
|
|
*/
|
|
$exclusion_list = apply_filters(
|
|
'wu_maybe_redirect_to_admin_panel_exclusion_list',
|
|
[
|
|
'preview', // WordPress Preview
|
|
'ct_builder', // Oxygen Builder
|
|
'fl_builder', // Beaver Builder
|
|
'elementor-preview', // Elementor
|
|
'brizy-edit', // Brizy
|
|
'brizy-edit-iframe', // Brizy
|
|
],
|
|
$custom_login_page,
|
|
$post,
|
|
$this
|
|
);
|
|
|
|
foreach ($exclusion_list as $exclusion_param) {
|
|
if (wu_request($exclusion_param, null) !== null) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
$user = wp_get_current_user();
|
|
|
|
$active_blog = get_active_blog_for_user($user->ID);
|
|
|
|
$redirect_to = $active_blog ? get_admin_url($active_blog->blog_id) : false;
|
|
|
|
if (isset($_GET['redirect_to'])) {
|
|
$redirect_to = $_GET['redirect_to'];
|
|
} elseif (is_multisite() && ! get_active_blog_for_user($user->ID) && ! is_super_admin($user->ID)) {
|
|
$redirect_to = user_admin_url();
|
|
} elseif (is_multisite() && ! $user->has_cap('read')) {
|
|
$redirect_to = get_dashboard_url($user->ID);
|
|
} elseif ( ! $user->has_cap('edit_posts')) {
|
|
$redirect_to = $user->has_cap('read') ? admin_url('profile.php') : home_url();
|
|
}
|
|
|
|
if ( ! $redirect_to) {
|
|
return;
|
|
}
|
|
|
|
wp_safe_redirect($redirect_to);
|
|
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Adds the unverified email account error message.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param \WP_Ultimo\Models\Payment $payment The current payment.
|
|
* @param \WP_Ultimo\Models\Membership $membership the current membership.
|
|
* @param \WP_Ultimo\Models\Customer $customer the current customer.
|
|
* @return void
|
|
*/
|
|
public function add_verify_email_notice($payment, $membership, $customer): void {
|
|
|
|
if ($payment->get_total() == 0 && $customer->get_email_verification() === 'pending') {
|
|
$html = '<div class="wu-p-4 wu-bg-yellow-200 wu-mb-2 wu-text-yellow-700 wu-rounded">%s</div>';
|
|
|
|
$message = __('Your email address is not yet verified. Your site <strong>will only be activated</strong> after your email address is verified. Check your inbox and verify your email address.', 'wp-multisite-waas');
|
|
|
|
$message .= sprintf('<br><a href="#" class="wu-resend-verification-email wu-text-gray-700">%s</a>', __('Resend verification email →', 'wp-multisite-waas'));
|
|
|
|
printf($html, $message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if we should obfuscate the login URL.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function maybe_obfuscate_login_url(): void {
|
|
|
|
$use_custom_login = wu_get_setting('enable_custom_login_page', false);
|
|
|
|
if ( ! $use_custom_login) {
|
|
return;
|
|
}
|
|
|
|
if ('POST' === $_SERVER['REQUEST_METHOD']) {
|
|
return;
|
|
}
|
|
|
|
if (wu_request('interim-login')) {
|
|
return;
|
|
}
|
|
|
|
if (wu_request('action') === 'logout') {
|
|
return;
|
|
}
|
|
|
|
$new_login_url = $this->get_page_url('login');
|
|
|
|
if ( ! $new_login_url) {
|
|
return;
|
|
}
|
|
|
|
$should_obfuscate = wu_get_setting('obfuscate_original_login_url', 1);
|
|
|
|
$bypass_obfuscation = wu_request('wu_bypass_obfuscation');
|
|
|
|
if ($should_obfuscate && ! $bypass_obfuscation) {
|
|
status_header(404);
|
|
|
|
nocache_headers();
|
|
|
|
global $wp_query;
|
|
|
|
$wp_query->set_404();
|
|
|
|
include get_404_template();
|
|
|
|
die;
|
|
} else {
|
|
wp_safe_redirect($new_login_url);
|
|
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Redirects the customers to the registration page, when one is used.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function redirect_to_registration_page(): void {
|
|
|
|
$registration_url = $this->get_page_url('register');
|
|
|
|
if ($registration_url) {
|
|
wp_safe_redirect($registration_url);
|
|
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filters the login URL if necessary.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param string $login_url Original login URL.
|
|
* @param string $redirect URL to redirect to after login.
|
|
* @param bool $force_reauth If we need to force reauth.
|
|
* @return string
|
|
*/
|
|
public function filter_login_url($login_url, $redirect, $force_reauth = false) {
|
|
|
|
/**
|
|
* Fix incompatibility with UIPress, making sure we only filter after wp_loaded ran.
|
|
*/
|
|
if ( ! did_action('wp_loaded')) {
|
|
return $login_url;
|
|
}
|
|
|
|
$function_caller = wu_get_function_caller(5);
|
|
|
|
if ('wp_auth_check_html' === $function_caller) {
|
|
return $login_url;
|
|
}
|
|
|
|
$params = [];
|
|
|
|
$old_url_params = wp_parse_url($login_url, PHP_URL_QUERY);
|
|
|
|
wp_parse_str($old_url_params, $params);
|
|
|
|
$new_login_url = $this->get_page_url('login');
|
|
|
|
if ( ! $new_login_url) {
|
|
return $login_url;
|
|
}
|
|
|
|
if ($params) {
|
|
$new_login_url = add_query_arg($params, $new_login_url);
|
|
}
|
|
|
|
if ($redirect) {
|
|
$new_login_url = add_query_arg('redirect_to', urlencode($redirect), $new_login_url);
|
|
}
|
|
|
|
if ($force_reauth) {
|
|
$new_login_url = add_query_arg('reauth', 1, $new_login_url);
|
|
}
|
|
|
|
return $new_login_url;
|
|
}
|
|
|
|
/**
|
|
* Returns the ID of the pages being used for each WP Multisite WaaS purpose.
|
|
*
|
|
* @since 2.0.0
|
|
* @return array
|
|
*/
|
|
public function get_signup_pages() {
|
|
|
|
return [
|
|
'register' => wu_guess_registration_page(),
|
|
'update' => wu_get_setting('default_update_page', false),
|
|
'login' => wu_get_setting('default_login_page', false),
|
|
'block_frontend' => wu_get_setting('default_block_frontend_page', false),
|
|
'new_site' => wu_get_setting('default_new_site_page', false),
|
|
];
|
|
}
|
|
/**
|
|
* Returns the WP_Post object for one of the pages.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param string $page The slug of the page to retrieve.
|
|
* @return \WP_Post|false
|
|
*/
|
|
public function get_signup_page($page) {
|
|
|
|
$pages = $this->get_signup_pages();
|
|
|
|
$page_id = wu_get_isset($pages, $page);
|
|
|
|
if ( ! $page_id) {
|
|
return false;
|
|
}
|
|
|
|
return get_blog_post(wu_get_main_site_id(), $page_id);
|
|
}
|
|
/**
|
|
* Returns the URL for a particular page type.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param string $page_slug The signup page to get.
|
|
* @return string|false
|
|
*/
|
|
public function get_page_url($page_slug = 'login') {
|
|
|
|
$page = $this->get_signup_page($page_slug);
|
|
|
|
if ( ! $page) {
|
|
return false;
|
|
}
|
|
|
|
return wu_switch_blog_and_run(fn() => get_the_permalink($page));
|
|
}
|
|
|
|
/**
|
|
* Tags the WP Multisite WaaS pages on the main site.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param array $states The previous states of that page.
|
|
* @param \WP_Post $post The current post.
|
|
* @return array
|
|
*/
|
|
public function add_wp_ultimo_status_annotation($states, $post) {
|
|
|
|
if ( ! is_main_site()) {
|
|
return $states;
|
|
}
|
|
|
|
$labels = [
|
|
'register' => __('WP Multisite WaaS - Register Page', 'wp-multisite-waas'),
|
|
'login' => __('WP Multisite WaaS - Login Page', 'wp-multisite-waas'),
|
|
'block_frontend' => __('WP Multisite WaaS - Site Blocked Page', 'wp-multisite-waas'),
|
|
'update' => __('WP Multisite WaaS - Membership Update Page', 'wp-multisite-waas'),
|
|
'new_site' => __('WP Multisite WaaS - New Site Page', 'wp-multisite-waas'),
|
|
];
|
|
|
|
$pages = array_map('absint', $this->get_signup_pages());
|
|
|
|
if (in_array($post->ID, $pages, true)) {
|
|
$key = array_search($post->ID, $pages, true);
|
|
|
|
$states['wp_ultimo_page'] = wu_get_isset($labels, $key);
|
|
}
|
|
|
|
return $states;
|
|
}
|
|
|
|
/**
|
|
* Renders the confirmation page.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param array $atts Shortcode attributes.
|
|
* @param null|string $content The post content.
|
|
* @return string
|
|
*/
|
|
public function render_confirmation_page($atts, $content = null) {
|
|
|
|
return wu_get_template_contents(
|
|
'checkout/confirmation',
|
|
[
|
|
'errors' => Checkout::get_instance()->errors,
|
|
'membership' => wu_get_membership_by_hash(wu_request('membership')),
|
|
]
|
|
);
|
|
}
|
|
}
|