fix(badges): complete full-chain badge circuit and preset icons
Close the full circuit break in the badge/medal system and replace empty default icons with preset SVG assets so badges render out of the box: - Add aksrt_get_worn_medal_icon() helper that renders the worn medal image inline (with settings fallback when the Badges class is unavailable). - Profile header (UC) now shows the worn medal icon beside the name, matching zibll's name row order (display_name → VIP → Medal → Level → Verify). - Add .medal-icon / .aksrt-identity-medal vertical-align rules in UC shell.css. - Extract SchemaUsers::default_medal_args() and preset 6 badges (rookie, checkin-30, writer, popular, annual-star, vip-member) with real icon URLs from assets/img/medal/ (medal-1/2/5/9/12/15.svg). - Vue badge.js: add MEDAL_BASE helper + preset icons matching PHP defaults.
This commit is contained in:
@@ -229,6 +229,92 @@ if (!function_exists('aksrt_get_user_name')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_get_worn_medal_icon')) {
|
||||
/**
|
||||
* Render the worn medal icon HTML for a user (standalone, zibll 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 aksrt_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('AKSRT\\User\\Badges') && is_callable(['AKSRT\\User\\Badges', 'enabled'])) {
|
||||
if (\AKSRT\User\Badges::enabled()) {
|
||||
$enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$enabled && class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_user_identity_settings')) {
|
||||
$ident = \AKSRT\Settings\Settings::get_user_identity_settings();
|
||||
if (!empty($ident['badge']['enabled'])) {
|
||||
$enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$enabled) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Class-backed path (canonical).
|
||||
if (class_exists('AKSRT\\User\\Badges')
|
||||
&& is_callable(['AKSRT\\User\\Badges', 'get_wear'])
|
||||
&& is_callable(['AKSRT\\User\\Badges', 'get_dictionary_map'])) {
|
||||
$slug = sanitize_key((string) \AKSRT\User\Badges::get_wear($user_id));
|
||||
$map = \AKSRT\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('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_user_identity_settings')) {
|
||||
$ident = \AKSRT\Settings\Settings::get_user_identity_settings();
|
||||
$slug = sanitize_key((string) get_user_meta($user_id, 'aksrt_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 class="medal-icon img-icon ml3 aksrt-identity-medal is-wear' . $extra . '" src="' . $icon . '" alt="' . esc_attr($label) . '" title="' . esc_attr($label) . '" loading="lazy" decoding="async" />';
|
||||
}
|
||||
|
||||
// Text fallback (rare): small pill labelled with badge text.
|
||||
$extra = $class !== '' ? ' ' . esc_attr($class) : '';
|
||||
return '<span class="badg badg-sm ml3 aksrt-identity-medal is-wear' . $extra . '" title="' . esc_attr($label) . '"><i class="fa fa-award" aria-hidden="true"></i> ' . esc_html($label) . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_is_blog_comment_hot')) {
|
||||
/**
|
||||
* "神评" for ordinary post comments when likes cross threshold.
|
||||
|
||||
Reference in New Issue
Block a user