diff --git a/inc/helpers/aksrt-ip-geo.php b/inc/helpers/aksrt-ip-geo.php index 20501c62..807b63c4 100644 --- a/inc/helpers/aksrt-ip-geo.php +++ b/inc/helpers/aksrt-ip-geo.php @@ -1,11 +1,16 @@ false, - 'ip_geo_display' => ['comment'], + 'ip_geo_display' => ['comment', 'user_home', 'user_center', 'post'], 'ip_geo_format' => 'province_city', 'ip_geo_fallback_text' => '', ]; @@ -31,15 +36,34 @@ endif; if (!function_exists('aksrt_ip_geo_master_enabled')) : function aksrt_ip_geo_master_enabled(): bool { + return !empty(aksrt_get_ip_geo_config()['ip_geo_enabled']); + } +endif; + +if (!function_exists('aksrt_ip_geo_display_list')) : + /** + * @return list + */ + function aksrt_ip_geo_display_list(): array { $c = aksrt_get_ip_geo_config(); - return !empty($c['ip_geo_enabled']); + $display = $c['ip_geo_display'] ?? []; + if (!is_array($display)) { + $display = []; + } + $allowed = ['comment', 'user_home', 'user_center', 'post']; + $out = []; + foreach ($display as $item) { + $key = sanitize_key((string) $item); + if (in_array($key, $allowed, true) && !in_array($key, $out, true)) { + $out[] = $key; + } + } + return $out; } endif; if (!function_exists('aksrt_ip_geo_display_enabled')) : /** - * Whether a surface may show IP 归属地 badges. - * * @param string $location comment|user_home|user_center|post */ function aksrt_ip_geo_display_enabled(string $location): bool { @@ -47,41 +71,19 @@ if (!function_exists('aksrt_ip_geo_display_enabled')) : return false; } $location = sanitize_key($location); - $c = aksrt_get_ip_geo_config(); - $display = $c['ip_geo_display'] ?? []; - if (!is_array($display)) { - $display = [$display]; + if (!in_array($location, aksrt_ip_geo_display_list(), true)) { + return false; } - $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']; + if (in_array($location, ['user_home', 'user_center'], true) && !aksrt_user_city_enabled()) { + return false; } - - // 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); + return true; } endif; if (!function_exists('aksrt_ip_geo_format_key')) : function aksrt_ip_geo_format_key(): string { - $c = aksrt_get_ip_geo_config(); - $format = sanitize_key((string) ($c['ip_geo_format'] ?? 'province_city')); + $format = sanitize_key((string) (aksrt_get_ip_geo_config()['ip_geo_format'] ?? 'province_city')); return in_array($format, ['province_city', 'province', 'country_province'], true) ? $format : 'province_city'; @@ -90,14 +92,14 @@ endif; if (!function_exists('aksrt_user_city_enabled')) : /** - * Users feature switch (user home / user center), independent of comment city_s. + * Users feature: show city on user home / user center. + * Default true when key absent (zibll parity for new installs). */ function aksrt_user_city_enabled(): bool { if (!class_exists('\AKSRT\Settings\Settings')) { - return true; // zibll default on + return true; } $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; } @@ -106,24 +108,14 @@ if (!function_exists('aksrt_user_city_enabled')) : endif; if (!function_exists('aksrt_user_city_type')) : - /** - * User-facing precision (maps to shared format keys). - */ function aksrt_user_city_type(): string { if (!class_exists('\AKSRT\Settings\Settings')) { return aksrt_ip_geo_format_key(); } $all = \AKSRT\Settings\Settings::get_all(); $type = sanitize_key((string) ($all['user_city_type'] ?? '')); - // zibll: pro / city - if ($type === 'pro' || $type === 'province') { - return 'province'; - } - if ($type === 'city' || $type === 'province_city') { - return 'province_city'; - } - if ($type === 'country_province') { - return 'country_province'; + if (in_array($type, ['province_city', 'province', 'country_province'], true)) { + return $type; } return aksrt_ip_geo_format_key(); } @@ -138,10 +130,8 @@ if (!function_exists('aksrt_normalize_geo_addr')) : if (!is_array($raw)) { return ['country' => '', 'province' => '', 'city' => '']; } - // Accept zibll-shaped nation → country. - $country = trim((string) ($raw['country'] ?? $raw['nation'] ?? '')); return [ - 'country' => $country, + 'country' => trim((string) ($raw['country'] ?? '')), 'province' => trim((string) ($raw['province'] ?? '')), 'city' => trim((string) ($raw['city'] ?? '')), ]; @@ -161,7 +151,6 @@ if (!function_exists('aksrt_format_geo_label')) : return $label; } } - // Local fallback (mirrors IPGeo::format). switch ($type) { case 'province': return $addr['province'] !== '' ? $addr['province'] : $addr['city']; @@ -180,10 +169,10 @@ endif; if (!function_exists('aksrt_get_geo_badge_html')) : /** - * @param array|mixed $addr Addr meta. - * @param string $type Format. - * @param string $class CSS classes. - * @param string $title Title attr. + * @param array|mixed $addr Addr meta. + * @param string $type Format. + * @param string $class CSS classes. + * @param string $title Title attr. */ function aksrt_get_geo_badge_html($addr, string $type = 'province_city', string $class = 'badg badg-sm', string $title = ''): string { $label = aksrt_format_geo_label(is_array($addr) ? $addr : [], $type); @@ -218,18 +207,16 @@ endif; if (!function_exists('aksrt_store_user_addr')) : /** - * Resolve current client IP and persist user meta. - * Zibll: refresh on every login when user_city_s is on. - * Also refresh when article (post) display needs author addr. + * Resolve IP and write aksrt_user_addr (login / register / own-page refresh). */ function aksrt_store_user_addr(int $user_id, ?string $ip = null): void { if ($user_id <= 0 || !aksrt_ip_geo_master_enabled()) { return; } $need = aksrt_user_city_enabled() - || aksrt_ip_geo_display_enabled('post') - || aksrt_ip_geo_display_enabled('user_home') - || aksrt_ip_geo_display_enabled('user_center'); + || in_array('post', aksrt_ip_geo_display_list(), true) + || in_array('user_home', aksrt_ip_geo_display_list(), true) + || in_array('user_center', aksrt_ip_geo_display_list(), true); if (!$need) { return; } @@ -252,46 +239,22 @@ endif; if (!function_exists('aksrt_get_user_addr')) : /** - * @param int $user_id User ID. + * Read aksrt_user_addr; if empty and viewing self, resolve current client IP once. + * * @return array{country:string,province:string,city:string} */ function aksrt_get_user_addr(int $user_id): array { if ($user_id <= 0) { return ['country' => '', 'province' => '', 'city' => '']; } - $raw = get_user_meta($user_id, 'aksrt_user_addr', true); - // Legacy / accidental zibll key. - if ((!is_array($raw) || empty($raw)) && metadata_exists('user', $user_id, 'user_addr')) { - $raw = get_user_meta($user_id, 'user_addr', true); - } - $addr = aksrt_normalize_geo_addr($raw); + $addr = aksrt_normalize_geo_addr(get_user_meta($user_id, 'aksrt_user_addr', true)); 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; - } + // Self view: write-on-read from current IP (same outcome as next login). + if ((int) get_current_user_id() === $user_id && aksrt_ip_geo_master_enabled()) { + aksrt_store_user_addr($user_id); + return aksrt_normalize_geo_addr(get_user_meta($user_id, 'aksrt_user_addr', true)); } return $addr; } @@ -299,18 +262,12 @@ endif; if (!function_exists('aksrt_get_user_city_badge_html')) : /** - * Badge for user home / user center (requires user_city_s + display location). - * * @param int $user_id User. * @param string $location user_home|user_center * @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) { - return ''; - } - // aksrt_ip_geo_display_enabled already enforces master + user_city for user surfaces. - if (!aksrt_ip_geo_display_enabled($location)) { + if ($user_id <= 0 || !aksrt_ip_geo_display_enabled($location)) { return ''; } return aksrt_get_geo_badge_html(aksrt_get_user_addr($user_id), aksrt_user_city_type(), $class); @@ -319,7 +276,7 @@ endif; if (!function_exists('aksrt_get_post_author_city_badge_html')) : /** - * Article detail author IP 属地 (uses author last-login addr). + * Article author IP 属地 (author aksrt_user_addr). */ function aksrt_get_post_author_city_badge_html(int $author_id = 0, string $class = 'badg badg-sm'): string { if (!aksrt_ip_geo_display_enabled('post')) { @@ -331,14 +288,11 @@ if (!function_exists('aksrt_get_post_author_city_badge_html')) : if ($author_id <= 0) { return ''; } - // Prefer user_city type when feature on; else global format. $type = aksrt_user_city_enabled() ? aksrt_user_city_type() : aksrt_ip_geo_format_key(); return aksrt_get_geo_badge_html(aksrt_get_user_addr($author_id), $type, $class); } endif; -// ── Hooks: persist on login / register ────────────────────────────────────── - add_action('wp_login', static function ($user_login, $user = null): void { $user_id = 0; if ($user instanceof WP_User) { @@ -347,7 +301,7 @@ add_action('wp_login', static function ($user_login, $user = null): void { $u = get_user_by('login', $user_login); $user_id = $u instanceof WP_User ? (int) $u->ID : 0; } - if ($user_id > 0 && function_exists('aksrt_store_user_addr')) { + if ($user_id > 0) { aksrt_store_user_addr($user_id); } }, 20, 2); @@ -362,7 +316,5 @@ add_action('user_register', static function ($user_id): void { if ($ip !== '') { update_user_meta($user_id, 'aksrt_register_ip', $ip); } - if (function_exists('aksrt_store_user_addr')) { - aksrt_store_user_addr($user_id, $ip !== '' ? $ip : null); - } + aksrt_store_user_addr($user_id, $ip !== '' ? $ip : null); }, 20, 1); diff --git a/inc/helpers/comments/geo.php b/inc/helpers/comments/geo.php index f50de985..44841dc2 100644 --- a/inc/helpers/comments/geo.php +++ b/inc/helpers/comments/geo.php @@ -2,8 +2,8 @@ /** * Comment city / IP geo helpers. * - * Meta key: aksrt_comment_addr (array from IPGeo). - * Gates: extensions.ip_geo_enabled + ip_geo_display includes comment + comment_city_s. + * Meta: aksrt_comment_addr {country,province,city} + * Gates: ip_geo_enabled + ip_geo_display has comment + comment_city_s * * @package AKSRT */ @@ -11,25 +11,10 @@ defined('ABSPATH') || exit; if (!function_exists('aksrt_comment_city_enabled')) : - /** - * Whether comment city badges are enabled. - */ function aksrt_comment_city_enabled(): bool { - // Prefer shared display gate when available. - if (function_exists('aksrt_ip_geo_display_enabled')) { - if (!aksrt_ip_geo_display_enabled('comment')) { - // Allow legacy path: comment_city_s alone still works if master is on - // but display list empty — require master + city_s at minimum. - if (!function_exists('aksrt_ip_geo_master_enabled') || !aksrt_ip_geo_master_enabled()) { - return false; - } - // Master on but location not selected → off. - return false; - } - } elseif (function_exists('aksrt_ip_geo_master_enabled') && !aksrt_ip_geo_master_enabled()) { + if (function_exists('aksrt_ip_geo_display_enabled') && !aksrt_ip_geo_display_enabled('comment')) { return false; } - if (!class_exists('\AKSRT\Settings\Settings')) { return false; } @@ -39,9 +24,6 @@ if (!function_exists('aksrt_comment_city_enabled')) : endif; if (!function_exists('aksrt_comment_city_type')) : - /** - * Display format key for city badge. - */ function aksrt_comment_city_type(): string { if (!class_exists('\AKSRT\Settings\Settings')) { return function_exists('aksrt_ip_geo_format_key') ? aksrt_ip_geo_format_key() : 'province_city'; @@ -56,8 +38,6 @@ endif; if (!function_exists('aksrt_store_comment_addr')) : /** - * Resolve IP geo and persist on comment. - * * @param int $comment_id Comment ID. * @param string|null $ip Optional IP override. */ @@ -95,25 +75,23 @@ endif; if (!function_exists('aksrt_get_comment_addr')) : /** * @param int|WP_Comment $comment Comment. - * @return array{country?:string,province?:string,city?:string} + * @return array{country:string,province:string,city:string} */ function aksrt_get_comment_addr($comment): array { $comment_id = $comment instanceof WP_Comment ? (int) $comment->comment_ID : (int) $comment; if ($comment_id <= 0) { - return []; + return ['country' => '', 'province' => '', 'city' => '']; } $raw = get_comment_meta($comment_id, 'aksrt_comment_addr', true); if (function_exists('aksrt_normalize_geo_addr')) { return aksrt_normalize_geo_addr($raw); } - return is_array($raw) ? $raw : []; + return is_array($raw) ? $raw : ['country' => '', 'province' => '', 'city' => '']; } endif; if (!function_exists('aksrt_format_comment_city_label')) : /** - * Format addr array into display string. - * * @param array $addr Addr. * @param string $type Format. */ @@ -121,30 +99,11 @@ if (!function_exists('aksrt_format_comment_city_label')) : if (function_exists('aksrt_format_geo_label')) { return aksrt_format_geo_label($addr, $type); } - $country = trim((string) ($addr['country'] ?? '')); - $province = trim((string) ($addr['province'] ?? '')); - $city = trim((string) ($addr['city'] ?? '')); - switch ($type) { - case 'province': - return $province !== '' ? $province : $city; - case 'country_province': - $parts = array_filter([$country, $province]); - return implode(' ', $parts); - case 'province_city': - default: - $parts = array_filter([$province, $city]); - if (empty($parts) && $country !== '') { - return $country; - } - return implode(' ', $parts); - } + return ''; } endif; if (!function_exists('aksrt_get_comment_city_badge_html')) : - /** - * HTML badge for comment city (empty string if disabled/missing). - */ function aksrt_get_comment_city_badge_html($comment): string { if (!aksrt_comment_city_enabled()) { return ''; @@ -156,16 +115,10 @@ if (!function_exists('aksrt_get_comment_city_badge_html')) : 'badg badg-sm comment-city-badge' ); } - $addr = aksrt_get_comment_addr($comment); - $label = aksrt_format_comment_city_label($addr, aksrt_comment_city_type()); - if ($label === '') { - return ''; - } - return '' . esc_html($label) . ''; + return ''; } endif; -// Persist geo after any successful insert (covers REST + core). add_action('comment_post', static function ($comment_id): void { if (function_exists('aksrt_store_comment_addr')) { aksrt_store_comment_addr((int) $comment_id); diff --git a/src/AKSRT/Extensions/IPGeo.php b/src/AKSRT/Extensions/IPGeo.php index c86e0159..e00ee7f2 100644 --- a/src/AKSRT/Extensions/IPGeo.php +++ b/src/AKSRT/Extensions/IPGeo.php @@ -44,7 +44,7 @@ class IPGeo { } } - $provider = sanitize_key((string) ($config['ip_addr_sdk'] ?? ($config['ip_geo_provider'] ?? 'null'))); + $provider = sanitize_key((string) ($config['ip_addr_sdk'] ?? 'null')); $result = $this->query_provider($provider, $ip, $config); if (!empty($result['province']) || !empty($result['city']) || !empty($result['country'])) { @@ -66,7 +66,7 @@ class IPGeo { */ public function get_status(): array { $config = $this->get_config(); - $provider = sanitize_key((string) ($config['ip_addr_sdk'] ?? ($config['ip_geo_provider'] ?? 'null'))); + $provider = sanitize_key((string) ($config['ip_addr_sdk'] ?? 'null')); $enabled = !empty($config['ip_geo_enabled']); $missing = []; @@ -88,7 +88,7 @@ class IPGeo { 'transport' => 'http_api', 'missing_fields' => $missing, 'cache_ttl' => (int) ($config['ip_geo_cache_ttl'] ?? 86400), - 'display' => (array) ($config['ip_geo_display'] ?? ['comment']), + 'display' => (array) ($config['ip_geo_display'] ?? ['comment', 'user_home', 'user_center', 'post']), 'format' => (string) ($config['ip_geo_format'] ?? 'province_city'), ]; } diff --git a/src/AKSRT/Settings/ExtensionRuntime.php b/src/AKSRT/Settings/ExtensionRuntime.php index be43f120..4dfc34c2 100644 --- a/src/AKSRT/Settings/ExtensionRuntime.php +++ b/src/AKSRT/Settings/ExtensionRuntime.php @@ -47,19 +47,25 @@ class ExtensionRuntime { public static function get_ip_geo_settings(): array { $settings = Settings::get_all(); - $provider = sanitize_key((string) ($settings['ip_addr_sdk'] ?? ($settings['ip_geo_provider'] ?? 'null'))); + $provider = sanitize_key((string) ($settings['ip_addr_sdk'] ?? 'null')); $allowed = ['polling', 'qq', 'amap', 'null']; if (!in_array($provider, $allowed, true)) { $provider = 'null'; } $display_raw = $settings['ip_geo_display'] ?? ['comment', 'user_home', 'user_center', 'post']; - $display = is_array($display_raw) ? $display_raw : [$display_raw]; - $display = array_values(array_unique(array_filter(array_map('sanitize_key', $display)))); + $display = is_array($display_raw) ? $display_raw : []; $allowed_display = ['comment', 'user_home', 'user_center', 'post']; - $display = array_values(array_filter($display, static fn($v) => in_array($v, $allowed_display, true))); - if ($display === []) { - $display = ['comment', 'user_home', 'user_center', 'post']; + $display_norm = []; + foreach ($display as $item) { + $key = sanitize_key((string) $item); + if (in_array($key, $allowed_display, true) && !in_array($key, $display_norm, true)) { + $display_norm[] = $key; + } + } + // Empty / missing → full four surfaces (canonical default). + if ($display_norm === []) { + $display_norm = $allowed_display; } $format = sanitize_key((string) ($settings['ip_geo_format'] ?? 'province_city')); @@ -70,9 +76,8 @@ class ExtensionRuntime { return [ 'ip_geo_enabled' => !empty($settings['ip_geo_enabled']), 'ip_addr_sdk' => $provider, - 'ip_geo_provider' => $provider, 'ip_geo_cache_ttl' => max(3600, (int) ($settings['ip_geo_cache_ttl'] ?? 86400)), - 'ip_geo_display' => $display, + 'ip_geo_display' => $display_norm, 'ip_geo_format' => $format, 'ip_geo_fallback_text' => (string) ($settings['ip_geo_fallback_text'] ?? ''), 'ip_addr_sdk_qq_appkey' => (string) ($settings['ip_addr_sdk_qq_appkey'] ?? ''),