Merge pull request 'feat(ip-geo): full-chain IP 归属地 on comments, user home, center, post' (#296) from worktree-ip-location-display into main
Reviewed-on: CYL/wordpress-theme-aksrt#296
This commit is contained in:
@@ -7,7 +7,7 @@ export const ipSchema = {
|
||||
ip_geo_enabled: false,
|
||||
ip_addr_sdk: 'null',
|
||||
ip_geo_cache_ttl: 86400,
|
||||
ip_geo_display: ['comment'],
|
||||
ip_geo_display: ['comment', 'user_home', 'user_center', 'post'],
|
||||
ip_geo_format: 'province_city',
|
||||
ip_geo_fallback_text: '',
|
||||
ip_addr_sdk_qq_appkey: '',
|
||||
@@ -59,13 +59,15 @@ export const ipSchema = {
|
||||
key: 'ip_geo_display',
|
||||
label: '展示位置',
|
||||
type: 'checkbox',
|
||||
default: ['comment'],
|
||||
default: ['comment', 'user_home', 'user_center', 'post'],
|
||||
options: [
|
||||
{ label: '评论区', value: 'comment' },
|
||||
{ label: '用户主页', value: 'user_home' },
|
||||
{ label: '文章页', value: 'post' },
|
||||
{ label: '用户中心', value: 'user_center' },
|
||||
{ label: '文章详细页', value: 'post' },
|
||||
],
|
||||
dependsOn: { key: 'ip_geo_enabled', value: true },
|
||||
help: '用户主页/用户中心还需在「用户 → 用户功能」开启「显示城市」;评论区还需在评论设置开启「评论城市」。',
|
||||
},
|
||||
{
|
||||
key: 'ip_geo_format',
|
||||
|
||||
@@ -9,7 +9,8 @@ export const featuresSchema = {
|
||||
user_cover_upload: true,
|
||||
user_social_links: true,
|
||||
user_desc_std: '这家伙很懒…',
|
||||
user_city_s: false,
|
||||
user_city_s: true,
|
||||
user_city_type: 'province',
|
||||
user_join_day_my_name: '本站',
|
||||
user_avatar_default: '',
|
||||
user_cover_img: '',
|
||||
@@ -30,7 +31,19 @@ export const featuresSchema = {
|
||||
{ key: 'user_cover_upload', label: '封面上传', type: 'switch', default: true },
|
||||
{ key: 'user_social_links', label: '社交链接', type: 'switch', default: true },
|
||||
{ key: 'user_desc_std', label: '默认签名', type: 'input', default: '这家伙很懒…', help: '用户未设置个人简介时显示的默认文案' },
|
||||
{ key: 'user_city_s', label: '显示城市', type: 'switch', default: false },
|
||||
{ key: 'user_city_s', label: '显示城市(IP 归属地)', type: 'switch', default: true, help: '根据用户登录 IP 在用户主页与用户中心显示归属地;需同时在「扩展 → IP归属地」启用并勾选对应展示位置' },
|
||||
{
|
||||
key: 'user_city_type',
|
||||
label: '位置精度',
|
||||
type: 'radio',
|
||||
default: 'province',
|
||||
options: [
|
||||
{ label: '省份', value: 'province' },
|
||||
{ label: '省份+城市', value: 'province_city' },
|
||||
{ label: '国家+省份', value: 'country_province' },
|
||||
],
|
||||
dependsOn: { key: 'user_city_s', value: true },
|
||||
},
|
||||
{ key: 'user_join_day_my_name', label: '站名', type: 'input', default: '本站', help: '用于「已加入 X 天」显示中的站点名称' },
|
||||
{ key: 'user_avatar_default', label: '默认头像', type: 'media', default: '' },
|
||||
{ key: 'user_cover_img', label: '默认封面', type: 'media', default: '' },
|
||||
|
||||
@@ -87,3 +87,24 @@
|
||||
#comments .comt-avatar .avatar-img { width: 60px; height: 60px; border-radius: 50%; }
|
||||
#comments .comt-box #comment { min-height: 88px; resize: vertical; }
|
||||
@media (min-width: 768px) { .hide-pc { display: none !important; } }
|
||||
|
||||
/* IP geo badges */
|
||||
.comt-meta .comment-city-badge,
|
||||
.comt-meta .aksrt-ip-geo-badge {
|
||||
margin-left: 0.35em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.aksrt-author-hero__identity .aksrt-ip-geo-badge,
|
||||
.uc-header__meta .aksrt-ip-geo-badge,
|
||||
.article-avatar .aksrt-ip-geo-badge {
|
||||
margin-left: 0.35em;
|
||||
margin-right: 0.15em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.aksrt-author-hero__identity {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
margin-top: 0.35rem;
|
||||
}
|
||||
|
||||
@@ -583,3 +583,6 @@
|
||||
.aksrt-user-home .dashboard-tabs__count.opacity8 {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.aksrt-author-hero__identity { display:flex; flex-wrap:wrap; align-items:center; gap:.35rem; margin-top:.35rem; }
|
||||
.aksrt-author-hero__identity .aksrt-ip-geo-badge { margin:0; }
|
||||
|
||||
@@ -17,6 +17,7 @@ require_once AKSRT_DIR . '/inc/helpers/aksrt-domain-model.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-template-tags.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-frontend-tags.php';
|
||||
// Comment kernel (shared by post / forum / shop surfaces).
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-ip-geo.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/comments/content.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/comments/actions.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/comments/geo.php';
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
<?php
|
||||
/**
|
||||
* IP 归属地 — shared storage, format, and display helpers.
|
||||
*
|
||||
* Display positions (ip_geo_display): comment | user_home | user_center | post
|
||||
* Meta:
|
||||
* comment → aksrt_comment_addr (array)
|
||||
* user → aksrt_user_addr (array), aksrt_register_ip (string)
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_get_ip_geo_config')) :
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
function aksrt_get_ip_geo_config(): array {
|
||||
if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_ip_geo_settings')) {
|
||||
return \AKSRT\Settings\Settings::get_ip_geo_settings();
|
||||
}
|
||||
return [
|
||||
'ip_geo_enabled' => false,
|
||||
'ip_geo_display' => ['comment'],
|
||||
'ip_geo_format' => 'province_city',
|
||||
'ip_geo_fallback_text' => '',
|
||||
];
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_ip_geo_master_enabled')) :
|
||||
function aksrt_ip_geo_master_enabled(): bool {
|
||||
$c = aksrt_get_ip_geo_config();
|
||||
return !empty($c['ip_geo_enabled']);
|
||||
}
|
||||
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 {
|
||||
if (!aksrt_ip_geo_master_enabled()) {
|
||||
return false;
|
||||
}
|
||||
$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);
|
||||
}
|
||||
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'));
|
||||
return in_array($format, ['province_city', 'province', 'country_province'], true)
|
||||
? $format
|
||||
: 'province_city';
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_user_city_enabled')) :
|
||||
/**
|
||||
* Users feature switch (user home / user center), independent of comment city_s.
|
||||
*/
|
||||
function aksrt_user_city_enabled(): bool {
|
||||
if (!class_exists('\AKSRT\Settings\Settings')) {
|
||||
return false;
|
||||
}
|
||||
$all = \AKSRT\Settings\Settings::get_all();
|
||||
return !empty($all['user_city_s']);
|
||||
}
|
||||
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';
|
||||
}
|
||||
return aksrt_ip_geo_format_key();
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_normalize_geo_addr')) :
|
||||
/**
|
||||
* @param mixed $raw Meta value.
|
||||
* @return array{country:string,province:string,city:string}
|
||||
*/
|
||||
function aksrt_normalize_geo_addr($raw): array {
|
||||
if (!is_array($raw)) {
|
||||
return ['country' => '', 'province' => '', 'city' => ''];
|
||||
}
|
||||
// Accept zibll-shaped nation → country.
|
||||
$country = trim((string) ($raw['country'] ?? $raw['nation'] ?? ''));
|
||||
return [
|
||||
'country' => $country,
|
||||
'province' => trim((string) ($raw['province'] ?? '')),
|
||||
'city' => trim((string) ($raw['city'] ?? '')),
|
||||
];
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_format_geo_label')) :
|
||||
/**
|
||||
* @param array<string,string> $addr Addr.
|
||||
* @param string $type Format key.
|
||||
*/
|
||||
function aksrt_format_geo_label(array $addr, string $type = 'province_city'): string {
|
||||
$addr = aksrt_normalize_geo_addr($addr);
|
||||
if (class_exists('\AKSRT\Extensions\IPGeo')) {
|
||||
$label = \AKSRT\Extensions\IPGeo::get_instance()->format($addr, $type);
|
||||
if (is_string($label) && $label !== '') {
|
||||
return $label;
|
||||
}
|
||||
}
|
||||
// Local fallback (mirrors IPGeo::format).
|
||||
switch ($type) {
|
||||
case 'province':
|
||||
return $addr['province'] !== '' ? $addr['province'] : $addr['city'];
|
||||
case 'country_province':
|
||||
return trim($addr['country'] . ' ' . $addr['province']);
|
||||
case 'province_city':
|
||||
default:
|
||||
$parts = array_filter([$addr['province'], $addr['city']]);
|
||||
if (empty($parts) && $addr['country'] !== '') {
|
||||
return $addr['country'];
|
||||
}
|
||||
return implode(' ', $parts);
|
||||
}
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_get_geo_badge_html')) :
|
||||
/**
|
||||
* @param array<string,string>|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);
|
||||
if ($label === '') {
|
||||
$fallback = (string) (aksrt_get_ip_geo_config()['ip_geo_fallback_text'] ?? '');
|
||||
if ($fallback === '') {
|
||||
return '';
|
||||
}
|
||||
$label = $fallback;
|
||||
}
|
||||
if ($title === '') {
|
||||
$title = __('IP 属地', 'aksrt');
|
||||
}
|
||||
$class = trim($class . ' aksrt-ip-geo-badge');
|
||||
return '<span class="' . esc_attr($class) . '" title="' . esc_attr($title) . '">' . esc_html($label) . '</span>';
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_lookup_geo_for_ip')) :
|
||||
/**
|
||||
* @return array{country:string,province:string,city:string}
|
||||
*/
|
||||
function aksrt_lookup_geo_for_ip(string $ip): array {
|
||||
$ip = trim($ip);
|
||||
if ($ip === '' || !class_exists('\AKSRT\Extensions\IPGeo')) {
|
||||
return ['country' => '', 'province' => '', 'city' => ''];
|
||||
}
|
||||
$geo = \AKSRT\Extensions\IPGeo::get_instance()->lookup($ip);
|
||||
return aksrt_normalize_geo_addr(is_array($geo) ? $geo : []);
|
||||
}
|
||||
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.
|
||||
*/
|
||||
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');
|
||||
if (!$need) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($ip === null || $ip === '') {
|
||||
$ip = function_exists('aksrt_get_client_ip') ? (string) aksrt_get_client_ip() : (string) ($_SERVER['REMOTE_ADDR'] ?? '');
|
||||
}
|
||||
$ip = trim($ip);
|
||||
if ($ip === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$addr = aksrt_lookup_geo_for_ip($ip);
|
||||
if ($addr['country'] === '' && $addr['province'] === '' && $addr['city'] === '') {
|
||||
return;
|
||||
}
|
||||
update_user_meta($user_id, 'aksrt_user_addr', $addr);
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_get_user_addr')) :
|
||||
/**
|
||||
* @param int $user_id User ID.
|
||||
* @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);
|
||||
}
|
||||
return aksrt_normalize_geo_addr($raw);
|
||||
}
|
||||
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 || !aksrt_user_city_enabled()) {
|
||||
return '';
|
||||
}
|
||||
if (!aksrt_ip_geo_display_enabled($location)) {
|
||||
return '';
|
||||
}
|
||||
return aksrt_get_geo_badge_html(aksrt_get_user_addr($user_id), aksrt_user_city_type(), $class);
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_get_post_author_city_badge_html')) :
|
||||
/**
|
||||
* Article detail author IP 属地 (uses author last-login 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')) {
|
||||
return '';
|
||||
}
|
||||
if ($author_id <= 0) {
|
||||
$author_id = (int) get_the_author_meta('ID');
|
||||
}
|
||||
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) {
|
||||
$user_id = (int) $user->ID;
|
||||
} elseif (is_string($user_login) && $user_login !== '') {
|
||||
$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')) {
|
||||
aksrt_store_user_addr($user_id);
|
||||
}
|
||||
}, 20, 2);
|
||||
|
||||
add_action('user_register', static function ($user_id): void {
|
||||
$user_id = (int) $user_id;
|
||||
if ($user_id <= 0) {
|
||||
return;
|
||||
}
|
||||
$ip = function_exists('aksrt_get_client_ip') ? (string) aksrt_get_client_ip() : (string) ($_SERVER['REMOTE_ADDR'] ?? '');
|
||||
$ip = trim($ip);
|
||||
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);
|
||||
}
|
||||
}, 20, 1);
|
||||
@@ -2,7 +2,8 @@
|
||||
/**
|
||||
* Comment city / IP geo helpers.
|
||||
*
|
||||
* Meta key: aksrt_comment_addr (array|string from IPGeo).
|
||||
* Meta key: aksrt_comment_addr (array from IPGeo).
|
||||
* Gates: extensions.ip_geo_enabled + ip_geo_display includes comment + comment_city_s.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
@@ -14,6 +15,21 @@ 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()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!class_exists('\AKSRT\Settings\Settings')) {
|
||||
return false;
|
||||
}
|
||||
@@ -28,7 +44,7 @@ if (!function_exists('aksrt_comment_city_type')) :
|
||||
*/
|
||||
function aksrt_comment_city_type(): string {
|
||||
if (!class_exists('\AKSRT\Settings\Settings')) {
|
||||
return 'province_city';
|
||||
return function_exists('aksrt_ip_geo_format_key') ? aksrt_ip_geo_format_key() : 'province_city';
|
||||
}
|
||||
$s = \AKSRT\Settings\Settings::get_comment_display_settings();
|
||||
$type = sanitize_key((string) ($s['city_type'] ?? 'province_city'));
|
||||
@@ -54,19 +70,21 @@ if (!function_exists('aksrt_store_comment_addr')) :
|
||||
$ip = $comment instanceof WP_Comment ? (string) $comment->comment_author_IP : '';
|
||||
}
|
||||
$ip = trim((string) $ip);
|
||||
if ($ip === '' || !class_exists('\AKSRT\Extensions\IPGeo')) {
|
||||
if ($ip === '') {
|
||||
return;
|
||||
}
|
||||
$geo = \AKSRT\Extensions\IPGeo::get_instance()->lookup($ip);
|
||||
if (!is_array($geo)) {
|
||||
if (function_exists('aksrt_lookup_geo_for_ip')) {
|
||||
$addr = aksrt_lookup_geo_for_ip($ip);
|
||||
} elseif (class_exists('\AKSRT\Extensions\IPGeo')) {
|
||||
$geo = \AKSRT\Extensions\IPGeo::get_instance()->lookup($ip);
|
||||
$addr = [
|
||||
'country' => (string) ($geo['country'] ?? ''),
|
||||
'province' => (string) ($geo['province'] ?? ''),
|
||||
'city' => (string) ($geo['city'] ?? ''),
|
||||
];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
// Store compact array.
|
||||
$addr = [
|
||||
'country' => (string) ($geo['country'] ?? ''),
|
||||
'province' => (string) ($geo['province'] ?? ''),
|
||||
'city' => (string) ($geo['city'] ?? ''),
|
||||
];
|
||||
if ($addr['country'] === '' && $addr['province'] === '' && $addr['city'] === '') {
|
||||
return;
|
||||
}
|
||||
@@ -85,6 +103,9 @@ if (!function_exists('aksrt_get_comment_addr')) :
|
||||
return [];
|
||||
}
|
||||
$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 : [];
|
||||
}
|
||||
endif;
|
||||
@@ -97,6 +118,9 @@ if (!function_exists('aksrt_format_comment_city_label')) :
|
||||
* @param string $type Format.
|
||||
*/
|
||||
function aksrt_format_comment_city_label(array $addr, string $type = 'province_city'): string {
|
||||
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'] ?? ''));
|
||||
@@ -125,7 +149,14 @@ if (!function_exists('aksrt_get_comment_city_badge_html')) :
|
||||
if (!aksrt_comment_city_enabled()) {
|
||||
return '';
|
||||
}
|
||||
$addr = aksrt_get_comment_addr($comment);
|
||||
if (function_exists('aksrt_get_geo_badge_html')) {
|
||||
return aksrt_get_geo_badge_html(
|
||||
aksrt_get_comment_addr($comment),
|
||||
aksrt_comment_city_type(),
|
||||
'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 '';
|
||||
|
||||
@@ -49,7 +49,7 @@ extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="uc-header__meta">
|
||||
<div class="uc-header__meta desc user-identity flex ac hh">
|
||||
<span class="uc-header__meta-item" title="<?php esc_attr_e('用户名', 'aksrt'); ?>">
|
||||
<i class="fas fa-user" aria-hidden="true"></i> <?php echo esc_html($target_user->user_login); ?>
|
||||
</span>
|
||||
@@ -58,6 +58,15 @@ extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_
|
||||
<i class="fas fa-envelope" aria-hidden="true"></i> <?php echo esc_html($target_user->user_email); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
// IP 归属地 (zibll user_page_header_desc + user_city_s).
|
||||
$uc_city = function_exists('aksrt_get_user_city_badge_html')
|
||||
? aksrt_get_user_city_badge_html((int) $user_id, 'user_center', 'badg')
|
||||
: '';
|
||||
if ($uc_city !== '') {
|
||||
echo $uc_city; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uc-header__actions">
|
||||
|
||||
@@ -33,10 +33,11 @@ class SchemaExtensionsIP {
|
||||
['key' => 'ip_addr_sdk_amap_secretkey', 'label' => '高德 SecretKey', 'type' => 'input', 'default' => ''],
|
||||
]],
|
||||
['key' => 'display', 'title' => '展示设置', 'fields' => [
|
||||
['key' => 'ip_geo_display', 'label' => '展示位置', 'type' => 'checkbox', 'default' => ['comment'], 'sanitize_type' => 'array', 'options' => [
|
||||
['key' => 'ip_geo_display', 'label' => '展示位置', 'type' => 'checkbox', 'default' => ['comment', 'user_home', 'user_center', 'post'], 'sanitize_type' => 'array', 'options' => [
|
||||
['label' => '评论区', 'value' => 'comment'],
|
||||
['label' => '用户主页', 'value' => 'user_home'],
|
||||
['label' => '文章页', 'value' => 'post'],
|
||||
['label' => '用户中心', 'value' => 'user_center'],
|
||||
['label' => '文章详细页', 'value' => 'post'],
|
||||
]],
|
||||
['key' => 'ip_geo_format', 'label' => '显示格式', 'type' => 'radio', 'default' => 'province_city', 'options' => [
|
||||
['label' => '省份+城市', 'value' => 'province_city'],
|
||||
|
||||
@@ -520,7 +520,12 @@ class SchemaUsers {
|
||||
['key' => 'user_cover_upload', 'label' => '封面上传', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'user_social_links', 'label' => '社交链接', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'user_desc_std', 'label' => '默认签名', 'type' => 'input', 'default' => '这家伙很懒…', 'desc' => '用户未设置个人简介时显示的默认文案'],
|
||||
['key' => 'user_city_s', 'label' => '显示城市', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'user_city_s', 'label' => '显示城市(IP 归属地)', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'user_city_type', 'label' => '位置精度', 'type' => 'radio', 'default' => 'province', 'options' => [
|
||||
['label' => '省份', 'value' => 'province'],
|
||||
['label' => '省份+城市', 'value' => 'province_city'],
|
||||
['label' => '国家+省份', 'value' => 'country_province'],
|
||||
]],
|
||||
['key' => 'user_join_day_my_name', 'label' => '站名', 'type' => 'input', 'default' => '本站', 'desc' => '用于「已加入 X 天」显示中的站点名称'],
|
||||
['key' => 'user_avatar_default', 'label' => '默认头像', 'type' => 'media', 'default' => ''],
|
||||
['key' => 'user_cover_img', 'label' => '默认封面', 'type' => 'media', 'default' => ''],
|
||||
|
||||
@@ -53,8 +53,14 @@ class ExtensionRuntime {
|
||||
$provider = 'null';
|
||||
}
|
||||
|
||||
$display_raw = $settings['ip_geo_display'] ?? ['comment'];
|
||||
$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))));
|
||||
$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'];
|
||||
}
|
||||
|
||||
$format = sanitize_key((string) ($settings['ip_geo_format'] ?? 'province_city'));
|
||||
if (!in_array($format, ['province_city', 'province', 'country_province'], true)) {
|
||||
|
||||
@@ -94,6 +94,15 @@ $is_self = is_user_logged_in() && get_current_user_id() === $author_id;
|
||||
<?php if ($show_time) : ?>
|
||||
<span class="icon-circle" title="<?php echo esc_attr($abs_fmt); ?>" data-toggle="tooltip"><?php echo esc_html($time_text); ?></span>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
// Article detail IP 归属地 (extension display: post).
|
||||
$post_city = function_exists('aksrt_get_post_author_city_badge_html')
|
||||
? aksrt_get_post_author_city_badge_html($author_id, 'badg badg-sm')
|
||||
: '';
|
||||
if ($post_city !== '') {
|
||||
echo $post_city; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
?>
|
||||
<?php if ($show_bio) : ?>
|
||||
<?php $bio = trim((string) get_the_author_meta('description')); ?>
|
||||
<?php if ($bio !== '') : ?>
|
||||
|
||||
@@ -112,19 +112,30 @@ $pm_url = ($pm_enabled && $messages_url !== '')
|
||||
}
|
||||
?>
|
||||
|
||||
<?php if ($show_desc && $user->description) : ?>
|
||||
<p class="aksrt-author-hero__desc"><?php echo esc_html($user->description); ?></p>
|
||||
<?php
|
||||
// IP 归属地 (zibll author_header_identity / user_city_s).
|
||||
$city_badge = function_exists('aksrt_get_user_city_badge_html')
|
||||
? aksrt_get_user_city_badge_html($user_id, 'user_home', 'badg')
|
||||
: '';
|
||||
?>
|
||||
<?php if ($city_badge !== '' || !empty($signals)) : ?>
|
||||
<div class="aksrt-author-hero__identity user-identity flex ac hh">
|
||||
<?php if ($city_badge !== '') : ?>
|
||||
<?php echo $city_badge; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($signals)) : ?>
|
||||
<?php foreach ($signals as $signal) : ?>
|
||||
<span class="aksrt-identity-chip aksrt-identity-chip--<?php echo esc_attr($signal['tone']); ?>">
|
||||
<i class="fas fa-<?php echo esc_attr($signal['icon']); ?>" aria-hidden="true"></i>
|
||||
<span><?php echo esc_html($signal['label']); ?></span>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($signals)) : ?>
|
||||
<div class="aksrt-identity-chips">
|
||||
<?php foreach ($signals as $signal) : ?>
|
||||
<span class="aksrt-identity-chip aksrt-identity-chip--<?php echo esc_attr($signal['tone']); ?>">
|
||||
<i class="fas fa-<?php echo esc_attr($signal['icon']); ?>" aria-hidden="true"></i>
|
||||
<span><?php echo esc_html($signal['label']); ?></span>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ($show_desc && $user->description) : ?>
|
||||
<p class="aksrt-author-hero__desc"><?php echo esc_html($user->description); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($notice) && is_array($notice)) : ?>
|
||||
|
||||
Reference in New Issue
Block a user