markup, contact option labels, * and public social-link renderer. Local SVG inventory removed. * * @package AKSRT * @version 3.4.0 */ defined('ABSPATH') || exit; // ============================================================ // PHP 7.x 兼容辅助函数(替代 PHP 8.0+ 的 match 表达式) // ============================================================ if (!function_exists('aksrt_parse_country_list')): /** * 解析 GeoIP 屏蔽国家列表字符串为数组 * * @param string $raw 逗号分隔的国家代码 * @return array 大写国家代码数组 */ function aksrt_parse_country_list($raw) { if (empty($raw)) return array(); $parts = explode(',', wp_unslash($raw)); $result = array(); foreach ($parts as $p) { $trimmed = trim($p); if ($trimmed !== '') { $result[] = strtoupper($trimmed); } } return array_values(array_filter($result)); } endif; // ============================================================ // Brand icon map (FA 5.15.4 free) // ============================================================ if (!function_exists('aksrt_brand_icon_map')) : /** * Short key → FA5 class string (allowlisted). * * @return array */ function aksrt_brand_icon_map(): array { static $map = null; if ($map !== null) { return $map; } // FA5 free has no bilibili/gitee brands — use solid stand-ins. $map = [ 'github' => 'fab fa-github', 'google' => 'fab fa-google', 'x' => 'fab fa-twitter', 'twitter' => 'fab fa-twitter', 'email' => 'fas fa-envelope', 'envelope' => 'fas fa-envelope', 'wechat' => 'fab fa-weixin', 'weixin' => 'fab fa-weixin', 'qq' => 'fab fa-qq', 'weibo' => 'fab fa-weibo', 'telegram' => 'fab fa-telegram-plane', 'discord' => 'fab fa-discord', 'bilibili' => 'fas fa-tv', 'linkedin' => 'fab fa-linkedin-in', 'facebook' => 'fab fa-facebook-f', 'youtube' => 'fab fa-youtube', 'instagram' => 'fab fa-instagram', 'web' => 'fas fa-globe', 'globe' => 'fas fa-globe', 'gitee' => 'fas fa-code-branch', 'baidu' => 'fas fa-paw', 'alipay' => 'fab fa-alipay', ]; return $map; } endif; if (!function_exists('aksrt_normalize_icon_key')) : /** * Normalize short key or full FA class string to a short map key. * * Examples: 'fab fa-github' | 'fabfa-github' | 'fa-github' | 'github' | 'weixin' → 'github' | 'wechat' * * @param string $name Raw icon key or FA class string. * @return string Short key (may be empty). */ function aksrt_normalize_icon_key(string $name): string { $name = trim($name); if ($name === '') { return ''; } // Strip style prefixes: fab/fas/far + optional space or hyphen. $name = preg_replace('/^(fab|fas|far)[\s-]*/i', '', $name); $name = preg_replace('/^fa[\s-]*/i', '', (string) $name); $name = trim((string) $name, "- \t\n\r\0\x0B"); $name = strtolower($name); // Aliases → canonical keys used by the map / contact options. $aliases = [ 'weixin' => 'wechat', 'weixingzh' => 'wechat', 'twitter' => 'x', 'envelope' => 'email', 'globe' => 'web', ]; if (isset($aliases[$name])) { return $aliases[$name]; } return $name; } endif; if (!function_exists('aksrt_brand_icon_class')) : /** * Resolve a short key or FA class string to an allowlisted FA5 class. * * @param string $name Short key or full FA class string. * @return string e.g. 'fab fa-github', or '' if unknown. */ function aksrt_brand_icon_class(string $name): string { $raw = trim($name); if ($raw === '') { return ''; } // Pass through already-valid full FA class strings (footer contact_more). if (preg_match('/^(fa[sbr]|fa)\s+fa-[\w-]+(?:\s+fa-[\w-]+)*$/i', $raw)) { // Prefer mapped short key when strip matches our catalog (normalizes weixin etc.). $key = aksrt_normalize_icon_key($raw); $map = aksrt_brand_icon_map(); if ($key !== '' && isset($map[$key])) { return $map[$key]; } // Allowlisted style + glyph only — collapse whitespace, lower style prefix. $parts = preg_split('/\s+/', strtolower($raw)); $parts = array_values(array_filter((array) $parts)); return implode(' ', $parts); } $key = aksrt_normalize_icon_key($raw); if ($key === '') { return ''; } $map = aksrt_brand_icon_map(); return $map[$key] ?? ''; } endif; if (!function_exists('aksrt_brand_icon')) : /** * Escaped FA markup for a brand/contact icon. * * @param string $name Short key or FA class string. * @param array|string $extra_classes Optional extra classes. * @return string Safe HTML or empty string when unknown. */ function aksrt_brand_icon(string $name, $extra_classes = []): string { $class = aksrt_brand_icon_class($name); if ($class === '') { return ''; } if (is_string($extra_classes) && $extra_classes !== '') { $extra_classes = preg_split('/\s+/', $extra_classes) ?: []; } if (is_array($extra_classes) && $extra_classes !== []) { $extra = array_filter(array_map('sanitize_html_class', $extra_classes)); if ($extra !== []) { $class .= ' ' . implode(' ', $extra); } } return ''; } endif; // ============================================================ // 图标 key → 显示名称 // ============================================================ if (!function_exists('aksrt_icon_key_to_name')) : function aksrt_icon_key_to_name($key) { $key = aksrt_normalize_icon_key((string) $key); $map = array( 'github' => 'GitHub', 'google' => 'Google', 'x' => 'X', 'email' => '邮箱', 'wechat' => '微信', 'qq' => 'QQ', 'weibo' => '微博', 'telegram' => 'Telegram', 'discord' => 'Discord', 'bilibili' => 'Bilibili', 'linkedin' => 'LinkedIn', 'facebook' => 'Facebook', 'youtube' => 'YouTube', 'instagram' => 'Instagram', 'web' => '网站', 'gitee' => 'Gitee', 'baidu' => 'Baidu', 'alipay' => 'Alipay', ); return isset($map[$key]) ? $map[$key] : ucwords(str_replace('-', ' ', $key)); } endif; // ============================================================ // 联系方式图标选项(仅保留选定的 15 个) // ============================================================ if (!function_exists('aksrt_contact_icon_options')) : function aksrt_contact_icon_options($selected = '') { $icons = array( 'github' => 'GitHub', 'google' => 'Google', 'x' => 'X', 'email' => '邮箱', 'wechat' => '微信', 'qq' => 'QQ', 'weibo' => '微博', 'telegram' => 'Telegram', 'discord' => 'Discord', 'bilibili' => 'Bilibili', 'linkedin' => 'LinkedIn', 'facebook' => 'Facebook', 'youtube' => 'YouTube', 'instagram' => 'Instagram', 'web' => '网站', ); $selected = aksrt_normalize_icon_key((string) $selected); $html = ''; foreach ($icons as $key => $label) { $sel = $key === $selected ? ' selected' : ''; $html .= ''; } return $html; } endif; // ============================================================ // Public social links (author hero / profile) // ============================================================ if (!function_exists('aksrt_render_social_links')) : /** * Echo a list of public contact links with FA icons. * * @param array $contacts */ function aksrt_render_social_links(array $contacts): void { $links = []; foreach ($contacts as $contact) { if (!is_array($contact)) { continue; } $url = isset($contact['url']) ? (string) $contact['url'] : ''; $icon = isset($contact['icon']) ? (string) $contact['icon'] : ''; if ($url === '' || $icon === '') { continue; } $icon_html = aksrt_brand_icon($icon); if ($icon_html === '') { $icon_html = ''; } $label = (string) ($contact['name'] ?? $contact['title'] ?? $contact['label'] ?? ''); if ($label === '') { $label = aksrt_icon_key_to_name($icon); } $links[] = [ 'url' => $url, 'label' => $label, 'icon' => $icon_html, ]; } if ($links === []) { return; } echo ''; } endif;