Files
kate522andClaude Fable 5 d40906b4a3 feat(single): align author bar follow and reward actions with the site flows
- guests get the sign-in trigger instead of a redirect to the login page,
  for both follow and wallet reward controls
- follow requests swap the label for an inline loader and block a second
  submit; the followed state uses the .actived hook
- follower counts sync through data-follow-count on the user homepage
  (the previous selector matched nothing) and only for the viewed profile
- reward button uses the secondary action colour; the reward template is
  only rendered for signed-in visitors
- drop the unused author-hero aria-disabled rule and stale wording in the
  touched comments

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-11-04 13:34:34 +08:00

592 lines
24 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Shared identity chrome: VIP / verify / level / badges for author bar & comments.
*
* @package Jio
*/
defined('ABSPATH') || exit;
if (!function_exists('jio_get_user_identity_signals')) {
/**
* @return list<array{type?:string,label:string,icon:string,tone:string,title?:string,icon_url?:string,slug?:string,wear?:bool}>
*/
function jio_get_user_identity_signals(int $user_id): array {
if ($user_id <= 0) {
return [];
}
if (class_exists('\Jio\User\Home')) {
$signals = \Jio\User\Home::get_instance()->get_profile_signals($user_id);
return is_array($signals) ? array_values($signals) : [];
}
return [];
}
}
if (!function_exists('jio_current_user_is_verified')) {
/**
* Whether the current user carries a verification (认证) signal.
*
* @return bool
*/
function jio_current_user_is_verified(): bool {
$user_id = get_current_user_id();
if ($user_id <= 0 || !function_exists('jio_get_user_identity_signals')) {
return false;
}
foreach (jio_get_user_identity_signals($user_id) as $signal) {
if ((string) ($signal['type'] ?? '') === 'verify') {
return true;
}
}
return false;
}
}
if (!function_exists('jio_render_user_identity_chips')) {
/**
* Render compact identity chips (verify / level / badges).
*
* Badge signals with icon_url render as legacy-like medal images.
*
* @param int $user_id
* @param string $context author|comment|card
* @param array $args {
* Optional. Additional options.
*
* @type bool $include_vip Whether to prepend VIP badge. Default true.
* @type bool $skip_level Whether to omit the level chip (rendered inline elsewhere). Default false.
* @type bool $skip_badges Whether to omit badge signals from this row. Default false.
* }
*/
function jio_render_user_identity_chips(int $user_id, string $context = 'author', array $args = []): string {
if ($user_id <= 0) {
return '';
}
$args = wp_parse_args($args, [
'include_vip' => true,
'skip_level' => false,
]);
$html = '';
if (!empty($args['include_vip']) && function_exists('jio_get_vip_icon')) {
$vip = jio_get_vip_icon($user_id);
if (is_string($vip) && $vip !== '') {
$html .= $vip;
}
}
$signals = jio_get_user_identity_signals($user_id);
// Keep the public identity order stable: certification, worn badge, level.
usort($signals, static function (array $left, array $right): int {
$priority = ['verify' => 0, 'badge' => 1, 'level' => 2];
return ($priority[(string) ($left['type'] ?? '')] ?? 3) <=> ($priority[(string) ($right['type'] ?? '')] ?? 3);
});
if ($context === 'comment') {
$signals = array_values(array_filter($signals, static function (array $signal): bool {
return (string) ($signal['type'] ?? '') !== 'badge' || !empty($signal['wear']);
}));
}
// Comments stay compact; author/card can show more.
$limit = $context === 'comment' ? 3 : 6;
$n = 0;
foreach ($signals as $signal) {
if ($n >= $limit) {
break;
}
$label = trim((string) ($signal['label'] ?? ''));
if ($label === '') {
continue;
}
$type = sanitize_html_class((string) ($signal['type'] ?? ''));
// Level is rendered inline next to the name by the caller; skip it here.
if (!empty($args['skip_level']) && $type === 'level') {
continue;
}
if (!empty($args['skip_badges']) && $type === 'badge') {
continue;
}
$tone = sanitize_html_class((string) ($signal['tone'] ?? 'info'));
$icon = sanitize_html_class((string) ($signal['icon'] ?? 'check'));
$icon_url = esc_url((string) ($signal['icon_url'] ?? ''));
$title = (string) ($signal['title'] ?? $label);
$is_wear = !empty($signal['wear']);
// Image medal when dictionary provides icon_url.
if ($icon_url !== '') {
$classes = 'medal-icon img-icon ml3 jio-identity-medal jio-identity-medal--' . $context;
if ($is_wear) {
$classes .= ' is-wear';
}
if ($type !== '') {
$classes .= ' jio-identity-medal--' . $type;
}
$html .= '<img' . jio_get_lazy_attr('lazy_other', $icon_url, $classes) . ' alt="' . esc_attr($label) . '" title="' . esc_attr($title) . '" decoding="async">';
$n++;
continue;
}
// Font Awesome: map short names to fa-* if needed.
if ($icon !== '' && !str_contains($icon, 'fa-')) {
$icon = 'fa-' . $icon;
}
$html .= '<span class="badg badg-sm ml3 jio-identity-chip jio-identity-chip--' . esc_attr($tone) . ' jio-identity-chip--' . esc_attr($context) . ($is_wear ? ' is-wear' : '') . '" title="' . esc_attr($title) . '">';
if ($icon !== '') {
$html .= '<i class="fa ' . esc_attr($icon) . '" aria-hidden="true"></i> ';
}
$html .= esc_html($label) . '</span>';
$n++;
}
return $html;
}
}
if (!function_exists('jio_get_user_follow')) {
/**
* Render the canonical user follow control.
*
* Guests get the login trigger instead of a follow request; signed-in
* visitors get the server-rendered state that follow.js keeps in sync.
*/
function jio_get_user_follow(string $class, int $follow_id, ?string $text = null, ?string $ok_text = null, ?string $guest_text = null): string {
$current_user_id = get_current_user_id();
if ($follow_id <= 0 || $current_user_id === $follow_id) {
return '';
}
if (class_exists('\Jio\Settings\Settings') && \Jio\Settings\Settings::close_sign()) {
return '';
}
$text = $text ?? __('关注', 'jio');
$ok_text = $ok_text ?? __('已关注', 'jio');
$guest_text = $guest_text ?? $text;
$class = trim($class);
if (!is_user_logged_in()) {
// 游客点击由 auth.js 的全局委托拉起登录弹窗,不直接跳转登录页。
return '<a href="javascript:;" class="' . esc_attr($class . ' signin-loader') . '"><i class="fa far fa-heart em09" aria-hidden="true"></i> <span>' . esc_html($guest_text) . '</span></a>';
}
$is_following = class_exists('\Jio\User\Follow')
&& \Jio\User\Follow::get_instance()->is_following($current_user_id, $follow_id);
$state_class = $is_following ? ' actived' : '';
$title = $is_following ? __('点击取消关注', 'jio') : __('关注该用户', 'jio');
$label = $is_following ? $ok_text : $text;
$icon_class = $is_following ? 'fa fas fa-heart em09' : 'fa far fa-heart em09';
// 文案随按钮下发,follow.js 切换状态时沿用同一套标签。
$labels = ' data-jio-follow-text="' . esc_attr($text) . '" data-jio-follow-ok="' . esc_attr($ok_text) . '"';
return '<a href="javascript:;" class="' . esc_attr($class . $state_class) . '" data-jio-follow="' . $follow_id . '"' . $labels . ' title="' . esc_attr($title) . '"><i class="' . esc_attr($icon_class) . '" aria-hidden="true"></i> <span data-jio-follow-label>' . esc_html($label) . '</span></a>';
}
}
if (!function_exists('jio_get_user_name')) {
/**
* legacy parity: name link + auth + wear medal + level + optional follow.
*
* @param array|int $args User id or args array.
*/
function jio_get_user_name($args = []): string {
$defaults = [
'id' => 0,
'class' => 'flex ac flex1',
'name_class' => '',
'vip' => true,
'medal' => true,
'auth' => true,
'level' => true,
'follow' => false,
'highlight_query' => '',
];
if (is_numeric($args)) {
$defaults['id'] = (int) $args;
$args = $defaults;
} else {
$args = wp_parse_args(is_array($args) ? $args : [], $defaults);
}
$user_id = (int) $args['id'];
if ($user_id <= 0) {
$user_id = get_current_user_id();
}
if ($user_id <= 0) {
return '';
}
$user = get_userdata($user_id);
if (!$user) {
return '';
}
$home = function_exists('jio_get_user_home_url')
? jio_get_user_home_url($user_id)
: get_author_posts_url($user_id);
$display = $user->display_name;
$vip_html = '';
if (!empty($args['vip'])) {
// 禁封徽章占据 VIP 图标位(禁封态覆盖会员图标)。
$vip_html = function_exists('jio_get_user_ban_name_badge')
? jio_get_user_ban_name_badge($user_id)
: '';
if ($vip_html === '' && function_exists('jio_get_vip_icon')) {
$vip_html = (string) jio_get_vip_icon($user_id);
}
}
$name_class = trim('display-name text-ellipsis ' . (string) $args['name_class']);
$name_markup = !empty($args['highlight_query']) && function_exists('jio_renderer_highlight_text')
? jio_renderer_highlight_text((string) $display, (string) $args['highlight_query'])
: esc_html($display);
$name_link = '<a class="' . esc_attr($name_class) . '" href="' . esc_url($home) . '">' . $name_markup . '</a>';
$auth_html = '';
$medal_html = '';
$level_html = '';
$signals = jio_get_user_identity_signals($user_id);
foreach ($signals as $signal) {
$type = (string) ($signal['type'] ?? '');
$label = trim((string) ($signal['label'] ?? ''));
if ($label === '') {
continue;
}
$icon_url = esc_url((string) ($signal['icon_url'] ?? ''));
$title = (string) ($signal['title'] ?? $label);
if ($type === 'verify' && !empty($args['auth']) && $auth_html === '') {
$auth_html = $icon_url !== ''
? '<img' . jio_get_lazy_attr('lazy_other', $icon_url, 'jio-identity-certification-icon img-icon ml3') . ' alt="' . esc_attr($label) . '" title="' . esc_attr($title) . '" decoding="async">'
: '<span class="badg badg-sm ml3 jio-identity-chip jio-identity-chip--success" title="' . esc_attr($title) . '"><i class="fa fas fa-check-circle" aria-hidden="true"></i> ' . esc_html($label) . '</span>';
} elseif ($type === 'level' && !empty($args['level']) && $level_html === '') {
if ($icon_url !== '') {
$level_html = '<img' . jio_get_lazy_attr('lazy_other', $icon_url, 'jio-user-level-icon img-icon ml3') . ' alt="' . esc_attr($label) . '" title="' . esc_attr($title) . '" decoding="async">';
} else {
// Text fallback mirrors legacy LV badge: small pill, never oversized.
$level_html = '<span class="badg badg-sm ml3 jio-user-level-badge" title="' . esc_attr($title) . '">' . esc_html($label) . '</span>';
}
} elseif ($type === 'badge' && !empty($args['medal']) && $medal_html === '' && !empty($signal['wear'])) {
if ($icon_url !== '') {
$medal_html = '<img' . jio_get_lazy_attr('lazy_other', $icon_url, 'medal-icon img-icon ml3 jio-identity-medal is-wear') . ' alt="' . esc_attr($label) . '" title="' . esc_attr($title) . '" decoding="async">';
} else {
$medal_html = '<span class="badg badg-sm ml3 jio-identity-chip is-wear" title="' . esc_attr($title) . '"><i class="fa fas fa-trophy" aria-hidden="true"></i> ' . esc_html($label) . '</span>';
}
}
}
// If medal requested but no wear flag, use first badge with icon.
if (!empty($args['medal']) && $medal_html === '') {
foreach ($signals as $signal) {
if ((string) ($signal['type'] ?? '') !== 'badge') {
continue;
}
$label = trim((string) ($signal['label'] ?? ''));
$icon_url = esc_url((string) ($signal['icon_url'] ?? ''));
$title = (string) ($signal['title'] ?? $label);
if ($label === '') {
continue;
}
if ($icon_url !== '') {
$medal_html = '<img' . jio_get_lazy_attr('lazy_other', $icon_url, 'medal-icon img-icon ml3 jio-identity-medal') . ' alt="' . esc_attr($label) . '" title="' . esc_attr($title) . '" decoding="async">';
} else {
$medal_html = '<span class="badg badg-sm ml3 jio-identity-chip" title="' . esc_attr($title) . '"><i class="fa fas fa-trophy" aria-hidden="true"></i> ' . esc_html($label) . '</span>';
}
break;
}
}
$follow_html = !empty($args['follow'])
? jio_get_user_follow('focus-color ml10 follow flex0', $user_id)
: '';
// Order: name → auth → wear medal → level → follow (legacy).
$html = '<name class="' . esc_attr((string) $args['class']) . '">' . $name_link . $vip_html . $auth_html . $medal_html . $level_html . $follow_html . '</name>';
/**
* Filter rendered user name chrome.
*
* @param string $html
* @param int $user_id
* @param array $args
*/
return (string) apply_filters('jio_user_show_name', $html, $user_id, $args);
}
}
if (!function_exists('jio_get_user_posts_meta_sum')) {
/**
* 求和用户已发布文章的某个 meta(legacy get_user_posts_meta_sum parity)。
*
* @param int $user_id 用户 ID。
* @param string $meta_key 文章 meta 键。
*/
function jio_get_user_posts_meta_sum(int $user_id, string $meta_key): int {
global $wpdb;
if ($user_id <= 0 || $meta_key === '') {
return 0;
}
$cache_group = 'jio_user_posts_' . $meta_key . '_sum';
$cached = wp_cache_get($user_id, $cache_group);
if (false !== $cached) {
return (int) $cached;
}
$sum = $wpdb->get_var($wpdb->prepare(
"SELECT SUM(_m.meta_value + 0) FROM {$wpdb->posts} _p INNER JOIN {$wpdb->postmeta} _m ON _p.ID = _m.post_id"
. " WHERE _p.post_author = %d AND _m.meta_key = %s AND _p.post_status = 'publish'",
$user_id,
$meta_key
));
$sum = $sum ? (int) $sum : 0;
wp_cache_set($user_id, $sum, $cache_group, 43200);
return $sum;
}
}
if (!function_exists('jio_get_user_badges')) {
/**
* legacy parity: 作者资料卡统计徽章行(文章 / 评论 / 粉丝|点赞 / 人气值)。
*
* @param int $user_id 用户 ID。
*/
function jio_get_user_badges(int $user_id): string {
if ($user_id <= 0) {
return '';
}
$home = jio_get_user_home_url($user_id);
$post_n = jio_cut_count(count_user_posts($user_id, 'post', true));
$com_n = jio_cut_count((int) get_comments([
'user_id' => $user_id,
'status' => 'approve',
'count' => true,
'post_type' => ['post'],
]));
$followed_n = class_exists('\Jio\User\Follow')
? jio_cut_count((int) \Jio\User\Follow::get_instance()->get_follower_count($user_id))
: 0;
$like_n = jio_cut_count(jio_get_user_posts_meta_sum($user_id, '_jio_like_count'));
$view_n = jio_cut_count(jio_get_user_posts_meta_sum($user_id, 'jio_post_views'));
$html = '';
$html .= '<a class="but c-blue tag-posts" data-toggle="tooltip" title="' . esc_attr(sprintf(__('共%s篇文章', 'jio'), $post_n)) . '" href="' . esc_url($home) . '"><i class="fa fas fa-file-alt" aria-hidden="true"></i>' . $post_n . '</a>';
$html .= '<a class="but c-green tag-comment" data-toggle="tooltip" title="' . esc_attr(sprintf(__('共%s条评论', 'jio'), $com_n)) . '" href="' . esc_url($home) . '"><i class="fa fas fa-comment-dots" aria-hidden="true"></i>' . $com_n . '</a>';
if ($followed_n) {
$html .= '<a class="but c-yellow tag-follow" data-toggle="tooltip" title="' . esc_attr(sprintf(__('共%s个粉丝', 'jio'), $followed_n)) . '" href="' . esc_url($home) . '"><i class="fa fas fa-heart em09" aria-hidden="true"></i>' . $followed_n . '</a>';
} elseif ($like_n) {
$html .= '<span class="badg c-yellow tag-like" data-toggle="tooltip" title="' . esc_attr(sprintf(__('获得%s个点赞', 'jio'), $like_n)) . '"><i class="fa fas fa-thumbs-up" aria-hidden="true"></i>' . $like_n . '</span>';
}
$html .= '<span class="badg c-red tag-view" data-toggle="tooltip" title="' . esc_attr(sprintf(__('人气值 %s', 'jio'), $view_n)) . '"><i class="fa fas fa-fire" aria-hidden="true"></i>' . $view_n . '</span>';
/**
* Filter the author-card count badges row.
*
* @param string $html Badges HTML.
* @param int $user_id User ID.
*/
return (string) apply_filters('jio_user_count_badges', $html, $user_id);
}
}
if (!function_exists('jio_render_user_medal_entry')) {
/**
* Render the compact legacy-style badge overview entry.
*
* The configured limit controls preview icons only; the count remains
* the complete owned badge count returned by the privacy-aware DTO.
*
* @param int $user_id
* @param string $context user-center|user-home
* @param bool $can_wear Whether the viewer may initially wear a badge.
*/
function jio_render_user_medal_entry(int $user_id, string $context = 'user-home', bool $can_wear = false): string {
if ($user_id <= 0 || !class_exists('Jio\\User\\Badges') || !class_exists('Jio\\Settings\\Settings')) {
return '';
}
$settings = \Jio\Settings\Settings::get_user_identity_settings();
$medal = is_array($settings['medal'] ?? null) ? $settings['medal'] : [];
if (empty($medal['enabled']) || ($context === 'user-home' && empty($medal['public_display']))) {
return '';
}
$data = \Jio\User\Badges::list_for_user($user_id);
if (empty($data['enabled']) || ($context === 'user-home' && empty($data['public_display']))) {
return '';
}
$count = max(0, (int) ($data['count'] ?? 0));
$is_manager = \Jio\User\Badges::can_manually_set(get_current_user_id());
if ($context === 'user-home' && $count === 0 && !$is_manager) {
return '';
}
$action = $is_manager && $context === 'user-home' && $count === 0 ? 'jio_user_medal_manually_add_modal' : 'jio_user_medal_info_modal';
$modal_class = $action === 'jio_user_medal_manually_add_modal'
? 'jio-badge-modal jio-badge-modal--grant'
: 'jio-badge-modal jio-badge-modal--overview';
$query = ['action' => $action, 'id' => $user_id];
$url = add_query_arg($query, admin_url('admin-ajax.php'));
$limit = max(1, min(8, (int) ($medal['limit'] ?? 3)));
$icons = [];
foreach ((array) ($data['categories'] ?? []) as $category) {
foreach ((array) ($category['items'] ?? []) as $item) {
if (empty($item['owned'])) {
continue;
}
$icon_url = esc_url((string) ($item['icon_url'] ?? ''));
if ($icon_url === '') {
continue;
}
$label = sanitize_text_field((string) ($item['label'] ?? __('徽章', 'jio')));
$icons[] = '<img' . jio_get_lazy_attr('lazy_other', $icon_url, 'img-icon medal-icon jio-medal-entry__icon') . ' alt="' . esc_attr($label) . '" title="' . esc_attr($label) . '" decoding="async">';
if (count($icons) >= $limit) {
break 2;
}
}
}
$label = $count > 0 ? sprintf(_n('%d枚徽章', '%d枚徽章', $count, 'jio'), $count) : ($is_manager && $context === 'user-home' ? __('授予徽章', 'jio') : __('获取徽章', 'jio'));
$icons_html = implode('', $icons);
if ($icons_html === '') {
$icons_html = '<span class="jio-medal-entry__fallback" aria-hidden="true"><i class="fa fas fa-trophy"></i></span>';
}
$classes = 'jio-medal-entry jio-medal-entry--' . sanitize_html_class($context);
return '<a class="' . esc_attr($classes . ' jio-modal-link') . '" data-jio-modal="remote" data-jio-modal-url="' . esc_url($url) . '" data-jio-modal-class="' . esc_attr($modal_class) . '" data-jio-modal-loading="spinner" data-jio-modal-swipe-close="true" data-jio-modal-height="240" data-jio-modal-mobile-bottom="true" data-jio-modal-cache="false" href="' . esc_url($url) . '" aria-label="' . esc_attr($label) . '"><span class="jio-medal-entry__icons">' . $icons_html . '</span><span class="jio-medal-entry__count">' . esc_html($label) . '</span><i class="fa fas fa-angle-right jio-medal-entry__arrow" aria-hidden="true"></i></a>';
}
}
if (!function_exists('jio_user_has_visible_badges')) {
/**
* Whether a user owns at least one badge that exists in the current catalog.
*
* Used by user-center surfaces to decide whether to show the "我的徽章"
* button. Prevents rendering a button that opens an empty modal when the
* badge dictionary has no entries or none of the user's badges match it.
*
* @param int $user_id Target user (0 = current user).
* @return bool
*/
function jio_user_has_visible_badges(int $user_id = 0): bool {
if ($user_id <= 0) {
$user_id = get_current_user_id();
}
if ($user_id <= 0 || !class_exists('Jio\\User\\Badges')) {
return false;
}
$map = \Jio\User\Badges::get_dictionary_map();
if (empty($map)) {
return false;
}
$owned = \Jio\User\Badges::get_owned($user_id);
foreach ((array) $owned as $slug) {
if (is_string($slug) && $slug !== '' && isset($map[$slug])) {
return true;
}
}
return false;
}
}
if (!function_exists('jio_get_worn_medal_icon')) {
/**
* Render the worn medal icon HTML for a user (standalone, legacy parity).
*
* Returns an <img> tag when a badge is worn and has an icon_url in the
* dictionary. Handles the edge case where the worn slug lives in user meta
* but the badge class is unavailable (defensive: rebuilds from settings).
*
* @param int $user_id Target user (0 = current user).
* @param string $class Extra CSS classes ( space-separated ).
* @return string HTML safe for echo; '' when nothing to render.
*/
function jio_get_worn_medal_icon(int $user_id = 0, string $class = ''): string {
if ($user_id <= 0) {
$user_id = get_current_user_id();
}
if ($user_id <= 0) {
return '';
}
$enabled = false;
$slug = '';
$icon = '';
$label = '';
if (class_exists('Jio\\User\\Badges') && is_callable(['Jio\\User\\Badges', 'enabled'])) {
if (\Jio\User\Badges::enabled()) {
$enabled = true;
}
}
if (!$enabled && class_exists('\Jio\Settings\Settings') && method_exists('\Jio\Settings\Settings', 'get_user_identity_settings')) {
$ident = \Jio\Settings\Settings::get_user_identity_settings();
if (!empty($ident['badge']['enabled'])) {
$enabled = true;
}
}
if (!$enabled) {
return '';
}
// Class-backed path (canonical).
if (class_exists('Jio\\User\\Badges')
&& is_callable(['Jio\\User\\Badges', 'get_wear'])
&& is_callable(['Jio\\User\\Badges', 'get_dictionary_map'])) {
$slug = sanitize_key((string) \Jio\User\Badges::get_wear($user_id));
$map = \Jio\User\Badges::get_dictionary_map();
$entry = is_array($map[$slug] ?? null) ? $map[$slug] : [];
if (is_array($entry) && !empty($entry)) {
$icon = isset($entry['icon_url']) ? esc_url((string) $entry['icon_url']) : '';
$label = isset($entry['label']) ? sanitize_text_field((string) $entry['label']) : '';
}
}
// Fallback when class is missing or returned nothing: rebuild from settings.
if ($slug === '' && $icon === '' && class_exists('\Jio\Settings\Settings') && method_exists('\Jio\Settings\Settings', 'get_user_identity_settings')) {
$ident = \Jio\Settings\Settings::get_user_identity_settings();
$slug = sanitize_key((string) get_user_meta($user_id, 'jio_wear_badge', true));
if ($slug !== '') {
$dictionary = is_array($ident['badge']['dictionary'] ?? null) ? $ident['badge']['dictionary'] : [];
foreach ((array) $dictionary as $item) {
if (is_array($item) && !empty($item['slug']) && (string) $item['slug'] === $slug) {
$icon = isset($item['icon_url']) ? esc_url((string) $item['icon_url']) : '';
$label = isset($item['label']) ? sanitize_text_field((string) $item['label']) : '';
break;
}
}
}
}
if ($slug === '' || ($icon === '' && $label === '')) {
return '';
}
if ($icon !== '') {
$extra = $class !== '' ? ' ' . esc_attr($class) : '';
return '<img' . jio_get_lazy_attr('lazy_other', $icon, 'medal-icon img-icon ml3 jio-identity-medal is-wear' . $extra) . ' alt="' . esc_attr($label) . '" title="' . esc_attr($label) . '" decoding="async">';
}
// Text fallback (rare): small pill labelled with badge text.
$extra = $class !== '' ? ' ' . esc_attr($class) : '';
return '<span class="badg badg-sm ml3 jio-identity-medal is-wear' . $extra . '" title="' . esc_attr($label) . '"><i class="fa fas fa-trophy" aria-hidden="true"></i> ' . esc_html($label) . '</span>';
}
}
if (!function_exists('jio_is_blog_comment_hot')) {
/**
* "神评" for ordinary post comments when likes cross the fixed 10-like
* threshold (not configurable).
*/
function jio_is_blog_comment_hot($comment): bool {
$comment_id = $comment instanceof WP_Comment ? (int) $comment->comment_ID : (int) $comment;
if ($comment_id <= 0) {
return false;
}
if ('1' === (string) get_comment_meta($comment_id, '_jio_comment_hot', true)) {
return true;
}
$threshold = 10;
$likes = function_exists('jio_get_comment_likes') ? jio_get_comment_likes($comment_id) : (int) get_comment_meta($comment_id, 'jio_comment_likes', true);
if ($likes < $threshold) {
return false;
}
update_comment_meta($comment_id, '_jio_comment_hot', '1');
return true;
}
}