$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_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, 'allow_reply' => true, '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'] : ['smilie' => true, 'code' => true, 'image' => true]; $phrases = is_array($settings['quick_phrases'] ?? null) ? $settings['quick_phrases'] : []; 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)), 'allow_reply' => !empty($settings['allow_reply']), 'empty_text' => (string) ($settings['empty_text'] ?? __('暂无评论,来做第一个评论的人吧~', 'aksrt')), 'toolbar' => $toolbar, 'upload_enabled' => !empty($toolbar['upload_img']), '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']), 'quick_s' => !isset($settings['quick_s']) || !empty($settings['quick_s']), 'quick_phrases' => $phrases, '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,filter_html:string,pagination_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(); if (function_exists('aksrt_comments_render_filter') && !empty($ctx['corderby_enabled'])) { aksrt_comments_render_filter($ctx); } $filter_html = (string) ob_get_clean(); ob_start(); if ($items_html === '' && function_exists('aksrt_comments_render_empty')) { aksrt_comments_render_empty($ctx); } else { echo '
    '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- rendered comment markup. echo $items_html; echo '
'; } $list_html = (string) ob_get_clean(); ob_start(); if (function_exists('aksrt_render_comment_pagination') && $max_pages > 1) { // Temporarily override page counts via filter. $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); } $pagination_html = (string) ob_get_clean(); wp_reset_postdata(); return [ 'html' => $list_html, 'items_html' => $items_html, 'filter_html' => $filter_html, 'pagination_html' => $pagination_html, 'count_text' => sprintf(__('共 %d 条', 'aksrt'), $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'] : []; ?> $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; $avatar_size = max(40, (int) $ctx['avatar_size']); $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])) : ''; $placeholder = (string) $ctx['box_placeholder']; 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, $avatar_size, '', '', ['class' => 'avatar-img comt-avatar']); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>

display_name); ?>

'avatar-img comt-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) : ?>
$ctx Comments context. */ function aksrt_comments_render_list(array $ctx): void { ?>
    'ol', 'short_ping' => true, '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']), ]); ?>
$ctx Comments context. */ function aksrt_comments_render_empty(array $ctx): void { $closed = !comments_open(); $text = (string) ($ctx['empty_text'] ?? __('暂无评论内容', 'aksrt')); if ($closed) { $text = __('评论已关闭', 'aksrt'); } elseif (!empty($ctx['author_only'])) { $text = __('暂无作者评论', 'aksrt'); } $hint = $closed ? __('本文评论已关闭,仅可浏览历史留言', 'aksrt') : (!empty($ctx['author_only']) ? __('切换到「查看全部」可浏览其他评论', 'aksrt') : __('成为第一个评论者吧', 'aksrt')); if (function_exists('aksrt_get_null')) { echo aksrt_get_null($text, 40, 'null.svg', 'comment comment-null comments-empty', 220); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo '

' . esc_html($hint) . '

'; return; } ?>

0 ? sprintf(__('共%s条', 'aksrt'), (string) $count) : __('抢沙发', 'aksrt'); ?>
0 || !empty($ctx['author_only']) || have_comments()); if ($show_filter) { aksrt_comments_render_filter($ctx); } ?>