id ) { remove_all_actions('admin_notices'); remove_all_actions('all_admin_notices'); } } function settingsPanel() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Sorry, you are not allowed to access this page.', 'admin-login-url-change' ) ); } // Check if Pro plugin is active $is_pro = apply_filters( 'aluc_pro_active', false ); $slug = get_option( 'jh_new_login_url', '' ); $home_url = trailingslashit( home_url() ); $current_url = $slug ? $home_url . $slug . '/' : esc_html__( 'Not set yet', 'admin-login-url-change' ); // Security score: 1 point per active feature $score = 0; if ( $slug ) $score += 40; // custom login URL if ( get_option('aluc_block_direct_wp_login', 0) ) $score += 20; // block wp-login direct if ( get_option('aluc_hide_login_errors', 0) ) $score += 15; // hide login errors if ( get_option('aluc_limit_login_attempts', 0) ) $score += 25; // PRO $score = min( $score, 100 ); $circumference = 2 * 3.14159 * 45; // ≈ 283 ?>
>

v PRO

render_sidebar( $score, $circumference, $is_pro ); ?>

render_sidebar( $score, $circumference, $is_pro ); ?>
[ 'label' => __( 'IP Address Blocker', 'admin-login-url-change' ), 'icon' => 'red', 'subtitle' => __( 'Block specific IP addresses from accessing your login page', 'admin-login-url-change' ), 'desc' => __( 'Block individual IPs or entire IP ranges that are attacking your site. Supports both IPv4 and IPv6.', 'admin-login-url-change' ), 'features' => [ [ 'title' => __( 'Block individual IP addresses', 'admin-login-url-change' ), 'desc' => __( 'Add single IPs to block list instantly', 'admin-login-url-change' ) ], [ 'title' => __( 'Block entire IP ranges (CIDR)', 'admin-login-url-change' ), 'desc' => __( 'Support for both IPv4 and IPv6 CIDR ranges', 'admin-login-url-change' ) ], [ 'title' => __( 'Import / export block lists', 'admin-login-url-change' ), 'desc' => __( 'Manage large block lists with ease', 'admin-login-url-change' ) ], [ 'title' => __( 'Automatic IP ban after failed logins', 'admin-login-url-change' ), 'desc' => __( 'Auto-ban bots and brute-force attackers', 'admin-login-url-change' ) ], ], ], 'country-block' => [ 'label' => __( 'Country Blocker', 'admin-login-url-change' ), 'icon' => 'amber', 'subtitle' => __( 'Restrict login access by country / geo-location', 'admin-login-url-change' ), 'desc' => __( 'Only allow logins from specific countries. Perfect if your team is in one location.', 'admin-login-url-change' ), 'features' => [ [ 'title' => __( 'Block countries with 1 click', 'admin-login-url-change' ), 'desc' => __( 'Simple country select UI', 'admin-login-url-change' ) ], [ 'title' => __( 'Allowlist-only mode', 'admin-login-url-change' ), 'desc' => __( 'Only let whitelisted countries log in', 'admin-login-url-change' ) ], [ 'title' => __( 'GeoIP database auto-updated', 'admin-login-url-change' ), 'desc' => __( 'Always up-to-date geo-location data', 'admin-login-url-change' ) ], [ 'title' => __( 'Custom redirect for blocked countries', 'admin-login-url-change' ), 'desc' => __( 'Show a custom page to blocked visitors', 'admin-login-url-change' ) ], ], ], 'login-limit' => [ 'label' => __( 'Login Attempt Limiter', 'admin-login-url-change' ), 'icon' => 'blue', 'subtitle' => __( 'Stop brute-force attacks by limiting login attempts', 'admin-login-url-change' ), 'desc' => __( 'Automatically lock out IPs that exceed a configurable number of failed login attempts.', 'admin-login-url-change' ), 'features' => [ [ 'title' => __( 'Configurable attempt threshold', 'admin-login-url-change' ), 'desc' => __( 'Set max attempts before lockout', 'admin-login-url-change' ) ], [ 'title' => __( 'Auto lockout with custom duration', 'admin-login-url-change' ), 'desc' => __( 'Choose lockout time in minutes', 'admin-login-url-change' ) ], [ 'title' => __( 'Email alerts on lockout', 'admin-login-url-change' ), 'desc' => __( 'Get notified about lockout events', 'admin-login-url-change' ) ], [ 'title' => __( 'Allowlist trusted IPs', 'admin-login-url-change' ), 'desc' => __( 'Never lock out your own IP', 'admin-login-url-change' ) ], ], ], 'two-fa' => [ 'label' => __( 'Two-Factor Authentication', 'admin-login-url-change' ), 'icon' => 'purple', 'subtitle' => __( 'Add an extra layer of security with 2FA', 'admin-login-url-change' ), 'desc' => __( 'Require a time-based one-time password (TOTP) or email code on every login.', 'admin-login-url-change' ), 'features' => [ [ 'title' => __( 'Email-based OTP fallback', 'admin-login-url-change' ), 'desc' => __( 'Works without an authenticator app', 'admin-login-url-change' ) ], [ 'title' => __( 'Trusted device remember (30 days)', 'admin-login-url-change' ), 'desc' => __( 'Skip 2FA on trusted devices', 'admin-login-url-change' ) ], ], ], ]; foreach ( $pro_tabs as $tab_id => $tab ) : ?>
render_sidebar( $score, $circumference, $is_pro ); ?>

