$args Comment query args. * @return array */ function aksrt_comments_template_query_args(array $args): array { $order = isset($_GET['aksrt_comment_order']) ? sanitize_key((string) wp_unslash($_GET['aksrt_comment_order'])) : ''; if ($order === '') { $settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_comment_display_settings() : []; $order = (($settings['order'] ?? 'desc') === 'asc') ? 'oldest' : 'newest'; } if (!in_array($order, ['newest', 'oldest', 'hottest'], true)) { $order = 'newest'; } if ($order === 'oldest') { $args['order'] = 'ASC'; $args['orderby'] = 'comment_date_gmt'; } else { // newest + hottest: base DESC; hottest reorders via comments_clauses. $args['order'] = 'DESC'; $args['orderby'] = 'comment_date_gmt'; } if (isset($_GET['aksrt_author_only']) && (int) wp_unslash($_GET['aksrt_author_only']) === 1) { $post_id = (int) get_queried_object_id(); if ($post_id <= 0 && !empty($args['post_id'])) { $post_id = (int) $args['post_id']; } $author_id = $post_id > 0 ? (int) get_post_field('post_author', $post_id) : 0; if ($author_id > 0) { $args['user_id'] = $author_id; } } return $args; } endif; add_filter('comments_template_query_args', static function ($args) { if (!is_array($args)) { $args = []; } return function_exists('aksrt_comments_template_query_args') ? aksrt_comments_template_query_args($args) : $args; }); if (!function_exists('aksrt_comment_box_visible')) : /** * Whether the comment module may render for the current visitor. * * Mirrors the reference theme's comment_box_hide conditions. */ function aksrt_comment_box_visible(): bool { $settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_comment_display_settings() : []; $hide = sanitize_key((string) ($settings['box_hide'] ?? '')); switch ($hide) { case 'signin': return is_user_logged_in(); case 'vip': return function_exists('aksrt_is_vip') && aksrt_is_vip(); case 'vip_2': return function_exists('aksrt_is_vip2') && aksrt_is_vip2(); case 'auth': return function_exists('aksrt_current_user_is_verified') && aksrt_current_user_is_verified(); default: return true; } } endif; if (!function_exists('aksrt_comments_build_context')) : /** * Resolve comments runtime context once. * * @return array */ function aksrt_comments_build_context(): array { $settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_comment_display_settings() : [ 'order' => 'desc', 'nested_depth' => 3, 'require_login' => false, 'avatar_size' => 48, 'empty_text' => __('暂无评论,来做第一个评论的人吧~', 'aksrt'), ]; $default_order = (($settings['order'] ?? 'desc') === 'asc') ? 'oldest' : 'newest'; $order = isset($_GET['aksrt_comment_order']) ? sanitize_key((string) wp_unslash($_GET['aksrt_comment_order'])) : $default_order; if (!in_array($order, ['newest', 'oldest', 'hottest'], true)) { $order = 'newest'; } $avatar_size = max(24, (int) ($settings['avatar_size'] ?? 48)); $toolbar = is_array($settings['toolbar'] ?? null) ? $settings['toolbar'] : ['code' => true, 'image' => true]; return [ 'settings' => $settings, 'comment_count' => (int) get_comments_number(), 'is_logged_in' => is_user_logged_in(), 'current_user' => wp_get_current_user(), 'require_login' => !empty($settings['require_login']), 'order' => $order, 'reverse_comments' => $order === 'newest', 'is_hottest' => $order === 'hottest', 'author_only' => isset($_GET['aksrt_author_only']) && (int) $_GET['aksrt_author_only'] === 1, 'post_author_id' => (int) get_the_author_meta('ID'), 'avatar_size' => $avatar_size, 'max_depth' => max(1, (int) ($settings['nested_depth'] ?? 3)), 'empty_text' => (string) ($settings['empty_text'] ?? __('暂无评论,来做第一个评论的人吧~', 'aksrt')), 'toolbar' => $toolbar, 'upload_enabled' => !empty($toolbar['upload_img']), 'link_enabled' => !empty($toolbar['link']), 'user_url_enabled' => !empty($settings['user_url']), 'box_placeholder' => (string) ($settings['box_placeholder'] ?? __('说点什么吧...', 'aksrt')), 'submit_text' => (string) ($settings['submit_text'] ?? __('提交评论', 'aksrt')), 'title_text' => (string) ($settings['title'] ?? __('评论', 'aksrt')), 'corderby_enabled' => !empty($settings['corderby']), 'close_comments' => !empty($settings['close_comments']), 'box_hidden' => !aksrt_comment_box_visible(), 'oauth_providers' => class_exists('\AKSRT\Auth\OAuth') ? \AKSRT\Auth\OAuth::get_instance()->get_auth_providers_data() : [], ]; } endif; if (!function_exists('aksrt_comments_apply_hottest_order')) : /** * Apply hottest-order SQL once for the current comments query. */ function aksrt_comments_apply_hottest_order(): void { static $applied = false; if ($applied) { return; } $applied = true; add_filter('comments_clauses', static function ($clauses) { global $wpdb; $clauses['join'] .= " LEFT JOIN {$wpdb->commentmeta} AS aksrt_cm ON ({$wpdb->comments}.comment_ID = aksrt_cm.comment_id AND aksrt_cm.meta_key = 'aksrt_comment_likes')"; $clauses['orderby'] = 'CAST(aksrt_cm.meta_value AS UNSIGNED) DESC, ' . $clauses['orderby']; return $clauses; }); } endif; if (!function_exists('aksrt_comments_normalize_order')) : /** * Normalize comment order key. */ function aksrt_comments_normalize_order(string $order = ''): string { $order = sanitize_key($order); if (!in_array($order, ['newest', 'oldest', 'hottest'], true)) { $settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_comment_display_settings() : []; $order = (($settings['order'] ?? 'desc') === 'asc') ? 'oldest' : 'newest'; } if (!in_array($order, ['newest', 'oldest', 'hottest'], true)) { $order = 'newest'; } return $order; } endif; if (!function_exists('aksrt_comments_query_for_post')) : /** * Shared comment query for first paint / fragment / load-more. * * @return array{comments:array,total:int,max_pages:int,page:int,order:string,author_only:bool,settings:array} */ function aksrt_comments_query_for_post(int $post_id, array $args = []): array { $settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_comment_display_settings() : []; $order = aksrt_comments_normalize_order((string) ($args['order'] ?? '')); $author_only = !empty($args['author_only']); $page = max(1, (int) ($args['page'] ?? 1)); $per_page = max(1, (int) ($args['per_page'] ?? get_option('comments_per_page', 10))); $include_unapproved_for_user = (int) ($args['include_unapproved_user'] ?? 0); $query_args = [ 'post_id' => $post_id, 'status' => 'approve', 'number' => $per_page, 'offset' => ($page - 1) * $per_page, 'orderby' => 'comment_date_gmt', 'order' => $order === 'oldest' ? 'ASC' : 'DESC', 'hierarchical' => 'threaded', ]; if ($author_only) { $author_id = (int) get_post_field('post_author', $post_id); if ($author_id > 0) { $query_args['user_id'] = $author_id; $query_args['hierarchical'] = false; } } if ($include_unapproved_for_user > 0) { // WP_Comment_Query does not support mixed status easily; keep approve only for list fragment. } // Hottest uses meta_value_num when meta exists; fall back to date. $hottest_filter = null; if ($order === 'hottest') { $query_args['orderby'] = 'meta_value_num'; $query_args['meta_key'] = 'aksrt_comment_likes'; $query_args['order'] = 'DESC'; // Ensure comments without like meta still appear. $query_args['meta_query'] = [ 'relation' => 'OR', [ 'key' => 'aksrt_comment_likes', 'compare' => 'EXISTS', ], [ 'key' => 'aksrt_comment_likes', 'compare' => 'NOT EXISTS', ], ]; // Prefer clauses filter for stable hottest ordering. $hottest_filter = static function ($clauses) { global $wpdb; if (strpos($clauses['join'], 'aksrt_cm_hot') === false) { $clauses['join'] .= " LEFT JOIN {$wpdb->commentmeta} AS aksrt_cm_hot ON ({$wpdb->comments}.comment_ID = aksrt_cm_hot.comment_id AND aksrt_cm_hot.meta_key = 'aksrt_comment_likes')"; } $clauses['orderby'] = 'CAST(COALESCE(aksrt_cm_hot.meta_value, 0) AS UNSIGNED) DESC, ' . $wpdb->comments . '.comment_date_gmt DESC'; return $clauses; }; add_filter('comments_clauses', $hottest_filter, 20); // Prefer date orderby with clauses override. $query_args['orderby'] = 'comment_date_gmt'; unset($query_args['meta_key'], $query_args['meta_query']); } $comment_query = new WP_Comment_Query($query_args); $comments = is_array($comment_query->comments) ? $comment_query->comments : []; if ($hottest_filter) { remove_filter('comments_clauses', $hottest_filter, 20); } // Pin reorder for page 1 when not author-only. if ($page === 1 && !$author_only && function_exists('aksrt_reorder_pinned_comments')) { $comments = aksrt_reorder_pinned_comments($comments, $post_id); } $count_args = [ 'post_id' => $post_id, 'status' => 'approve', 'count' => true, ]; if ($author_only) { $author_id = (int) get_post_field('post_author', $post_id); if ($author_id > 0) { $count_args['user_id'] = $author_id; } } $total = (int) get_comments($count_args); $max_pages = (int) max(1, (int) ceil($total / $per_page)); return [ 'comments' => $comments, 'total' => $total, 'max_pages' => $max_pages, 'page' => $page, 'order' => $order, 'author_only' => $author_only, 'settings' => $settings, 'per_page' => $per_page, ]; } endif; if (!function_exists('aksrt_comments_render_items_html')) : /** * Render comment list items HTML via canonical callback. * * @param array $comments * @param array $settings * @param string $order */ function aksrt_comments_render_items_html(array $comments, array $settings = [], string $order = 'newest'): string { if (empty($comments) || !function_exists('aksrt_comment_callback')) { return ''; } set_query_var('aksrt_comment_settings', $settings); set_query_var('aksrt_comment_order', aksrt_comments_normalize_order($order)); $avatar = max(24, (int) ($settings['avatar_size'] ?? 48)); $depth = max(1, (int) ($settings['nested_depth'] ?? 3)); $reverse = $order === 'newest'; ob_start(); wp_list_comments([ 'callback' => 'aksrt_comment_callback', 'style' => 'ol', 'avatar_size' => $avatar, 'max_depth' => $depth, 'reverse_top_level' => $reverse, 'reverse_children' => $reverse, ], $comments); return (string) ob_get_clean(); } endif; if (!function_exists('aksrt_comments_render_single_html')) : /** * Render one comment item HTML. */ function aksrt_comments_render_single_html(\WP_Comment $comment, array $settings = []): string { $html = aksrt_comments_render_items_html([$comment], $settings, 'newest'); return $html; } endif; if (!function_exists('aksrt_comments_render_list_fragment')) : /** * Fragment payload for order/author/page AJAX. * * @return array{html:string,items_html:string,count_text:string,total:int,max_pages:int,page:int,order:string,author_only:bool,empty:bool} */ function aksrt_comments_render_list_fragment(int $post_id, array $args = []): array { $result = aksrt_comments_query_for_post($post_id, $args); $settings = $result['settings']; $order = $result['order']; $author_only = !empty($result['author_only']); $page = (int) $result['page']; $max_pages = (int) $result['max_pages']; $total = (int) $result['total']; // Fake globals needed by pagination helpers when not on singular loop. $GLOBALS['post'] = get_post($post_id); setup_postdata($GLOBALS['post']); set_query_var('cpage', $page); set_query_var('aksrt_comment_order', $order); set_query_var('aksrt_comment_settings', $settings); $items_html = aksrt_comments_render_items_html($result['comments'], $settings, $order); $ctx = [ 'order' => $order, 'author_only' => $author_only, 'post_author_id' => (int) get_post_field('post_author', $post_id), 'corderby_enabled' => !empty($settings['corderby']), 'comment_count' => $total, 'empty_text' => (string) ($settings['empty_text'] ?? __('暂无评论,来做第一个评论的人吧~', 'aksrt')), ]; ob_start(); echo '
    '; if ($items_html === '') { if (function_exists('aksrt_comments_render_empty')) { aksrt_comments_render_empty($ctx); } echo ''; } else { if (function_exists('aksrt_comments_render_filter') && !empty($ctx['corderby_enabled'])) { aksrt_comments_render_filter($ctx); } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- rendered comment markup. echo $items_html; if (function_exists('aksrt_render_comment_pagination') && $max_pages > 1) { $pages_filter = static function () use ($max_pages) { return $max_pages; }; add_filter('get_comment_pages_count', $pages_filter); aksrt_render_comment_pagination(); remove_filter('get_comment_pages_count', $pages_filter); } } echo '
'; $list_html = (string) ob_get_clean(); wp_reset_postdata(); return [ 'html' => $list_html, 'items_html' => $items_html, 'count_text' => sprintf(__('共%s条', 'aksrt'), (string) $total), 'total' => $total, 'max_pages' => $max_pages, 'page' => $page, 'order' => $order, 'author_only' => $author_only, 'empty' => $items_html === '', ]; } endif; if (!function_exists('aksrt_comments_render_signarea')) : /** * Login-required gate. * * @param array $ctx Comments context. */ function aksrt_comments_render_signarea(array $ctx): void { $oauth_providers = is_array($ctx['oauth_providers'] ?? null) ? $ctx['oauth_providers'] : []; $login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url(get_permalink()) : wp_login_url(get_permalink()); ?> $ctx Comments context. */ function aksrt_comments_render_form(array $ctx): void { $is_logged_in = !empty($ctx['is_logged_in']); $current_user = $ctx['current_user'] ?? null; $require_name_email = (bool) get_option('require_name_email'); $comment_author = isset($_COOKIE['comment_author_' . COOKIEHASH]) ? sanitize_text_field(wp_unslash((string) $_COOKIE['comment_author_' . COOKIEHASH])) : ''; $comment_email = isset($_COOKIE['comment_author_email_' . COOKIEHASH]) ? sanitize_text_field(wp_unslash((string) $_COOKIE['comment_author_email_' . COOKIEHASH])) : ''; $comment_author_url = isset($_COOKIE['comment_author_url_' . COOKIEHASH]) ? esc_url_raw(wp_unslash((string) $_COOKIE['comment_author_url_' . COOKIEHASH])) : ''; $placeholder = (string) $ctx['box_placeholder']; $post_id = (int) get_the_ID(); $can_comment = function_exists('aksrt_user_can') ? aksrt_user_can('comment_add', get_current_user_id(), $post_id) : $is_logged_in; if (!$can_comment) { if (!$is_logged_in) { aksrt_comments_render_signarea($ctx); } else { // 治理状态区分提示(参考主题 zib_get_user_ban_nocan_info 语义: // 禁封中/小黑屋/禁言显示状态徽章与查看入口,而非笼统的无权限文案)。 $ban_nocan = function_exists('aksrt_get_user_ban_nocan_html') ? aksrt_get_user_ban_nocan_html(get_current_user_id(), __('暂时无法发表评论', 'aksrt')) : ''; if ($ban_nocan !== '') { echo $ban_nocan; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- helper escapes internally. } else { echo '

' . esc_html__('当前账号没有发表评论的权限。', 'aksrt') . '

'; } } return; } if (function_exists('aksrt_get_comment_virtual_input_html')) { echo aksrt_get_comment_virtual_input_html($placeholder, '#respond'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } ?>
ID, 60, '', '', ['class' => 'avatar']); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>

ID) : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- vip 徽章内部已转义。 ?>display_name); ?>

