get_current_user_login_url(); $parsed_url = wp_parse_url( $redirect_to ); $query = isset( $parsed_url['query'] ) ? '?' . $parsed_url['query'] : ''; return $custom_url . $query; } return $redirect_to; } public function filter_lostpassword_redirect_url( $location, $status ) { if ( strpos( $location, 'wp-login.php' ) !== false && ( strpos( $location, 'checkemail=' ) !== false || strpos( $location, 'action=lostpassword' ) !== false ) ) { $custom_url = $this->get_current_user_login_url(); $parsed_url = wp_parse_url( $location ); $query = isset( $parsed_url['query'] ) ? '?' . $parsed_url['query'] : ''; return $custom_url . $query; } return $location; } public function plugins_loaded() { if ( ! is_user_logged_in() ) { remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 ); } } /** * Validate that admin custom login URL is set if custom login is enabled */ public function validate_admin_custom_login_url() { if ( ! is_admin() ) { return; } $settings = get_option( 'ADALC_settings', array() ); $enabled = isset( $settings['enable_custom_login'] ) ? $settings['enable_custom_login'] : 0; $admin_url = isset( $settings['role_slugs']['administrator'] ) ? trim( $settings['role_slugs']['administrator'] ) : ''; if ( $enabled && empty( $admin_url ) ) { echo '

AccessDoor: Administrator custom login URL is required when custom login is enabled. Please set it in plugin settings.

'; } } /** * Set intended role cookie/session before sending reset password link */ public function set_intended_role_for_reset_link() { if ( isset( $_POST['user_login'] ) ) { $user_login = sanitize_text_field( $_POST['user_login'] ); $user = get_user_by( 'login', $user_login ); if ( ! $user ) { $user = get_user_by( 'email', $user_login ); } if ( $user ) { $roles = (array) $user->roles; foreach ( $roles as $role ) { if ( $this->get_role_login_url( $role ) ) { setcookie( 'ADALC_intended_role', $role, time() + 3600, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true ); $_COOKIE['ADALC_intended_role'] = $role; if ( ! session_id() ) { session_start(); } $_SESSION['ADALC_intended_role'] = $role; break; } } } } } public function accessdoor_modify_password_reset_link( $message, $key, $user_login, $user_data ) { $roles = (array) $user_data->roles; $user_role = $roles[0] ?? ''; $custom_login_url = $this->get_role_login_url( $user_role ); if( ! $custom_login_url ){ $custom_login_url = $this->get_current_user_login_url(); } // Build new reset link $new_link = add_query_arg( array( 'action' => 'rp', 'key' => $key, 'login' => rawurlencode( $user_login ), ), $custom_login_url ); // Replace the default reset link in email body $message = preg_replace( '#https?://[^\s]+#', $new_link, $message ); return $message; } /** * Handle custom login page request based on role - DIRECTLY SHOW LOGIN FORM. */ public function handle_custom_login() { $login_role = get_query_var( 'ADALC_login_role' ); if ( ! $login_role ) { return; } // Validate that this is a valid role. if ( ! wp_roles()->is_role( $login_role ) ) { status_header( 404 ); nocache_headers(); include( get_query_template( '404' ) ); exit; } // Store the intended role in cookie for validation during login. setcookie( 'ADALC_intended_role', $login_role, time() + 3600, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true ); $_COOKIE['ADALC_intended_role'] = $login_role; // Set for immediate use. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized // Also store in session as backup. if ( ! session_id() ) { session_start(); } $_SESSION['ADALC_intended_role'] = $login_role; $_SESSION['ADALC_current_login_url'] = home_url( get_query_var( 'pagename' ) ); // Set nocache headers. nocache_headers(); // Initialize variables expected by wp-login.php to prevent warnings. $user_login = ''; $user_email = ''; $redirect_to = ''; $error = ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $action = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( $_REQUEST['action'] ) ) : 'login'; // DIRECTLY load wp-login.php to show the login form. require_once ABSPATH . 'wp-login.php'; exit; } /** * Validate user role BEFORE login completes (during authentication). * * @param WP_User|WP_Error|null $user WP_User if authenticated, WP_Error on failure, null if not processed. * @param string $username Username or email address. * @param string $password User password. * @return WP_User|WP_Error User object on success, WP_Error on failure. */ public function validate_user_role_before_login( $user, $username, $password ) { // Only validate if user authentication was successful. if ( ! is_wp_error( $user ) && $user instanceof WP_User ) { // Get intended role from cookie or session. $intended_role = null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( isset( $_COOKIE['ADALC_intended_role'] ) ) { $intended_role = sanitize_key( $_COOKIE['ADALC_intended_role'] ); } elseif ( ! empty( $_SESSION['ADALC_intended_role'] ) ) { $intended_role = sanitize_key( $_SESSION['ADALC_intended_role'] ); } // Check if user is logging in via role-specific URL. if ( $intended_role ) { $user_roles = (array) $user->roles; // Check if user has the required role. if ( ! in_array( $intended_role, $user_roles, true ) ) { // Get all allowed login URLs for this user $allowed_urls = array(); foreach ( $user_roles as $role ) { $url = $this->get_role_login_url( $role ); if ( $url ) { $allowed_urls[] = trailingslashit( $url ); } } // Get the current URL being accessed $current_url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; $current_url = strtok( $current_url, '?' ); // Remove query string for strict match $current_url = trailingslashit( $current_url ); // If current URL is not in allowed URLs, block login if ( ! empty( $allowed_urls ) && ! in_array( $current_url, $allowed_urls, true ) ) { setcookie( 'ADALC_intended_role', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN ); if ( isset( $_SESSION['ADALC_intended_role'] ) ) { unset( $_SESSION['ADALC_intended_role'] ); } return new WP_Error( 'invalid_role_login', sprintf( __( 'ERROR: You do not have permission to login via this URL. Please use your designated login page.', 'accessdoor-smart-admin-login-url-control' ) ) ); } } // Role is valid - clear the cookie and session after validation. setcookie( 'ADALC_intended_role', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN ); if ( isset( $_SESSION['ADALC_intended_role'] ) ) { unset( $_SESSION['ADALC_intended_role'] ); } } } return $user; } /** * Get login URL for specific role. * * @param string $role Role slug. * @return string|false Login URL or false if not set. */ public function get_role_login_url( $role ) { $settings = get_option( 'ADALC_settings', array() ); if ( isset( $settings['role_slugs'][ $role ] ) && ! empty( $settings['role_slugs'][ $role ] ) ) { return home_url( $settings['role_slugs'][ $role ] ); } return false; } /** * Get login URL for current user or from session/cookie. * * @return string Login URL. */ public function get_current_user_login_url() { // First check if there's an intended role in cookie/session (during login attempt). // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( isset( $_COOKIE['ADALC_intended_role'] ) ) { $intended_role = sanitize_key( $_COOKIE['ADALC_intended_role'] ); $url = $this->get_role_login_url( $intended_role ); if ( $url ) { return $url; } } if ( ! empty( $_SESSION['ADALC_intended_role'] ) ) { $intended_role = sanitize_key( $_SESSION['ADALC_intended_role'] ); $url = $this->get_role_login_url( $intended_role ); if ( $url ) { return $url; } } // Then check if user is logged in. if ( is_user_logged_in() ) { $user = wp_get_current_user(); $roles = (array) $user->roles; // Try to get URL for user's first role. foreach ( $roles as $role ) { $url = $this->get_role_login_url( $role ); if ( $url ) { return $url; } } } // Fallback to first available role login URL. $settings = get_option( 'ADALC_settings', array() ); if ( isset( $settings['role_slugs'] ) && is_array( $settings['role_slugs'] ) ) { foreach ( $settings['role_slugs'] as $role => $slug ) { if ( ! empty( $slug ) ) { return home_url( $slug ); } } } return wp_login_url(); } /** * Filter login URL to use custom slug based on context. * * @param string $login_url The login URL. * @param string $redirect The redirect URL. * @param bool $force_reauth Whether to force reauth. * @return string Modified login URL. */ public function filter_login_url( $login_url, $redirect = '', $force_reauth = false ) { $settings = get_option( 'ADALC_settings', array() ); $enabled = isset( $settings['enable_custom_login'] ) ? $settings['enable_custom_login'] : 0; if ( ! $enabled ) { return $login_url; } // Check if any custom login URLs exist. $has_custom_urls = false; if ( isset( $settings['role_slugs'] ) && is_array( $settings['role_slugs'] ) ) { foreach ( $settings['role_slugs'] as $slug ) { if ( ! empty( $slug ) ) { $has_custom_urls = true; break; } } } // If no custom URLs configured, allow default wp-login/wp-admin access. if ( ! $has_custom_urls ) { return $login_url; } // If redirect is to wp-admin and no cookies set, redirect to configured redirect URL instead. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( ! empty( $redirect ) && strpos( $redirect, 'wp-admin' ) !== false && ! isset( $_COOKIE['ADALC_intended_role'] ) ) { $redirect_enabled = isset( $settings['redirect_wp_login'] ) ? $settings['redirect_wp_login'] : 1; if ( $redirect_enabled ) { $redirect_url = isset( $settings['redirect_url'] ) ? $settings['redirect_url'] : home_url(); wp_safe_redirect( $redirect_url, 302 ); exit; } else { status_header( 404 ); nocache_headers(); include( get_query_template( '404' ) ); exit; } } // Get appropriate login URL. $custom_url = $this->get_current_user_login_url(); if ( $redirect ) { $custom_url = add_query_arg( 'redirect_to', urlencode( $redirect ), $custom_url ); } if ( $force_reauth ) { $custom_url = add_query_arg( 'reauth', '1', $custom_url ); } return $custom_url; } /** * Filter site URL to replace wp-login.php references. * * @param string $url The complete site URL. * @param string $path Path relative to the site URL. * @param string|null $scheme The scheme to use. * @param int|null $blog_id The blog ID. * @return string Modified URL. */ public function filter_site_url( $url, $path, $scheme, $blog_id = null) { if ( $blog_id === null && is_multisite() ) { $blog_id = get_current_blog_id(); } static $in_filter = false; if ( $in_filter ) { return $url; } $in_filter = true; $settings = get_option( 'ADALC_settings', array() ); $enabled = isset( $settings['enable_custom_login'] ) ? $settings['enable_custom_login'] : 0; if ( ! $enabled || strpos( $url, 'wp-login.php' ) === false ) { $in_filter = false; return $url; } // Get custom login URL. $custom_url = $this->get_current_user_login_url(); // Parse the original URL to preserve query parameters. $parsed_url = wp_parse_url( $url ); $query = isset( $parsed_url['query'] ) ? '?' . $parsed_url['query'] : ''; // If checkemail or other login actions, keep the query string $in_filter = false; return $custom_url . $query; } /** * Store user role before logout for proper redirect. */ public function store_user_role_before_logout() { if ( is_user_logged_in() ) { $user = wp_get_current_user(); $roles = (array) $user->roles; // Store the first role that has a custom login URL. foreach ( $roles as $role ) { if ( $this->get_role_login_url( $role ) ) { setcookie( 'ADALC_logout_role', $role, time() + 60, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true ); $_COOKIE['ADALC_logout_role'] = $role; break; } } } } /** * Clear all login-related cookies and sessions on logout. */ public function clear_login_cookies_on_logout() { $settings = get_option( 'ADALC_settings', array() ); $enabled = isset( $settings['enable_custom_login'] ) ? $settings['enable_custom_login'] : 0; if ( ! $enabled ) { return; } // Clear intended role cookie. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( isset( $_COOKIE['ADALC_intended_role'] ) ) { setcookie( 'ADALC_intended_role', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true ); unset( $_COOKIE['ADALC_intended_role'] ); } // Clear session data. if ( session_id() ) { if ( isset( $_SESSION['ADALC_intended_role'] ) ) { unset( $_SESSION['ADALC_intended_role'] ); } if ( isset( $_SESSION['ADALC_current_login_url'] ) ) { unset( $_SESSION['ADALC_current_login_url'] ); } } wp_safe_redirect( home_url() ); exit; } /** * Redirect user to their role-specific login URL after logout. * * @param string $redirect_to The redirect destination URL. * @param string $requested_redirect_to The requested redirect destination URL. * @param WP_User|null $user The WP_User object for the user being logged out. * @return string Modified redirect URL. */ public function logout_redirect( $redirect_to, $requested_redirect_to, $user ) { $settings = get_option( 'ADALC_settings', array() ); $enabled = isset( $settings['enable_custom_login'] ) ? $settings['enable_custom_login'] : 0; if ( ! $enabled ) { return $redirect_to; } // Check if we stored a role before logout. // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized // if ( isset( $_COOKIE['ADALC_logout_role'] ) ) { // $logout_role = sanitize_key( $_COOKIE['ADALC_logout_role'] ); // $custom_url = $this->get_role_login_url( $logout_role ); // // Clear the logout role cookie. // setcookie( 'ADALC_logout_role', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true ); // unset( $_COOKIE['ADALC_logout_role'] ); // if ( $custom_url ) { // return $custom_url; // } // } // // Fallback: check if user object is available. // if ( $user instanceof WP_User ) { // $roles = (array) $user->roles; // $custom_url = false; // foreach ( $roles as $role ) { // $custom_url = $this->get_role_login_url( $role ); // if ( $custom_url ) { // return $custom_url; // } // } // // If no slug for any user role, try admin custom slug // if ( isset( $settings['role_slugs']['administrator'] ) && ! empty( $settings['role_slugs']['administrator'] ) ) { // return home_url( $settings['role_slugs']['administrator'] ); // } // } return home_url(); // Final fallback to redirect URL setting or home. // return isset( $settings['redirect_url'] ) ? $settings['redirect_url'] : home_url(); } /** * Block access to default wp-login.php. */ public function block_default_login() { $settings = get_option( 'ADALC_settings', array() ); $enabled = isset( $settings['enable_custom_login'] ) ? $settings['enable_custom_login'] : 0; if ( ! $enabled ) { return; } $redirect = isset( $settings['redirect_wp_login'] ) ? $settings['redirect_wp_login'] : 1; // Allow access for logged in users and AJAX/REST requests. if ( is_user_logged_in() || wp_doing_ajax() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || ( defined( 'WP_CLI' ) && WP_CLI ) ) { return; } // Check if accessing wp-login.php or wp-admin directly. global $pagenow; $is_wp_login = ( 'wp-login.php' === $pagenow ); $is_wp_admin = ( 'admin.php' === $pagenow || 'index.php' === $pagenow ) && strpos( $_SERVER['REQUEST_URI'], '/wp-admin' ) !== false; if ( $is_wp_login || $is_wp_admin ) { // Block ALL actions on wp-login.php if custom login is enabled. // This includes lostpassword, resetpass, rp, etc. // Only allow access to custom login URLs. // Clear any existing cookies before redirect or 404 if ( isset( $_COOKIE['ADALC_intended_role'] ) ) { setcookie( 'ADALC_intended_role', '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN ); } if ( $redirect ) { $redirect_enabled = isset( $settings['redirect_wp_login'] ) ? $settings['redirect_wp_login'] : 1; if ( $redirect_enabled ) { // Redirect to custom URL or home. $redirect_url = isset( $settings['redirect_url'] ) ? $settings['redirect_url'] : home_url(); wp_safe_redirect( $redirect_url, 302 ); exit; } else { // Show 404 if not redirecting status_header( 404 ); nocache_headers(); include( get_query_template( '404' ) ); exit; } } else { // Show 404 if not redirecting status_header( 404 ); nocache_headers(); include( get_query_template( '404' ) ); exit; } } } /** * Redirect WooCommerce logout to customer custom login URL. * * @param string $redirect_url Default redirect URL. * @return string Modified redirect URL. */ public function woocommerce_logout_redirect( $redirect_url ) { $settings = get_option( 'ADALC_settings', array() ); $enabled = isset( $settings['enable_custom_login'] ) ? $settings['enable_custom_login'] : 0; if ( ! $enabled ) { return $redirect_url; } // Get customer role login URL. $customer_login_url = $this->get_role_login_url( 'customer' ); if ( $customer_login_url ) { return $customer_login_url; } // Fallback to configured redirect URL only if redirect_wp_login is enabled. $redirect_enabled = isset( $settings['redirect_wp_login'] ) ? $settings['redirect_wp_login'] : 1; if ( $redirect_enabled ) { return isset( $settings['redirect_url'] ) ? $settings['redirect_url'] : home_url(); } return home_url(); } /** * Apply custom branding to login page */ public function enqueue_custom_login_styles() { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( isset( $_COOKIE['ADALC_intended_role'] ) ) { $role = sanitize_key( $_COOKIE['ADALC_intended_role'] ); $settings = get_option( 'ADALC_settings', array() ); $logo_id = isset( $settings['role_logo'][ $role ] ) ? $settings['role_logo'][ $role ] : ''; $bg_image_id = isset( $settings['role_bg_image'][ $role ] ) ? $settings['role_bg_image'][ $role ] : ''; $bg_color = isset( $settings['role_bg_color'][ $role ] ) ? $settings['role_bg_color'][ $role ] : '#f0f0f1'; $logo = $logo_id ? wp_get_attachment_url( $logo_id ) : ''; $bg_image = $bg_image_id ? wp_get_attachment_url( $bg_image_id ) : ''; $css = ''; if ( ! empty( $bg_image ) ) { $css .= 'body.login { background: url(' . esc_url( $bg_image ) . ') no-repeat center center fixed; background-size: cover; }'; } else { $css .= 'body.login { background: ' . esc_attr( $bg_color ) . '; }'; } if ( ! empty( $logo ) ) { $css .= '.login h1 a { background-image: url(' . esc_url( $logo ) . '); background-size: contain; width: 100%; }'; } wp_enqueue_style( 'login' ); wp_add_inline_style( 'login', $css ); } } /** * Block lost password requests for users not matching intended role. */ public function block_lostpassword_for_wrong_role() { if ( ! isset( $_REQUEST['action'] ) || $_REQUEST['action'] !== 'lostpassword' ) { return; } // Only run if custom login is enabled $settings = get_option( 'ADALC_settings', array() ); $enabled = isset( $settings['enable_custom_login'] ) ? $settings['enable_custom_login'] : 0; if ( ! $enabled ) { return; } // Get intended role from cookie/session $intended_role = null; if ( isset( $_COOKIE['ADALC_intended_role'] ) ) { $intended_role = sanitize_key( $_COOKIE['ADALC_intended_role'] ); } elseif ( ! empty( $_SESSION['ADALC_intended_role'] ) ) { $intended_role = sanitize_key( $_SESSION['ADALC_intended_role'] ); } if ( ! $intended_role ) { return; } // Get entered username/email $user_login = isset( $_POST['user_login'] ) ? sanitize_text_field( $_POST['user_login'] ) : ''; if ( empty( $user_login ) ) { return; } // Try to get user by login or email $user = get_user_by( 'login', $user_login ); if ( ! $user ) { $user = get_user_by( 'email', $user_login ); } if ( ! $user ) { return; } $has_custom_url = false; // Check if user has the intended role $user_roles = (array) $user->roles; if ( ! in_array( $intended_role, $user_roles, true ) ) { //check if user has any custom login URL for their roles // Check if user has no custom login URL for their role $has_custom_url = false; foreach ( $user_roles as $role ) { if ( $this->get_role_login_url( $role ) ) { $has_custom_url = true; break; } } // If no custom login URL for user, allow reset from fallback admin login URL $admin_url = $this->get_role_login_url( 'administrator' ); if ( ! $has_custom_url && $admin_url && isset($_SERVER['REQUEST_URI']) && strpos(rtrim($_SERVER['REQUEST_URI'], '/'), rtrim($admin_path, '/')) !== false ) { // Allow password reset return; } // Otherwise, block and show error wp_die( esc_html__( 'You are not allowed to reset password from this login page. Please use your designated login page.', 'accessdoor-smart-admin-login-url-control' ), esc_html__( 'Access Denied', 'accessdoor-smart-admin-login-url-control' ), array( 'response' => 403 ) ); } } } // Initialize the login handler class. new ADALC_Login_Handler();