Files
kate522andClaude Opus 5 427968a721 chore(branding): remove leftover upstream theme identifiers
The theme was renamed Zibll/子比 → AKSRT → Jio, but upstream branding
survived the sweeps in CSS classes, the SVG sprite prefix, a persisted
widget field ID, JS events, admin Vue class names, test infrastructure
and docblocks.

Renames:
- zib-widget / zib-widget-wrap / zib-slider → jio-widget-box /
  jio-widget-box-wrap / jio-slider-box (jio-widget is taken by the modern
  widget shell, jio-box-* by the card primitives)
- zib-partners-scroll + zps-* → jio-partners-scroll + jps-*
- zib-combo-info-card + zci-* → jio-combo-info-card + jci-*
- zibsvg- → jiosvg-, including the exported picker helpers and the
  fa-zibsvg- family-prefix guard
- zibpay_type → pay_type; the dual-read fallback in PostQuery collapses
  to a single key
- [zibajax="submit"] dropped (no PHP emitter); zib_ajax.success →
  jio_ajax.success
- aks-* admin Vue classes → jio-*
- zib_palette() → palette()

User-facing vendor traces are gone: the floating "more" button default no
longer ships a zibll.com link or 子比主题 marketing copy, the notice
widget ships no preset promo entries, and the four 官网教程 links are
removed from the post-list admin schema.

Test infrastructure renamed to neutral names (docker-compose.reference.yml,
Caddyfile, article-baseline.json, modern-widgets-contract.test.cjs) with
their DB/volume/env/slug identifiers following.

Kept intentionally, documented in tests/fixtures/README.md: the golden
fixture reference fingerprint (a SHA-256 record of an external directory,
read by validate-widget-golden / generate-widget-golden-fixture /
audit-widget-system), the doesNotMatch guards that prove the old tokens are
gone, and the reference theme's own meta key in the visual fixtures.

No backward-compat or data migration: saved widget configs holding old
icon keys or the old field ID silently lose them, per the project's
rewrite-over-compatibility rule.

Verified: 132/132 node contract tests, php tests/widget-system/run.php
(146 assertions), audit-admin-contracts, audit-psr4-paths and
validate-widget-golden all green; tracked bundles regenerated and in sync.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-02 00:06:54 +08:00