= 70 ) { esc_html_e( 'Good protection! Upgrade to Pro for full cover.', 'admin-login-url-change' ); } elseif ( $score >= 40 ) { esc_html_e( 'Fair — set a custom login URL to improve your score.', 'admin-login-url-change' ); } else { esc_html_e( 'Set a custom login URL to start protecting your site.', 'admin-login-url-change' ); } ?>

' . esc_html__('Not set', 'admin-login-url-change') . ''; ?>

🔒

min="1" max="100">
min="1">

render_sidebar( $score, $circumference ); ?>
'United States', 'GB' => 'United Kingdom', 'CA' => 'Canada', 'AU' => 'Australia', 'IN' => 'India', 'CN' => 'China', 'RU' => 'Russia' ]; foreach ( $countries as $code => $name ) { echo ''; } ?>
placeholder="https://">

render_sidebar( $score, $circumference ); ?>
min="1">
min="1">
min="1">

render_sidebar( $score, $circumference ); ?>

render_sidebar( $score, $circumference ); ?>
'Unauthorized' ] ); wp_die(); } // Check if a nonce is valid. if ( ! isset( $_POST['_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_nonce'] ) ), 'aluc-ajax-nonce' ) ) { wp_send_json_error( [ 'message' => 'Invalid nonce' ] ); wp_die(); } // Allowed: letters, numbers, underscores $slug = preg_replace('/[^A-Za-z0-9_]/', '', $_POST['slug']); if ( empty($slug) ) { wp_send_json_error(['message' => 'Only letters, numbers, and Underscores allowed']); } $old = get_option('jh_new_login_url'); update_option('jh_new_login_url', $slug); // Set rewrite flush flag if ($slug !== $old) { update_option('aluc_need_flush', 1); } wp_send_json_success([ 'message' => 'Saved successfully!', 'slug' => $slug ]); wp_die(); } function admin_login_url_change_page_settings( $links ) { $link = sprintf( "%s", admin_url( 'admin.php?page=admin-login-url-change' ), __( 'Settings', 'admin-login-url-change' ) ); array_push( $links, $link ); return $links; } function admin_login_url_change_css(){ // Only load on our settings page $screen = get_current_screen(); if ( ! $screen || 'toplevel_page_admin-login-url-change' !== $screen->id ) { return; } wp_enqueue_style( 'admin-login-url-change-css', ALUC_PLUGIN_URL . 'assets/css/style.css', [], VERSION ); wp_enqueue_script( 'admin-login-url-change-js', ALUC_PLUGIN_URL . 'assets/js/main.js', [ 'jquery' ], VERSION, true ); wp_localize_script( 'admin-login-url-change-js', 'aluc_core', [ 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'aluc-ajax-nonce' ), 'is_pro' => apply_filters( 'aluc_pro_active', false ) ? 1 : 0, ] ); } /** * Save a single free option via AJAX (toggle switches) */ public function aluc_save_option_ajax() { if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( [ 'message' => 'Unauthorized' ] ); } if ( ! isset( $_POST['_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_nonce'] ) ), 'aluc-ajax-nonce' ) ) { wp_send_json_error( [ 'message' => 'Invalid nonce' ] ); } $allowed_keys = [ 'aluc_block_direct_wp_login', 'aluc_hide_login_errors', 'aluc_disable_xmlrpc', 'aluc_remove_wp_version', ]; $key = isset( $_POST['option_key'] ) ? sanitize_key( $_POST['option_key'] ) : ''; if ( ! in_array( $key, $allowed_keys, true ) ) { wp_send_json_error( [ 'message' => 'Invalid option' ] ); } $value = isset( $_POST['option_value'] ) ? absint( $_POST['option_value'] ) : 0; update_option( $key, $value ); wp_send_json_success( [ 'message' => 'Saved' ] ); wp_die(); } /** * Block wp-admin & wp-login */ public function block_admin_access() { $slug = $this->get_slug(); if ( ! $slug ) return; $req = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : ''; $path = trim( wp_parse_url( $req, PHP_URL_PATH ), '/' ); if ( ! is_user_logged_in() && ( preg_match('#(^|/)wp-admin(/|$)#i', $path) || preg_match('#(^|/)admin(/|$)#i', $path) ) && ! preg_match('#admin-ajax\.php$#i', $path) ) { remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 ); wp_safe_redirect( home_url('/404'), 302 ); exit; } if ( strtolower($path) === 'wp-login.php' && strtoupper($_SERVER['REQUEST_METHOD']) === 'GET' ) { status_header(404); exit; } } /** Fix redirect to dashboard */ public function fix_login_redirect($redirect_to, $requested, $user) { if ( isset($user->ID) && $user->ID > 0 ) { if ( empty($redirect_to) || strpos($redirect_to, 'wp-login.php') !== false ) { return admin_url(); } } return $redirect_to; } /** Rewrite redirects */ public function rewrite_wp_login_redirects($location) { if ( stripos($location, 'wp-login.php') === false ) return $location; $slug = $this->get_slug(); if ( strpos($location, 'checkemail=confirm') !== false ) { return home_url("/{$slug}/?checkemail=confirm"); } return $location; } /** Serve login form at /slug */ public function register_custom_login_rewrite() { $slug = $this->get_slug(); if (! $slug) return; add_rewrite_rule("^{$slug}/?$", 'index.php?aluc_login=1', 'top'); } public function add_query_vars($vars) { $vars[] = 'aluc_login'; return $vars; } public function load_custom_login_template() { if ( get_query_var('aluc_login') ) { nocache_headers(); header('X-Robots-Tag: noindex, nofollow, noarchive', true); global $pagenow, $user_login, $error; $pagenow = 'wp-login.php'; require_once ABSPATH . 'wp-login.php'; exit; } } /** Logout redirect */ public function custom_logout_redirect() { $slug = $this->get_slug(); wp_safe_redirect( home_url("/{$slug}/?loggedout=true") ); exit; } /** Logout URL override */ public function custom_logout_url($url, $redirect) { $slug = $this->get_slug(); $url = home_url("/{$slug}/?action=logout"); if ($redirect) { $url = add_query_arg('redirect_to', urlencode($redirect), $url); } return wp_nonce_url($url, 'log-out'); } /** Lost password */ public function custom_lostpassword_url($url, $redirect) { $slug = $this->get_slug(); $url = home_url("/{$slug}/?action=lostpassword"); if ($redirect) { $url = add_query_arg('redirect_to', urlencode($redirect), $url); } return $url; } /** Login URL */ public function custom_login_url($login_url, $redirect, $reauth) { $slug = $this->get_slug(); $url = home_url("/{$slug}/"); if ($redirect) { $url = add_query_arg('redirect_to', urlencode($redirect), $url); } if ($reauth) { $url = add_query_arg('reauth', '1', $url); } return $url; } /** * Auto flush if slug changed */ public function auto_flush_if_slug_changed() { $slug = $this->get_slug(); $stored = get_option( 'aluc_runtime_slug', '' ); if ( $slug !== $stored ) { update_option( 'aluc_runtime_slug', $slug ); flush_rewrite_rules(); } } /** * Auto flush when plugin update */ public function auto_flush_when_plugin_update() { $stored = get_option( 'aluc_runtime_slug_flush', '' ); if ( empty($stored) ) { update_option( 'aluc_runtime_slug_flush', 1 ); flush_rewrite_rules(); } } /** Flush rewrite rules when settings are updated */ public function maybe_flush_rewrites() { if ( get_option('aluc_need_flush') ) { flush_rewrite_rules(); delete_option('aluc_need_flush'); } } /** Block search engines */ public function block_robots($output) { $slug = $this->get_slug(); $rules = "\n# Admin Login URL Change\nUser-agent: *\n"; $rules .= "Disallow: /{$slug}/\n"; $rules .= "Disallow: /wp-login.php\n"; $rules .= "Disallow: /wp-admin/\n"; return $output . $rules; } /** Reset email URL replacement */ public function modify_reset_password_email($message, $key, $user_login) { $slug = $this->get_slug(); $reset_url = home_url("/{$slug}/?action=rp&key={$key}&login=" . rawurlencode($user_login)); return preg_replace('/https?:\/\/[^\s]+/i', $reset_url, $message); } }