[ 'file' => 'templates/pages/page-login.php', 'slug' => 'login', 'title' => '登录', 'fallback' => '/login/', ], 'register' => [ 'file' => 'templates/pages/page-register.php', 'slug' => 'register', 'title' => '注册', 'fallback' => '/register/', ], 'bind' => [ 'file' => 'templates/pages/page-bind-account.php', 'slug' => 'bind-account', 'title' => '绑定账号', 'fallback' => '/bind-account/', ], 'reset-password' => [ 'file' => 'templates/pages/page-reset-password.php', 'slug' => 'reset-password', 'title' => '重置密码', 'fallback' => '/reset-password/', ], 'verify-email' => [ 'file' => 'templates/pages/page-verify-email.php', 'slug' => 'verify-email', 'title' => '邮箱验证', 'fallback' => '/verify-email/', ], 'categories' => [ 'file' => 'templates/pages/page-categories.php', 'slug' => 'categories', 'title' => '分类目录', 'fallback' => '/categories/', ], 'friends' => [ 'file' => 'templates/pages/page-friends.php', 'slug' => 'friends', 'title' => '友情链接', 'fallback' => '/friends/', ], 'profile' => [ 'file' => 'templates/pages/page-profile.php', 'slug' => 'profile', 'title' => '个人中心', 'fallback' => '/', ], ]; // Zibll-style v2 routing keeps only true fixed template pages in the registry. $_aksrt_special_templates = [ 'sign' => [ 'file' => 'templates/pages/page-sign.php', 'slug' => 'sign', 'title' => '登录/注册', 'fallback' => '/sign/', ], 'bind' => [ 'file' => 'templates/pages/page-bind-account.php', 'slug' => 'bind-account', 'title' => '绑定账号', 'fallback' => '/bind-account/', ], 'reset-password' => [ 'file' => 'templates/pages/page-reset-password.php', 'slug' => 'reset-password', 'title' => '重置密码', 'fallback' => '/reset-password/', ], 'verify-email' => [ 'file' => 'templates/pages/page-verify-email.php', 'slug' => 'verify-email', 'title' => '邮箱验证', 'fallback' => '/verify-email/', ], 'categories' => [ 'file' => 'templates/pages/page-categories.php', 'slug' => 'categories', 'title' => '分类目录', 'fallback' => '/categories/', ], 'friends' => [ 'file' => 'templates/pages/page-friends.php', 'slug' => 'friends', 'title' => '友情链接', 'fallback' => '/friends/', ], 'profile' => [ 'file' => 'templates/pages/page-profile.php', 'slug' => 'profile', 'title' => '个人中心', 'fallback' => '/profile/', ], ]; /** @var array 缓存 key=模板文件路径 => value=WP_Post|null */ $_aksrt_template_page_cache = []; // ============================================================ // 二、核心工具函数 // ============================================================ /** * 查找使用指定模板文件的页面(按模板匹配,自适应任意 slug) * * @param string $template_file 相对于主题的模板路径 * @return WP_Post|null */ function aksrt_find_template_page(string $template_file) { global $_aksrt_template_page_cache; if (isset($_aksrt_template_page_cache[$template_file])) { return $_aksrt_template_page_cache[$template_file]; } $page = null; $pages = get_pages([ 'meta_key' => '_wp_page_template', 'meta_value' => $template_file, 'number' => 1, 'post_status' => 'publish', ]); if (!empty($pages)) { $page = $pages[0]; } $_aksrt_template_page_cache[$template_file] = $page; return $page; } /** * 获取使用指定模板的页面 URL * * @param string $key 注册表 key(当前仅 profile 使用) * @return string 页面 URL 或回退地址 */ function aksrt_get_template_url(string $key): string { global $_aksrt_special_templates; if (!isset($_aksrt_special_templates[$key])) { return home_url('/'); } $cfg = $_aksrt_special_templates[$key]; $page = aksrt_find_template_page($cfg['file']); if (!$page) { aksrt_ensure_template_page($key); $page = aksrt_find_template_page($cfg['file']); } if ($page) { return get_permalink($page->ID); } return home_url($cfg['fallback']); } /** * 定位模板文件的绝对路径 * * @param string $template_file 相对于主题的路径 * @return string|false 文件绝对路径或 false */ function aksrt_locate_template_file(string $template_file) { $path = locate_template([$template_file]); if ($path) return $path; $full = AKSRT_DIR . '/' . $template_file; return file_exists($full) ? $full : false; } /** * Resolve a public-facing page template file from stored meta or page slug. */ function aksrt_resolve_page_template_file(string $template_file = '', string $post_slug = ''): string { $template_file = ltrim($template_file, '/\\'); $post_slug = sanitize_title($post_slug); $legacy_auth_templates = [ 'templates/pages/page-login.php' => 'login', 'templates/pages/page-register.php' => 'register', 'templates/pages/page-bind-account.php' => 'bind', 'templates/pages/page-reset-password.php' => 'reset-password', 'templates/pages/page-verify-email.php' => 'verify-email', ]; if ($template_file !== '') { if ($template_file === 'templates/pages/page-sign.php') { return aksrt_get_auth_template_file(aksrt_get_auth_tab(), true); } if (!empty($legacy_auth_templates[$template_file])) { return aksrt_get_auth_template_file((string) $legacy_auth_templates[$template_file], true); } if (strpos($template_file, 'templates/pages/') === 0 && aksrt_locate_template_file($template_file)) { return $template_file; } } if ($post_slug !== '') { $auth_slug_map = [ 'sign' => aksrt_get_auth_tab(), 'login' => 'login', 'register' => 'register', 'bind-account' => 'bind', 'reset-password' => 'reset-password', 'verify-email' => 'verify-email', ]; if (!empty($auth_slug_map[$post_slug])) { return aksrt_get_auth_template_file((string) $auth_slug_map[$post_slug], true); } $slug_map = [ 'categories' => 'templates/pages/page-categories.php', 'friends' => 'templates/pages/page-friends.php', 'profile' => 'templates/pages/page-profile.php', ]; if (!empty($slug_map[$post_slug]) && aksrt_locate_template_file($slug_map[$post_slug])) { return $slug_map[$post_slug]; } } return ''; } /** * Normalize auth view keys used by the unified sign page. */ function aksrt_normalize_auth_tab(string $tab): string { $tab = sanitize_key($tab); switch ($tab) { case 'signin': case 'login': return 'login'; case 'signup': case 'register': return 'register'; case 'bind': case 'bind-account': return 'bind'; case 'reset': case 'lostpassword': case 'reset-password': return 'reset-password'; case 'verify': case 'verify-email': return 'verify-email'; default: return 'login'; } } /** * Whether an auth tab should be rendered by the unified sign page. */ function aksrt_auth_tab_uses_unified_sign_page(string $tab): bool { return in_array( aksrt_normalize_auth_tab($tab), ['login', 'register'], true ); } /** * Resolve the auth template file, preferring the unified sign page when present. */ function aksrt_get_auth_template_file(string $tab = 'login', bool $prefer_sign_page = true): string { $normalized_tab = aksrt_normalize_auth_tab($tab); $sign_template = 'templates/pages/page-sign.php'; if ( $prefer_sign_page && aksrt_auth_tab_uses_unified_sign_page($normalized_tab) && aksrt_locate_template_file($sign_template) ) { return $sign_template; } switch ($normalized_tab) { case 'register': return 'templates/pages/page-register.php'; case 'bind': return 'templates/pages/page-bind-account.php'; case 'reset-password': return 'templates/pages/page-reset-password.php'; case 'verify-email': return 'templates/pages/page-verify-email.php'; default: return 'templates/pages/page-login.php'; } } /** * Return the active auth view for sign routes and the sign page template. */ function aksrt_get_auth_tab(): string { $query_tab = get_query_var('aksrt_auth_tab'); if (is_string($query_tab) && $query_tab !== '') { return aksrt_normalize_auth_tab($query_tab); } if (!empty($_GET['tab'])) { return aksrt_normalize_auth_tab((string) wp_unslash($_GET['tab'])); } $post = get_queried_object(); if ($post instanceof WP_Post) { return aksrt_normalize_auth_tab((string) $post->post_name); } return 'login'; } /** * 清除模板页面缓存 */ function aksrt_clear_template_page_cache(): void { global $_aksrt_template_page_cache; $_aksrt_template_page_cache = []; } /** * Prepare the public user-home template context and return its template path. */ function aksrt_get_user_home_template_path(): string { global $_aksrt_special_templates, $aksrt_profile_user; $nicename = (string) get_query_var('user_nicename'); if ($nicename === '') { return ''; } $user = get_user_by('slug', $nicename); if (!$user instanceof WP_User) { return ''; } $template_path = aksrt_locate_template_file('templates/pages/page-user-home.php'); if (!$template_path) { return ''; } $aksrt_profile_user = $user; return $template_path; } /** * Resolve the active special-page template path for the current request. */ function aksrt_get_current_special_template_path(): string { if (get_query_var('user_nicename')) { return aksrt_get_user_home_template_path(); } if (get_query_var('aksrt_user_center')) { $profile_template = aksrt_locate_template_file('templates/pages/page-profile.php'); return $profile_template ?: ''; } if (get_query_var('aksrt_sign')) { $auth_template = aksrt_get_auth_template_file((string) get_query_var('aksrt_auth_tab'), true); $auth_template_path = aksrt_locate_template_file($auth_template); return $auth_template_path ?: ''; } if (is_page()) { $page_id = get_queried_object_id(); if ($page_id > 0) { $page_template = get_post_meta($page_id, '_wp_page_template', true); $resolved_template = aksrt_resolve_page_template_file( is_string($page_template) ? $page_template : '', (string) get_post_field('post_name', $page_id) ); if ($resolved_template !== '') { $resolved_path = aksrt_locate_template_file($resolved_template); if ($resolved_path) { return $resolved_path; } } } } return ''; } /** * 根据当前请求路径识别系统模板页 key。 * * 用于前台直接访问固定 slug 时的自动补页。 */ function aksrt_get_requested_template_key(): string { global $_aksrt_special_templates; $request_uri = isset($_SERVER['REQUEST_URI']) ? (string) $_SERVER['REQUEST_URI'] : ''; if ($request_uri === '') { return ''; } $request_path = wp_parse_url($request_uri, PHP_URL_PATH); if (!is_string($request_path) || $request_path === '') { return ''; } $home_path = (string) wp_parse_url(home_url('/'), PHP_URL_PATH); if ($home_path !== '' && str_starts_with($request_path, $home_path)) { $request_path = (string) substr($request_path, strlen($home_path)); } $request_slug = trim($request_path, '/'); if ($request_slug === '') { return ''; } foreach ($_aksrt_special_templates as $key => $cfg) { $slug = isset($cfg['slug']) ? sanitize_title((string) $cfg['slug']) : ''; if ($slug !== '' && $slug === $request_slug) { return (string) $key; } } return ''; } /** * 确保使用指定模板的页面存在,缺失则自动创建 * * @param string $key 注册表 key */ function aksrt_ensure_template_page(string $key): void { global $_aksrt_special_templates; if (!isset($_aksrt_special_templates[$key])) return; $cfg = $_aksrt_special_templates[$key]; $desired_slug = sanitize_title($cfg['slug'] ?? $key); // 已有页面使用此模板? if (aksrt_find_template_page($cfg['file'])) return; if ($desired_slug !== '') { $existing_page = get_page_by_path($desired_slug, OBJECT, 'page'); if ($existing_page instanceof WP_Post) { if ($existing_page->post_status !== 'publish') { wp_update_post([ 'ID' => $existing_page->ID, 'post_status' => 'publish', ]); } update_post_meta($existing_page->ID, '_wp_page_template', $cfg['file']); aksrt_clear_template_page_cache(); return; } } // 自动创建 $page_id = wp_insert_post([ 'post_title' => $cfg['title'], 'post_content' => '', 'post_status' => 'publish', 'post_type' => 'page', 'post_name' => $desired_slug !== '' ? $desired_slug : $key, 'comment_status' => 'closed', 'ping_status' => 'closed', ]); if (!is_wp_error($page_id) && $page_id > 0) { update_post_meta($page_id, '_wp_page_template', $cfg['file']); aksrt_clear_template_page_cache(); } } // ============================================================ // 三、URL 路由与模板加载 // ============================================================ // --- 3a. /user/{昵称} 自定义重写 --- add_filter('query_vars', function ($vars) { $vars[] = 'aksrt_user_center'; $vars[] = 'user_nicename'; return $vars; }); add_action('template_redirect', function () { if (is_admin() || wp_doing_ajax() || is_feed() || is_embed() || is_preview()) { return; } $resolved_path = aksrt_get_current_special_template_path(); if ($resolved_path === '') { return; } status_header(200); load_template($resolved_path, true); exit; }, 100); add_action('init', function () { add_rewrite_tag('%aksrt_user_center%', '([^&]+)'); add_rewrite_tag('%user_nicename%', '([^/]+)'); add_rewrite_rule('^profile/?$', 'index.php?aksrt_user_center=1', 'top'); add_rewrite_rule('^user/([^/]+)/?$', 'index.php?user_nicename=$matches[1]', 'top'); }); // --- 3b. 统一模板拦截器(核心)--- // 拦截所有使用主题特殊模板的页面请求,确保正确加载 add_filter('template_include', function ($template) { $resolved_path = aksrt_get_current_special_template_path(); if ($resolved_path !== '') { return $resolved_path; } return $template; global $_aksrt_special_templates; // A) /user/{昵称} 路由 → 加载公开主页模板 $nicename = get_query_var('user_nicename'); if (!empty($nicename)) { $user = get_user_by('slug', $nicename); if (!$user) return $template; // 不存在的用户 → 默认 404 $tpl = aksrt_locate_template_file('templates/pages/page-user-home.php'); if (!$tpl) { // 兜底:如果新模板不存在,回退到旧 profile 模板 $tpl = aksrt_locate_template_file($_aksrt_special_templates['profile']['file']); } if (!$tpl) return $template; global $aksrt_profile_user; $aksrt_profile_user = $user; return $tpl; } // B) 普通页面 → 检测是否使用了我们的特殊模板,确保加载正确的模板文件 // (防止 WP 在某些情况下未能正确解析自定义页面模板) if (is_page()) { $page_id = get_queried_object_id(); if ($page_id) { $page_template = get_post_meta($page_id, '_wp_page_template', true); if ($page_template && strpos($page_template, 'templates/pages/') === 0) { $tpl = aksrt_locate_template_file($page_template); if ($tpl) return $tpl; } } } return $template; }, 99); add_filter('template_include', function ($template) { $resolved_path = aksrt_get_current_special_template_path(); if ($resolved_path !== '') { return $resolved_path; } if (get_query_var('aksrt_user_center')) { $profile_template = aksrt_locate_template_file('templates/pages/page-profile.php'); if ($profile_template) { return $profile_template; } } if (is_page()) { $page_id = get_queried_object_id(); if ($page_id > 0) { $page_template = get_post_meta($page_id, '_wp_page_template', true); $resolved_template = aksrt_resolve_page_template_file( is_string($page_template) ? $page_template : '', (string) get_post_field('post_name', $page_id) ); if ($resolved_template !== '') { $resolved_path = aksrt_locate_template_file($resolved_template); if ($resolved_path) { return $resolved_path; } } } } return $template; }, 100); // ============================================================ // 四、自动维护 + flush // ============================================================ add_action('init', function () { global $_aksrt_special_templates; // 后台/AJAX:检查并创建缺失页面 $pages_bootstrapped = get_option('aksrt_template_pages_bootstrapped'); $requested_template_key = (!is_admin() && !wp_doing_ajax()) ? aksrt_get_requested_template_key() : ''; if (is_admin() || wp_doing_ajax() || $pages_bootstrapped !== AKSRT_VERSION) { foreach ($_aksrt_special_templates as $key => $cfg) { if ($key === 'profile') { continue; } aksrt_ensure_template_page($key); } if ($pages_bootstrapped !== AKSRT_VERSION) { update_option('aksrt_template_pages_bootstrapped', AKSRT_VERSION); } } elseif ($requested_template_key !== '' && $requested_template_key !== 'profile') { aksrt_ensure_template_page($requested_template_key); } // 统一 flush 检查 $rewrite_version = AKSRT_VERSION . ':sign-profile-routing-v1'; $flushed = get_option('aksrt_user_rules_flushed'); if ($flushed !== $rewrite_version) { flush_rewrite_rules(false); update_option('aksrt_user_rules_flushed', $rewrite_version); } }); // 页面变更时清缓存 add_action('save_post', function ($pid) { if (get_post_type($pid) === 'page') aksrt_clear_template_page_cache(); }); add_action('delete_post', function ($pid) { if (get_post_type($pid) === 'page') aksrt_clear_template_page_cache(); }); // ============================================================ // 五、公开 API 函数(兼容旧代码调用) // ============================================================ if (!function_exists('aksrt_get_user_center_url')) : /** * 获取本人中心 URL(私有空间入口) * * @param string $tab 可选 tab 参数 * @return string */ function aksrt_get_user_center_url(string $tab = ''): string { if (get_option('permalink_structure')) { $url = home_url('/profile/'); } else { $url = add_query_arg('aksrt_user_center', '1', home_url('/')); } if ($tab !== '') { $url = add_query_arg('tab', $tab, $url); } return $url; } endif; if (!function_exists('aksrt_get_user_home_url')) : /** * 获取公开用户主页 URL(/user/{nicename}/) * * @param WP_User|int|string|null $user 用户对象、ID、nicename 或 null(当前用户) * @return string */ function aksrt_get_user_home_url($user = null): string { $slug = ''; if ($user instanceof WP_User) { $slug = $user->user_nicename; } elseif (is_int($user) && $user > 0) { $u = get_userdata($user); $slug = $u ? $u->user_nicename : ''; } elseif (is_string($user) && $user) { $slug = $user; } else { $current = wp_get_current_user(); $slug = $current->ID ? $current->user_nicename : ''; } if (!$slug) return home_url('/'); return home_url('/user/' . trailingslashit($slug)); } endif; if (!function_exists('aksrt_is_user_center_page')) : /** * 判断当前是否为本人中心页面 */ function aksrt_is_user_center_page(): bool { return (bool) get_query_var('aksrt_user_center') || (is_page_template('templates/pages/page-profile.php') && !(bool) get_query_var('user_nicename')); } endif; if (!function_exists('aksrt_is_user_home_page')) : /** * 判断当前是否为公开用户主页 */ function aksrt_is_user_home_page(): bool { return (bool) get_query_var('user_nicename') || is_page_template('templates/pages/page-user-home.php'); } endif; if (!function_exists('aksrt_get_profile_url')) : /** * 兼容层:获取用户主页 URL * * @deprecated 使用 aksrt_get_user_center_url() 或 aksrt_get_user_home_url() 替代 * @param WP_User|int|string|null $user * @return string */ function aksrt_get_profile_url($user = null): string { // 无参调用 → 当前用户主页(公开页) if ($user === null) { return aksrt_get_user_home_url(); } return aksrt_get_user_home_url($user); } endif; if (!function_exists('aksrt_get_sign_page_url')) : /** * Get the unified auth page URL, with legacy route fallback while the page self-heals. * * @param string $tab * @param array $args */ function aksrt_get_sign_page_url(string $tab = 'login', array $args = []): string { $tab = aksrt_normalize_auth_tab($tab); $legacy_fallbacks = [ 'login' => home_url('/login/'), 'register' => home_url('/register/'), 'bind' => home_url('/bind-account/'), 'reset-password' => home_url('/reset-password/'), 'verify-email' => home_url('/verify-email/'), ]; $page = aksrt_find_template_page('templates/pages/page-sign.php'); if (!$page) { aksrt_ensure_template_page('sign'); $page = aksrt_find_template_page('templates/pages/page-sign.php'); } if ($page instanceof WP_Post) { $url = get_permalink($page->ID); $args = ['tab' => $tab] + $args; return add_query_arg($args, $url); } $url = $legacy_fallbacks[$tab] ?? home_url('/login/'); return !empty($args) ? add_query_arg($args, $url) : $url; } /** * Determine whether the current request is served by the unified auth experience. */ function aksrt_is_auth_page_request(): bool { return (bool) get_query_var('aksrt_sign') || is_page_template('templates/pages/page-sign.php') || is_page_template('templates/pages/page-login.php') || is_page_template('templates/pages/page-register.php') || is_page_template('templates/pages/page-bind-account.php') || is_page_template('templates/pages/page-reset-password.php') || is_page_template('templates/pages/page-verify-email.php'); } endif; if (!function_exists('aksrt_get_login_url')) : /** 获取登录页 URL */ function aksrt_get_login_url($redirect = '') { $url = aksrt_get_sign_page_url('login'); if ($redirect) { $url = add_query_arg('redirect_to', urlencode($redirect), $url); } return $url; } endif; if (!function_exists('aksrt_get_register_url')) : /** 获取注册页 URL */ function aksrt_get_register_url() { return aksrt_get_sign_page_url('register'); } endif; if (!function_exists('aksrt_get_bind_url')) : /** 获取绑定账号页面 URL */ function aksrt_get_bind_url($transient_key = '') { $url = aksrt_get_template_url('bind'); if ($transient_key) { $url = add_query_arg('obk', $transient_key, $url); } return $url; } endif; if (!function_exists('aksrt_get_logout_url')) : /** 获取退出登录 URL */ function aksrt_get_logout_url($redirect = '') { $target = $redirect ?: home_url('/'); $url = add_query_arg('redirect_to', rawurlencode($target), home_url('/logout/')); return wp_nonce_url($url, 'aksrt-logout'); } endif; if (!function_exists('aksrt_get_reset_password_url')) : /** * 获取重置密码页面 URL * * @param string $token 主题重置 token(可选,设置密码时需要) * @param int $user_id 用户 ID(可选,设置密码时需要) * @return string */ function aksrt_get_reset_password_url(string $token = '', int $user_id = 0): string { $url = aksrt_get_template_url('reset-password'); if ($token !== '' && $user_id > 0) { $url = add_query_arg([ 'token' => $token, 'uid' => $user_id, ], $url); } return $url; } endif; if (!function_exists('aksrt_get_verify_email_url')) : /** 获取邮箱验证页面 URL */ function aksrt_get_verify_email_url(int $user_id = 0, array $args = []): string { $url = aksrt_get_template_url('verify-email'); if ($user_id > 0) { $args['uid'] = $user_id; } if (!empty($args)) { $url = add_query_arg($args, $url); } return $url; } endif; require_once __DIR__ . '/class-aksrt-user-notifications.php'; // ============================================================ // 六、作者链接改写 // ============================================================ add_filter('author_link', function ($link, $author_id) { $user = get_userdata($author_id); $slug = $user ? $user->user_nicename : 'user-' . $author_id; return home_url('/user/' . trailingslashit($slug)); }, 10, 2); add_action('template_redirect', function () { if (!is_author()) return; $author_id = get_queried_object_id(); if ($author_id) { $user = get_userdata($author_id); $slug = $user ? $user->user_nicename : 'user-' . $author_id; wp_safe_redirect(home_url('/user/' . trailingslashit($slug)), 301); exit; } }); // ============================================================ // AJAX: 保存用户个人资料(显示名称、简介、联系方式) // ============================================================ add_action('wp_ajax_aksrt_save_profile', function () { if (!isset($_POST['_profile_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_profile_nonce'])), 'aksrt_profile_save')) { wp_send_json_error(['message' => __('安全验证失败,请刷新页面重试', 'aksrt')]); } $user_id = isset($_POST['user_id']) ? (int) $_POST['user_id'] : 0; $result = function_exists('aksrt_save_user_center_profile') ? aksrt_save_user_center_profile($user_id, $_POST) : new WP_Error('aksrt_profile_unavailable', __('保存失败', 'aksrt')); if (is_wp_error($result)) { wp_send_json_error(['message' => $result->get_error_message()]); } wp_send_json_success(['message' => __('保存成功!', 'aksrt')]); }); // ============================================================ // AJAX: 发送邮箱验证码(修改密码/更改邮箱通用) // ============================================================ if (!function_exists('aksrt_get_email_code_key')) : function aksrt_get_email_code_key(int $user_id, string $scene): string { return 'aksrt_email_code_' . $scene . '_' . $user_id; } endif; if (!function_exists('aksrt_get_email_code_rate_key')) : function aksrt_get_email_code_rate_key(int $user_id, string $scene, string $target = ''): string { $suffix = $target !== '' ? '_' . md5(strtolower($target)) : ''; return 'aksrt_email_code_rate_' . $scene . '_' . $user_id . $suffix; } endif; if (!function_exists('aksrt_store_email_code')) : function aksrt_store_email_code(int $user_id, string $scene, string $code, string $target = ''): void { set_transient( aksrt_get_email_code_key($user_id, $scene), [ 'hash' => wp_hash_password($code), 'target' => $target, 'issued_at' => time(), ], 5 * MINUTE_IN_SECONDS ); } endif; if (!function_exists('aksrt_consume_email_code')) : function aksrt_consume_email_code(int $user_id, string $scene, string $code, string $target = ''): bool { $key = aksrt_get_email_code_key($user_id, $scene); $stored = get_transient($key); if (!is_array($stored) || empty($stored['hash']) || !wp_check_password($code, $stored['hash'])) { return false; } if ($target !== '' && strtolower((string) ($stored['target'] ?? '')) !== strtolower($target)) { return false; } delete_transient($key); return true; } endif; add_action('wp_ajax_aksrt_send_email_code', function () { if ( ! isset( $_POST['_settings_nonce'] ) || ! wp_verify_nonce( $_POST['_settings_nonce'], 'aksrt_account_settings' ) ) { wp_send_json_error( array( 'message' => __( '安全验证失败,请刷新页面重试', 'aksrt' ) ) ); } if ( ! is_user_logged_in() ) { wp_send_json_error( array( 'message' => __( '请先登录', 'aksrt' ) ) ); } $scene = isset( $_POST['scene'] ) ? sanitize_key( (string) $_POST['scene'] ) : ''; if ( ! in_array( $scene, array( 'change_password', 'change_email' ), true ) ) { wp_send_json_error( array( 'message' => __( '无效的验证场景', 'aksrt' ) ) ); } if ( aksrt_is_captcha_enabled_for( $scene ) ) { $captcha_result = aksrt_verify_captcha( $_POST ); if ( $captcha_result !== true ) { wp_send_json_error( array( 'message' => $captcha_result ) ); } } $current_user = wp_get_current_user(); $target_email = ''; $success_message = ''; if ( $scene === 'change_password' ) { $target_email = $current_user->user_email; if ( empty( $target_email ) || ! is_email( $target_email ) ) { wp_send_json_error( array( 'message' => __( '当前账号未绑定有效邮箱', 'aksrt' ) ) ); } $success_message = __( '验证码已发送到您的注册邮箱', 'aksrt' ); } else { $new_email = isset( $_POST['new_email'] ) ? trim( wp_unslash( $_POST['new_email'] ) ) : ''; $current_password = isset( $_POST['current_password'] ) ? trim( wp_unslash( $_POST['current_password'] ) ) : ''; if ( empty( $current_password ) || ! wp_check_password( $current_password, $current_user->user_pass, $current_user->ID ) ) { wp_send_json_error( array( 'message' => __( '当前密码不正确', 'aksrt' ) ) ); } if ( empty( $new_email ) || ! is_email( $new_email ) ) { wp_send_json_error( array( 'message' => __( '请输入有效的新邮箱地址', 'aksrt' ) ) ); } if ( strtolower( $new_email ) === strtolower( $current_user->user_email ) ) { wp_send_json_error( array( 'message' => __( '新邮箱与当前邮箱相同', 'aksrt' ) ) ); } if ( email_exists( $new_email ) ) { wp_send_json_error( array( 'message' => __( '该邮箱已被其他账号使用', 'aksrt' ) ) ); } $target_email = $new_email; $success_message = __( '验证码已发送到新邮箱,请完成验证后再提交', 'aksrt' ); } // 频率限制:60秒内不能重复发送 $rate_key = aksrt_get_email_code_rate_key( $current_user->ID, $scene, $target_email ); if ( get_transient( $rate_key ) ) { wp_send_json_error( array( 'message' => __( '操作过于频繁,请稍后再试', 'aksrt' ) ) ); } set_transient( $rate_key, true, 60 ); // 生成验证码并同步发送,只有真正发信成功后才写入验证码缓存。 $code = str_pad( (string) random_int( 0, 999999 ), 6, '0', STR_PAD_LEFT ); $site_name = get_bloginfo( 'name' ); $default_subject = '[' . $site_name . '] ' . __( '邮箱验证码', 'aksrt' ); $default_content = sprintf( __( "您好 %s,\n\n您正在进行敏感操作验证,验证码为:\n\n【%s】\n\n验证码有效期为 5 分钟。如非本人操作,请忽略此邮件。", 'aksrt' ), $current_user->display_name, $code ); $sent = class_exists( 'AKSRT_Settings' ) ? AKSRT_Settings::send_event_email( 'change_code', $target_email, $default_subject, $default_content, [ '{username}' => $current_user->display_name, '{site_name}' => $site_name, '{code}' => $code ] ) : wp_mail( $target_email, $default_subject, $default_content, [ 'Content-Type: text/plain; charset=UTF-8' ] ); if ( ! $sent ) { delete_transient( $rate_key ); error_log( '[AKSRT] 验证码邮件发送失败 user_id=' . $current_user->ID . ' email=' . $target_email . ' scene=' . $scene ); wp_send_json_error( array( 'message' => __( '验证码邮件发送失败,请稍后重试', 'aksrt' ) ) ); } aksrt_store_email_code( $current_user->ID, $scene, $code, $target_email ); wp_send_json_success( array( 'message' => $success_message ) ); }); // ============================================================ // AJAX: 修改密码 // ============================================================ add_action('wp_ajax_aksrt_change_password', function () { if ( ! isset( $_POST['_settings_nonce'] ) || ! wp_verify_nonce( $_POST['_settings_nonce'], 'aksrt_account_settings' ) ) { wp_send_json_error( array( 'message' => __( '安全验证失败,请刷新页面重试', 'aksrt' ) ) ); } $user_id = get_current_user_id(); if ( ! $user_id ) { wp_send_json_error( array( 'message' => __( '请先登录', 'aksrt' ) ) ); } $old_password = isset( $_POST['old_password'] ) ? trim( wp_unslash( $_POST['old_password'] ) ) : ''; $new_password = isset( $_POST['new_password'] ) ? trim( wp_unslash( $_POST['new_password'] ) ) : ''; $new_password_confirm = isset( $_POST['new_password_confirm'] ) ? trim( wp_unslash( $_POST['new_password_confirm'] ) ) : ''; $email_code = isset( $_POST['email_code'] ) ? sanitize_text_field( $_POST['email_code'] ) : ''; // 验证原密码 $user = get_userdata( $user_id ); if ( ! $user || ! wp_check_password( $old_password, $user->data->user_pass, $user_id ) ) { wp_send_json_error( array( 'message' => __( '原密码不正确', 'aksrt' ) ) ); } // 验证新密码强度 if ( mb_strlen( $new_password ) < 6 ) { wp_send_json_error( array( 'message' => __( '新密码长度至少6位', 'aksrt' ) ) ); } if ( mb_strlen( $new_password ) > 128 ) { wp_send_json_error( array( 'message' => __( '新密码过长', 'aksrt' ) ) ); } if ( $new_password !== $new_password_confirm ) { wp_send_json_error( array( 'message' => __( '两次输入的新密码不一致', 'aksrt' ) ) ); } // 人机验证 if ( aksrt_is_captcha_enabled_for( 'change_password' ) ) { $captcha_result = aksrt_verify_captcha( $_POST ); if ( $captcha_result !== true ) { wp_send_json_error( array( 'message' => $captcha_result ) ); } } // 验证邮箱验证码 if ( ! aksrt_consume_email_code( $user_id, 'change_password', $email_code, $user->user_email ) ) { wp_send_json_error( array( 'message' => __( '邮箱验证码错误或已过期', 'aksrt' ) ) ); } // 设置新密码 wp_set_password( $new_password, $user_id ); if ( class_exists( 'WP_Session_Tokens' ) ) { WP_Session_Tokens::get_instance( $user_id )->destroy_all(); } // 清除登录态 wp_clear_auth_cookie(); wp_send_json_success( array( 'message' => __( '密码修改成功,即将跳转到登录页…', 'aksrt' ), 'redirect_to' => aksrt_get_login_url(), )); }); // ============================================================ // AJAX: 更改邮箱 // ============================================================ add_action('wp_ajax_aksrt_change_email', function () { if ( ! isset( $_POST['_settings_nonce'] ) || ! wp_verify_nonce( $_POST['_settings_nonce'], 'aksrt_account_settings' ) ) { wp_send_json_error( array( 'message' => __( '安全验证失败,请刷新页面重试', 'aksrt' ) ) ); } $user_id = get_current_user_id(); if ( ! $user_id ) { wp_send_json_error( array( 'message' => __( '请先登录', 'aksrt' ) ) ); } $current_password = isset( $_POST['current_password'] ) ? trim( wp_unslash( $_POST['current_password'] ) ) : ''; $new_email = isset( $_POST['new_email'] ) ? trim( wp_unslash( $_POST['new_email'] ) ) : ''; $email_code = isset( $_POST['email_code'] ) ? sanitize_text_field( $_POST['email_code'] ) : ''; $current_user = wp_get_current_user(); if ( empty( $current_password ) || ! wp_check_password( $current_password, $current_user->user_pass, $current_user->ID ) ) { wp_send_json_error( array( 'message' => __( '当前密码不正确', 'aksrt' ) ) ); } // 验证新邮箱格式 if ( empty( $new_email ) || ! is_email( $new_email ) ) { wp_send_json_error( array( 'message' => __( '请输入有效的邮箱地址', 'aksrt' ) ) ); } if ( strtolower( $new_email ) === strtolower( $current_user->user_email ) ) { wp_send_json_error( array( 'message' => __( '新邮箱与当前邮箱相同', 'aksrt' ) ) ); } // 检查邮箱是否已被使用 if ( email_exists( $new_email ) ) { wp_send_json_error( array( 'message' => __( '该邮箱已被其他账号使用', 'aksrt' ) ) ); } // 人机验证 if ( aksrt_is_captcha_enabled_for( 'change_email' ) ) { $captcha_result = aksrt_verify_captcha( $_POST ); if ( $captcha_result !== true ) { wp_send_json_error( array( 'message' => $captcha_result ) ); } } // 验证邮箱验证码 if ( ! aksrt_consume_email_code( $user_id, 'change_email', $email_code, $new_email ) ) { wp_send_json_error( array( 'message' => __( '邮箱验证码错误或已过期', 'aksrt' ) ) ); } // 更新邮箱 $old_email = $current_user->user_email; $update_result = wp_update_user( [ 'ID' => $user_id, 'user_email' => $new_email, ] ); if ( is_wp_error( $update_result ) ) { wp_send_json_error( array( 'message' => $update_result->get_error_message() ?: __( '邮箱更新失败,请稍后重试', 'aksrt' ) ) ); } if ( is_email( $old_email ) ) { $site_name = get_bloginfo( 'name' ); $default_subject = '[' . $site_name . '] ' . __( '账号邮箱已变更', 'aksrt' ); $default_content = sprintf( __( "您好 %s,\n\n您的账号邮箱已成功修改为:%s\n\n如果这不是您的操作,请立即联系站点管理员。", 'aksrt' ), $current_user->display_name, $new_email ); if ( class_exists( 'AKSRT_Settings' ) ) { AKSRT_Settings::send_event_email( 'change_notice', $old_email, $default_subject, $default_content, [ '{username}' => $current_user->display_name, '{site_name}' => $site_name, '{new_email}' => $new_email ] ); } else { wp_mail( $old_email, $default_subject, $default_content, [ 'Content-Type: text/plain; charset=UTF-8' ] ); } } // ====== 邮箱变更后重置验证状态(阶段 5)====== // 1. 写入 14 天回滚窗口 meta(管理员可在此期内还原旧邮箱) // 2. 把 aksrt_email_verified 重置为 0 // 3. 若功能启用 → 立即给新邮箱发送验证邮件 update_user_meta( $user_id, 'aksrt_email_previous', $old_email ); update_user_meta( $user_id, 'aksrt_email_changed_at', time() ); $verify_url = ''; $verify_message = ''; if ( class_exists( 'AKSRT_Settings' ) && class_exists( 'AKSRT_Auth_Service' ) && AKSRT_Settings::registration_requires_email_verification() ) { update_user_meta( $user_id, 'aksrt_email_verified', 0 ); // 用户对自身的 edit_user 权限映射到 'read',因此 admin_send_verification 会通过权限校验。 $verify_result = AKSRT_Auth_Service::admin_send_verification( $user_id, $user_id ); if ( ! empty( $verify_result['success'] ) ) { $verify_url = function_exists('aksrt_get_verify_email_url') ? aksrt_get_verify_email_url( $user_id ) : ''; $verify_message = __( '请前往新邮箱完成验证,否则下次登录将被拦截。', 'aksrt' ); } } if ( class_exists( 'WP_Session_Tokens' ) ) { WP_Session_Tokens::get_instance( $user_id )->destroy_all(); } // 清除登录态 wp_clear_auth_cookie(); wp_send_json_success( array( 'message' => $verify_message !== '' ? __( '邮箱修改成功,请前往新邮箱完成验证后重新登录…', 'aksrt' ) : __( '邮箱修改成功,即将跳转到登录页…', 'aksrt' ), 'redirect_to' => $verify_url !== '' ? $verify_url : aksrt_get_login_url(), 'verify_url' => $verify_url, )); });