369 lines
16 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
/**
* Comment list item renderer — legacy DOM contract (1:1).
*
* Mirrors legacy / legacy / legacy
* from the legacy comments-list module.
*
* @package Jio
*/
defined('ABSPATH') || exit;
if (!function_exists('jio_get_comment_like_html')) :
/**
* Header like control (legacy: legacy).
*
* @param WP_Comment $comment Comment.
* @param bool $enabled Like enabled.
* @return string
*/
function jio_get_comment_like_html($comment, bool $enabled = true): string {
if (!$enabled) {
return '';
}
$comment_id = $comment instanceof WP_Comment ? (int) $comment->comment_ID : (int) $comment;
if ($comment_id <= 0) {
return '';
}
$like_count = function_exists('jio_get_comment_likes') ? (int) jio_get_comment_likes($comment_id) : 0;
$like_label = function_exists('jio_format_number') ? jio_format_number($like_count) : number_format_i18n($like_count);
$is_liked = function_exists('jio_is_comment_liked') && jio_is_comment_liked($comment_id);
$classes = 'action action-comment-like muted-2-color flex0 ml10' . ($is_liked ? ' actived' : '');
$icon = function_exists('jio_get_comment_icon') ? jio_get_comment_icon('like', 'icon mr3') : '';
return sprintf(
'<a href="javascript:;" data-comment-action="like" data-action="comment_like" class="%1$s" data-pid="%2$d" data-active="%3$s" aria-pressed="%4$s">%5$s<text></text><count>%6$s</count></a>',
esc_attr($classes),
$comment_id,
$is_liked ? '1' : '0',
$is_liked ? 'true' : 'false',
$icon, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- fixed sprite markup.
esc_html((string) $like_label)
);
}
endif;
if (!function_exists('jio_get_comment_avatar_box')) :
/**
* Comment avatar box (legacy: legacy).
*
* @param WP_Comment $comment Comment.
* @param string $class Classes for the avatar wrapper.
* @param bool $link Wrap in a link when a target URL exists.
* @return string
*/
function jio_get_comment_avatar_box(WP_Comment $comment, string $class = 'avatar-img comt-avatar', bool $link = true): string {
$user_id = (int) $comment->user_id;
$size = 45;
$avatar = $user_id > 0
? get_avatar($user_id, $size, '', '', ['class' => 'avatar'])
: get_avatar($comment->comment_author_email, $size, '', '', ['class' => 'avatar']);
$html = '<span class="' . esc_attr($class) . '">' . $avatar . '</span>';
if (!$link) {
return $html;
}
if ($user_id > 0) {
$url = function_exists('jio_get_user_home_url') ? jio_get_user_home_url($user_id) : get_author_posts_url($user_id);
return '<a href="' . esc_url($url) . '">' . $html . '</a>';
}
if (!empty($comment->comment_author_url)) {
return '<a rel="nofollow" href="' . esc_url($comment->comment_author_url) . '">' . $html . '</a>';
}
return $html;
}
endif;
if (!function_exists('jio_get_comments_user_name_html')) :
/**
* Name row (legacy: legacy) — topping + author + badges.
*
* @param WP_Comment $comment Comment.
* @param array<string,mixed> $settings Display settings.
* @return string
*/
function jio_get_comments_user_name_html(WP_Comment $comment, array $settings = []): string {
$user_id = (int) $comment->user_id;
$show_author_tag = !isset($settings['author_tag']) || !empty($settings['author_tag']);
$is_pinned = function_exists('jio_is_comment_pinned') && jio_is_comment_pinned($comment);
$is_post_author = $user_id > 0 && $user_id === (int) get_post_field('post_author', $comment->comment_post_ID);
$topping = '';
if ($is_pinned) {
$topping_icon = function_exists('jio_get_comment_icon') ? jio_get_comment_icon('topping') : '';
$topping = '<badge class="badge-topping jb-blue mr6 flex0" title="' . esc_attr__('置顶评论', 'jio') . '" data-toggle="tooltip">' . $topping_icon . '</badge>';
}
$user_name = '';
if ($user_id > 0) {
$user = get_userdata($user_id);
if ($user instanceof WP_User) {
$url = function_exists('jio_get_user_home_url') ? jio_get_user_home_url($user_id) : get_author_posts_url($user_id);
$user_name = '<a class="text-ellipsis font-bold" href="' . esc_url($url) . '">' . esc_html($user->display_name) . '</a>';
if (function_exists('jio_render_user_identity_chips')) {
$user_name .= jio_render_user_identity_chips($user_id, 'comment');
}
}
} elseif (!empty($comment->comment_author_url)) {
$user_name = '<a class="text-ellipsis font-bold" rel="nofollow" href="' . esc_url($comment->comment_author_url) . '">' . esc_html($comment->comment_author) . '</a>';
}
$user_name = $user_name !== '' ? $user_name : '<b class="mr6 text-ellipsis">' . esc_html($comment->comment_author) . '</b>';
$badge = '';
if ($show_author_tag && $is_post_author) {
$badge .= '<span class="badg c-green badg-sm flex0 ml3">' . esc_html__('作者', 'jio') . '</span>';
}
return '<name class="flex ac flex1">' . $topping . $user_name . $badge . '</name>';
}
endif;
if (!function_exists('jio_get_comment_header_html')) :
/**
* Comment header (legacy: legacy).
*
* @param WP_Comment $comment Comment.
* @param array<string,mixed> $settings Settings.
* @return string
*/
function jio_get_comment_header_html(WP_Comment $comment, array $settings = []): string {
$like_enabled = !isset($settings['like_enabled']) || !empty($settings['like_enabled']);
$avatar = jio_get_comment_avatar_box($comment, 'avatar-img comt-avatar');
$name = jio_get_comments_user_name_html($comment, $settings);
$like = jio_get_comment_like_html($comment, $like_enabled);
$html = '<div class="author-box flex ac">';
$html .= $avatar;
$html .= $name;
$html .= $like;
$html .= '</div>';
return '<div class="comment-header mb10">' . $html . '</div>';
}
endif;
if (!function_exists('jio_get_comment_report_html')) :
/**
* 评论举报入口 — 登录用户可举报他人评论(前台走 report.js 的 data-jio-report 契约)。
*
* 举报位于“回复”右侧三点下拉菜单内(参考主题同位置)。
*
* @param WP_Comment $comment Comment.
* @return string
*/
function jio_get_comment_report_html(WP_Comment $comment): string {
if (!is_user_logged_in() || !class_exists('\Jio\Settings\Settings')) {
return '';
}
$author_id = (int) $comment->user_id;
$reporter_id = get_current_user_id();
if ($author_id > 0 && $author_id === $reporter_id) {
return '';
}
// 已封禁/小黑屋用户不再显示举报入口。
if ($author_id > 0 && function_exists('jio_is_user_ban_restricted') && jio_is_user_ban_restricted($author_id)) {
return '';
}
$settings = \Jio\Settings\Settings::get_user_identity_settings();
if (empty($settings['report']['enabled'])) {
return '';
}
if (function_exists('jio_user_can') && !jio_user_can('user_report', $reporter_id, $author_id)) {
return '';
}
$report_payload = wp_json_encode([
'target_type' => 'comment',
'target_id' => (int) $comment->comment_ID,
'target_name' => get_comment_author($comment),
]);
return '<li><a class="comment-report-link" href="javascript:;" data-jio-report="' . esc_attr((string) $report_payload) . '"><i class="fa fas fa-exclamation-triangle mr10 fa-fw c-red" aria-hidden="true"></i>' . esc_html__('举报', 'jio') . '</a></li>';
}
endif;
if (!function_exists('jio_get_comments_action_dropdown_html')) :
/**
* More-actions menu (legacy: legacy) — pin / edit / approve / delete.
*
* @param WP_Comment $comment Comment.
* @param int $depth Depth.
* @return string
*/
function jio_get_comments_action_dropdown_html(WP_Comment $comment, int $depth = 0): string {
$perms = function_exists('jio_comment_action_permissions')
? jio_comment_action_permissions($comment)
: ['can_edit' => false, 'can_delete' => false, 'can_moderate' => false, 'can_pin' => false];
$is_pinned = function_exists('jio_is_comment_pinned') && jio_is_comment_pinned($comment);
$is_pending = '0' === (string) $comment->comment_approved;
$lists = '';
if (!empty($perms['can_pin']) && (int) $comment->comment_parent === 0) {
$label = $is_pinned ? __('取消置顶', 'jio') : __('设置置顶', 'jio');
// 不带 legacy 的 wp-ajax-submit 类:vendor main.min.js 会全局代理该类并向
// admin-ajax 发空 action 请求(400 "0"),置顶走 data-comment-action REST。
$lists .= '<li><a class="comment-topping" data-comment-action="pin" data-pinned="' . ($is_pinned ? '1' : '0') . '" href="javascript:;"><i class="fa fas fa-thumbtack mr10 fa-fw" aria-hidden="true"></i>' . esc_html($label) . '</a></li>';
}
if (!empty($perms['can_edit'])) {
$lists .= '<li><a class="comment-edit-link" data-commentid="' . (int) $comment->comment_ID . '" data-postid="' . (int) $comment->comment_post_ID . '" href="javascript:;"><i class="fa fas fa-edit mr10 fa-fw" aria-hidden="true"></i>' . esc_html__('编辑', 'jio') . '</a></li>';
}
if (!empty($perms['can_moderate'])) {
$text = $is_pending ? __('批准', 'jio') : __('驳回', 'jio');
$class = $is_pending ? 'approve' : 'unapprove';
$action = $is_pending ? 'approve' : 'hold';
$approve_icon = function_exists('jio_get_comment_icon') ? jio_get_comment_icon('approve', 'mr10 icon fa-fw') : '';
$lists .= '<li><a class="comment-approve-link ' . $class . '" data-comment-action="' . $action . '" data-commentid="' . (int) $comment->comment_ID . '" data-postid="' . (int) $comment->comment_post_ID . '" href="javascript:;">' . $approve_icon . '<text>' . esc_html($text) . '</text></a></li>';
}
if (!empty($perms['can_delete'])) {
$lists .= '<li><a class="comment-trash-link c-red" data-comment-action="delete" data-commentid="' . (int) $comment->comment_ID . '" data-postid="' . (int) $comment->comment_post_ID . '" href="javascript:;"><i class="fa far fa-trash-alt mr10 fa-fw" aria-hidden="true"></i>' . esc_html__('删除', 'jio') . '</a></li>';
}
// 末项(参考主题 comments_action_lists 钩子顺序):管理员 → 禁封用户;
// 否则 → 举报(登录且非本人且举报开启时,既有评论举报契约)。
$lists .= jio_get_comment_ban_or_report_item($comment);
if ($lists === '') {
return '';
}
$menu_icon = function_exists('jio_get_comment_icon') ? jio_get_comment_icon('menu_2') : '';
// 交互由主题自有 comments.js 委托处理(data-jio-comment-drop),
// 不用 vendor 的 data-toggle="dropdown" 遗留委托:该链路在部分环境
// 未注册/被早退,导致三点菜单点不开。open 类驱动的 CSS 契约不变。
$icon_a = '<a href="javascript:;" class="muted-color padding-6" data-jio-comment-drop aria-haspopup="true" aria-expanded="false" aria-label="' . esc_attr__('更多操作', 'jio') . '">' . $menu_icon . '</a>';
return '<span class="dropdown drop-fixed-sm padding-6">' . $icon_a . '<ul class="dropdown-menu">' . $lists . '</ul></span>';
}
endif;
if (!function_exists('jio_get_comment_footer_html')) :
/**
* comt-meta row (legacy: legacy).
*
* @param WP_Comment $comment Comment.
* @param array $args wp_list_comments args.
* @param int $depth Depth.
* @param array<string,mixed> $settings Settings.
* @return string
*/
function jio_get_comment_footer_html(WP_Comment $comment, array $args, int $depth, array $settings = []): string {
$is_pending = '0' === (string) $comment->comment_approved;
$is_mobile = wp_is_mobile();
$badg_approve = '';
if ($is_pending) {
$badg_approve = '<span class="badg c-red badg-sm">' . esc_html__('待审核', 'jio') . '</span>';
}
$badg_approve = '<span class="badge-approve">' . $badg_approve . '</span>';
$absolute = date_i18n(__('Y年m月d日 H:i:s', 'jio'), strtotime((string) $comment->comment_date));
$ago = function_exists('jio_time_ago')
? jio_time_ago((string) $comment->comment_date)
: human_time_diff(strtotime((string) $comment->comment_date), current_time('timestamp')) . __('前', 'jio');
$time_html = '<span class="comt-author"' . ($is_mobile ? ' data-toggle="tooltip"' : '') . ' title="' . esc_attr($absolute) . '">' . esc_html($ago) . '</span>';
$city_html = function_exists('jio_get_comment_city_badge_html')
? jio_get_comment_city_badge_html($comment)
: '';
$parent_html = '';
if ((int) $comment->comment_parent > 0) {
$parent_author = get_comment_author((int) $comment->comment_parent);
$parent_html = '<span>@<a rel="nofollow" class="url" href="javascript:;" data-scroll-to="#comment-' . (int) $comment->comment_parent . '">' . esc_html($parent_author) . '</a></span>';
}
$reply_html = '';
if (!$is_pending && $depth > 0) {
$max_depth = (int) ($args['max_depth'] ?? get_option('thread_comments_depth', 5));
$link = get_comment_reply_link(
[
'add_below' => 'div-comment',
'reply_text' => __('回复', 'jio'),
'login_text' => __('回复', 'jio'),
'depth' => $depth,
'max_depth' => $max_depth,
],
$comment
);
if ($link) {
// 去掉 WP 内联 onclick(addComment.moveForm),回复由 comment-move-form.js 事件委托处理。
$link = preg_replace('/ onclick="[^"]*"/i', '', $link);
// legacy 契约:aria-label 换成 tooltip 触发属性。
$link = preg_replace('# aria-label=#', $is_mobile ? ' title=' : ' data-toggle="tooltip" title=', $link);
if (strpos($link, 'data-commentid') === false) {
$link = str_replace(
'comment-reply-link',
'comment-reply-link" data-commentid="' . (int) $comment->comment_ID . '" data-postid="' . (int) $comment->comment_post_ID,
$link
);
}
$reply_html = '<span class="reply-link">' . $link . '</span>';
}
}
$actions = jio_get_comments_action_dropdown_html($comment, $depth);
$info = $time_html . $city_html . $parent_html . $badg_approve . $reply_html;
return '<div class="comt-meta muted-2-color">' . $info . $actions . '</div>';
}
endif;
if (!function_exists('jio_get_comments_list_html')) :
/**
* Single comment item HTML (legacy: legacy).
*
* @param WP_Comment $comment Comment.
* @param array $args Args.
* @param int $depth Depth.
* @param array $settings Settings.
* @return string
*/
function jio_get_comments_list_html(WP_Comment $comment, array $args = [], int $depth = 0, array $settings = []): string {
$comment_id = (int) $comment->comment_ID;
$con = function_exists('jio_render_comment_content')
? jio_render_comment_content((string) get_comment_text($comment))
: wp_kses_post((string) get_comment_text($comment));
$header = jio_get_comment_header_html($comment, $settings);
$footer = jio_get_comment_footer_html($comment, $args, $depth, $settings);
$html = '<li ' . comment_class('', $comment, null, false) . ' id="comment-' . esc_attr((string) $comment_id) . '">';
$html .= '<ul class="list-inline">';
$html .= '<li class="comt-main" id="div-comment-' . esc_attr((string) $comment_id) . '">';
$html .= $header;
$html .= '<div class="comment-footer">';
$html .= '<div class="mb10 comment-content" id="comment-content-' . esc_attr((string) $comment_id) . '">' . $con . '</div>';
$html .= $footer;
$html .= '</div>';
$html .= '</li>';
$html .= '</ul>';
return $html;
}
endif;
if (!function_exists('jio_comment_callback')) :
/**
* Canonical wp_list_comments callback (legacy: legacy).
*
* The closing </li> is emitted by the walker after children.
*
* @param WP_Comment $comment Comment.
* @param array $args Args.
* @param int $depth Depth.
*/
function jio_comment_callback($comment, $args, $depth) {
$GLOBALS['comment'] = $comment;
$settings = get_query_var('jio_comment_settings', []);
$settings = is_array($settings) ? $settings : [];
if (empty($settings) && class_exists('\Jio\Settings\Settings')) {
$settings = \Jio\Settings\Settings::get_comment_display_settings();
}
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- composed helpers escape.
echo jio_get_comments_list_html($comment, is_array($args) ? $args : [], (int) $depth, $settings);
}
endif;