'avatar']); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>

>
$ctx Comments context. */ function aksrt_comments_render_filter(array $ctx): void { if (empty($ctx['corderby_enabled'])) { return; } $order = (string) $ctx['order']; $author_only = !empty($ctx['author_only']); $post_author_id = (int) $ctx['post_author_id']; ?>
0) : ?>
  • '; return ''; } endif; if (!function_exists('aksrt_comments_render_empty')) : /** * Empty state (legacy: legacy('暂无评论内容', 40, 'null.svg', 'comment comment-null')). * * @param array $ctx Comments context. */ function aksrt_comments_render_empty(array $ctx): void { $text = (string) ($ctx['empty_text'] ?? __('暂无评论内容', 'aksrt')); if (!empty($ctx['author_only'])) { $text = __('暂无作者评论', 'aksrt'); } if (function_exists('aksrt_get_null')) { echo aksrt_get_null($text, 40, 'null.svg', 'comment comment-null', 280); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped return; } echo '

    ' . esc_html($text) . '

    '; } endif; if (!function_exists('aksrt_comments_render')) : /** * Compose the full comments surface. */ function aksrt_comments_render(): void { if (post_password_required() || !comments_open()) { return; } $ctx = aksrt_comments_build_context(); if (!empty($ctx['close_comments']) || !empty($ctx['box_hidden'])) { return; } if (!empty($ctx['is_hottest'])) { aksrt_comments_apply_hottest_order(); } set_query_var('aksrt_comment_order', (string) $ctx['order']); set_query_var('aksrt_comment_settings', $ctx['settings']); $count = (int) $ctx['comment_count']; $count_label = $count > 0 ? sprintf(__('共%s条', 'aksrt'), (string) $count) : __('抢沙发', 'aksrt'); ?>
    ' . esc_html($count_label) . ''; ?>
      0 || !empty($ctx['author_only']) || have_comments()); if ($show_filter) { aksrt_comments_render_filter($ctx); } if (have_comments()) { aksrt_comments_render_list_items($ctx); } else { aksrt_comments_render_empty($ctx); echo ''; } ?>
    $ctx Comments context. */ function aksrt_comments_render_list_items(array $ctx): void { wp_list_comments([ 'type' => 'comment', 'style' => 'ol', 'avatar_size' => (int) $ctx['avatar_size'], 'max_depth' => (int) $ctx['max_depth'], 'callback' => 'aksrt_comment_callback', 'reverse_top_level' => !empty($ctx['reverse_comments']), 'reverse_children' => !empty($ctx['reverse_comments']), ]); echo aksrt_get_comment_ajax_loader(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped if (function_exists('aksrt_render_comment_pagination')) { aksrt_render_comment_pagination(); } } endif;