diff --git a/inc/helpers/aksrt-ip-geo.php b/inc/helpers/aksrt-ip-geo.php index 5e667c04..20501c62 100644 --- a/inc/helpers/aksrt-ip-geo.php +++ b/inc/helpers/aksrt-ip-geo.php @@ -46,13 +46,35 @@ if (!function_exists('aksrt_ip_geo_display_enabled')) : if (!aksrt_ip_geo_master_enabled()) { return false; } + $location = sanitize_key($location); $c = aksrt_get_ip_geo_config(); $display = $c['ip_geo_display'] ?? []; if (!is_array($display)) { $display = [$display]; } - $display = array_map('sanitize_key', $display); - return in_array(sanitize_key($location), $display, true); + $display = array_values(array_unique(array_filter(array_map('sanitize_key', $display)))); + + // Legacy saves only had "comment". When master is on, expand so user/post + // surfaces work without forcing a re-save of the checkbox group. + if ($display === [] || $display === ['comment']) { + $display = ['comment', 'user_home', 'user_center', 'post']; + } + + // Zibll: user home/center are gated by user_city_s, not a separate surface list. + // Still honour an explicit opt-out if the admin removed them from the list after upgrade. + if (in_array($location, ['user_home', 'user_center'], true)) { + if (!aksrt_user_city_enabled()) { + return false; + } + // If list explicitly includes any user surface, require membership; else allow. + $has_user_keys = (bool) array_intersect($display, ['user_home', 'user_center']); + if ($has_user_keys) { + return in_array($location, $display, true); + } + return true; + } + + return in_array($location, $display, true); } endif; @@ -72,9 +94,13 @@ if (!function_exists('aksrt_user_city_enabled')) : */ function aksrt_user_city_enabled(): bool { if (!class_exists('\AKSRT\Settings\Settings')) { - return false; + return true; // zibll default on } $all = \AKSRT\Settings\Settings::get_all(); + // Unset → on (zibll _pz default true). Explicit false turns off. + if (!array_key_exists('user_city_s', $all)) { + return true; + } return !empty($all['user_city_s']); } endif; @@ -238,7 +264,36 @@ if (!function_exists('aksrt_get_user_addr')) : if ((!is_array($raw) || empty($raw)) && metadata_exists('user', $user_id, 'user_addr')) { $raw = get_user_meta($user_id, 'user_addr', true); } - return aksrt_normalize_geo_addr($raw); + $addr = aksrt_normalize_geo_addr($raw); + if ($addr['country'] !== '' || $addr['province'] !== '' || $addr['city'] !== '') { + return $addr; + } + + // Lazy backfill from stored IPs so pages work before next login. + $ips = []; + foreach (['aksrt_register_ip', 'register_ip'] as $k) { + $v = trim((string) get_user_meta($user_id, $k, true)); + if ($v !== '') { + $ips[] = $v; + } + } + // Own profile: refresh from current client IP (zibll updates on login; this covers open sessions). + if ((int) get_current_user_id() === $user_id) { + $cur = function_exists('aksrt_get_client_ip') ? (string) aksrt_get_client_ip() : (string) ($_SERVER['REMOTE_ADDR'] ?? ''); + $cur = trim($cur); + if ($cur !== '') { + array_unshift($ips, $cur); + } + } + $ips = array_values(array_unique(array_filter($ips))); + foreach ($ips as $ip) { + $looked = aksrt_lookup_geo_for_ip($ip); + if ($looked['country'] !== '' || $looked['province'] !== '' || $looked['city'] !== '') { + update_user_meta($user_id, 'aksrt_user_addr', $looked); + return $looked; + } + } + return $addr; } endif; @@ -251,9 +306,10 @@ if (!function_exists('aksrt_get_user_city_badge_html')) : * @param string $class CSS. */ function aksrt_get_user_city_badge_html(int $user_id, string $location = 'user_home', string $class = 'badg'): string { - if ($user_id <= 0 || !aksrt_user_city_enabled()) { + if ($user_id <= 0) { return ''; } + // aksrt_ip_geo_display_enabled already enforces master + user_city for user surfaces. if (!aksrt_ip_geo_display_enabled($location)) { return ''; } diff --git a/inc/helpers/aksrt-single-render.php b/inc/helpers/aksrt-single-render.php index 7af2618e..e8e2306f 100644 --- a/inc/helpers/aksrt-single-render.php +++ b/inc/helpers/aksrt-single-render.php @@ -348,7 +348,7 @@ if (!function_exists('aksrt_single_render_author_card')) : if ($author_id <= 0) { return; } - $author_url = get_author_posts_url($author_id); + $author_url = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url($author_id) : get_author_posts_url($author_id); $author_name = get_the_author(); $bio = trim((string) get_the_author_meta('description')); $name_html = function_exists('aksrt_get_user_name') diff --git a/inc/helpers/comments/item.php b/inc/helpers/comments/item.php index 4c547233..31e3b28c 100644 --- a/inc/helpers/comments/item.php +++ b/inc/helpers/comments/item.php @@ -57,7 +57,7 @@ if (!function_exists('aksrt_get_comments_user_name_html')) : if ($user_id > 0) { $user = get_userdata($user_id); $display = $user instanceof WP_User ? $user->display_name : get_comment_author($comment); - $url = get_author_posts_url($user_id); + $url = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url($user_id) : get_author_posts_url($user_id); $name = '' . esc_html($display) . ''; if (function_exists('aksrt_render_user_identity_chips')) { $name .= aksrt_render_user_identity_chips($user_id, 'comment'); diff --git a/inc/modules/user-parts/routing.php b/inc/modules/user-parts/routing.php index 5e5c0e17..610f5570 100644 --- a/inc/modules/user-parts/routing.php +++ b/inc/modules/user-parts/routing.php @@ -58,37 +58,46 @@ add_filter('template_include', function ($template) { return $resolved_path; } - return $template; - - global $_aksrt_special_templates; - - // A) /user/{昵称} 路由 → 加载公开主页模板 - $nicename = get_query_var('user_nicename'); - if (!empty($nicename)) { + // A) /user/{昵称} even if special-path helper returned empty (user missing → 404). + $nicename = (string) get_query_var('user_nicename'); + if ($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 ($user instanceof WP_User) { + $tpl = aksrt_locate_template_file('templates/pages/page-user-home.php'); + if ($tpl) { + global $aksrt_profile_user; + $aksrt_profile_user = $user; + return $tpl; + } } - if (!$tpl) return $template; - - global $aksrt_profile_user; - $aksrt_profile_user = $user; - return $tpl; + // Unknown nicename: force 404 instead of blank page. + global $wp_query; + if ($wp_query instanceof WP_Query) { + $wp_query->set_404(); + status_header(404); + nocache_headers(); + } + $four = get_query_template('404'); + return $four ?: $template; } - // B) 普通页面 → 检测是否使用了我们的特殊模板,确保加载正确的模板文件 - // (防止 WP 在某些情况下未能正确解析自定义页面模板) + // B) profile slug page without rewrite var (permalink edge). if (is_page()) { $page_id = get_queried_object_id(); if ($page_id) { + $slug = (string) get_post_field('post_name', $page_id); $page_template = get_post_meta($page_id, '_wp_page_template', true); - if ($page_template && strpos($page_template, 'templates/pages/') === 0) { + if ($slug === 'profile' || $page_template === 'templates/pages/page-profile.php') { + $tpl = aksrt_locate_template_file('templates/pages/page-profile.php'); + if ($tpl) { + return $tpl; + } + } + if (is_string($page_template) && strpos($page_template, 'templates/pages/') === 0) { $tpl = aksrt_locate_template_file($page_template); - if ($tpl) return $tpl; + if ($tpl) { + return $tpl; + } } } } @@ -136,26 +145,28 @@ add_filter('template_include', function ($template) { add_action('init', function () { global $_aksrt_special_templates; - // 后台/AJAX:检查并创建缺失页面 + // 后台/AJAX:检查并创建缺失页面(含 profile 用户中心) $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') { + } elseif ($requested_template_key !== '') { aksrt_ensure_template_page($requested_template_key); } - // 统一 flush 检查 - $rewrite_version = AKSRT_VERSION . ':orders-cart-revenue-routing-v1'; + // Always re-assert profile page template (blank WP page with slug profile is common). + if (function_exists('aksrt_ensure_template_page')) { + aksrt_ensure_template_page('profile'); + } + + // 统一 flush 检查 — bump when user-home rewrite / author override changes + $rewrite_version = AKSRT_VERSION . ':user-home-profile-routing-v2'; $flushed = get_option('aksrt_user_rules_flushed'); if ($flushed !== $rewrite_version) { flush_rewrite_rules(false); @@ -168,24 +179,63 @@ add_action('save_post', function ($pid) { if (get_post_type($pid) === 'page') ak add_action('delete_post', function ($pid) { if (get_post_type($pid) === 'page') aksrt_clear_template_page_cache(); }); // ============================================================ -// 六、作者链接改写 +// 六、作者链接改写 — 强制覆盖 WP 默认 /author/{slug}/ // ============================================================ add_filter('author_link', function ($link, $author_id) { + $author_id = (int) $author_id; + if ($author_id > 0 && function_exists('aksrt_get_user_home_url')) { + return aksrt_get_user_home_url($author_id); + } $user = get_userdata($author_id); - $slug = $user ? $user->user_nicename : 'user-' . $author_id; + $slug = $user ? $user->user_nicename : ('user-' . max(0, $author_id)); return home_url('/user/' . trailingslashit($slug)); -}, 10, 2); +}, 99, 2); +// Pretty-permalink author archives → public user home. 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); + if (is_admin() || wp_doing_ajax() || is_feed() || is_embed()) { + return; + } + if (!is_author()) { + return; + } + $author_id = (int) get_queried_object_id(); + if ($author_id <= 0) { + $author_id = (int) get_query_var('author'); + } + if ($author_id <= 0) { + return; + } + $target = function_exists('aksrt_get_user_home_url') + ? aksrt_get_user_home_url($author_id) + : home_url('/user/'); + if ($target === '' || $target === home_url('/')) { + return; + } + wp_safe_redirect($target, 301); + exit; +}, 1); + +// Catch bare ?author=ID when is_author() did not fire. +add_action('template_redirect', function () { + if (is_admin() || wp_doing_ajax()) { + return; + } + if (empty($_GET['author'])) { + return; + } + if (get_query_var('user_nicename') || get_query_var('aksrt_user_center')) { + return; + } + if (is_author()) { + return; // handled above + } + $author_id = (int) $_GET['author']; + if ($author_id > 0 && function_exists('aksrt_get_user_home_url')) { + wp_safe_redirect(aksrt_get_user_home_url($author_id), 301); exit; } -}); +}, 2); // ============================================================ // AJAX: 保存用户个人资料(显示名称、简介、联系方式) diff --git a/inc/modules/user-parts/template-registry.php b/inc/modules/user-parts/template-registry.php index 25b66354..53c3a3bc 100644 --- a/inc/modules/user-parts/template-registry.php +++ b/inc/modules/user-parts/template-registry.php @@ -488,8 +488,16 @@ function aksrt_ensure_template_page(string $key): void { $cfg = $_aksrt_special_templates[$key]; $desired_slug = sanitize_title($cfg['slug'] ?? $key); - // 已有页面使用此模板? - if (aksrt_find_template_page($cfg['file'])) return; + // 已有页面使用此模板?仍校验模板 meta,避免空白默认页。 + $found_page = aksrt_find_template_page($cfg['file']); + if ($found_page instanceof WP_Post) { + $current_tpl = get_post_meta((int) $found_page->ID, '_wp_page_template', true); + if ($current_tpl !== $cfg['file']) { + update_post_meta((int) $found_page->ID, '_wp_page_template', $cfg['file']); + aksrt_clear_template_page_cache(); + } + return; + } if ($desired_slug !== '') { $existing_page = get_page_by_path($desired_slug, OBJECT, 'page'); diff --git a/templates/parts/single-author-bar.php b/templates/parts/single-author-bar.php index bc20a6f5..acdc8881 100644 --- a/templates/parts/single-author-bar.php +++ b/templates/parts/single-author-bar.php @@ -30,7 +30,7 @@ $meta_items = is_array($args['meta_items'] ?? null) ? array_values(array_filter( $author_id = (int) get_the_author_meta('ID'); $author_name = get_the_author(); -$author_url = get_author_posts_url($author_id); +$author_url = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url($author_id) : get_author_posts_url($author_id); $modified_ts = (int) get_the_modified_time('U'); $published_ts = (int) get_the_time('U'); $now = (int) current_time('timestamp');