diff --git a/comments.php b/comments.php index 0eca1f3..35b574f 100644 --- a/comments.php +++ b/comments.php @@ -17,6 +17,18 @@ * * 4. **提交按钮的禁用态由 JS 控制**,模板里给出 `.is-loading` 的样式钩子。 * + * ── 3.2.19 修的两个结构问题 ────────────────────────────────── + * 5. **取数不再交给 `wp_list_comments()` 推导**。3.2.18 传了 + * `page=1` / `per_page=10`,而核心那段"独立查询"分支在内层 + * 条件不成立时**不会给 `$_comments` 赋值**(注释说会回退到 + * `$wp_query->comments`,但代码里没有这个回退),结果 + * `paged_walk(null, ...)` 输出空串 —— 评论一条都不显示。 + * 现在由 `yang_comment_page()` 取好、当第二个参数传进去。 + * + * 6. **子评论容器改成 `yang-children`**(见 `Yang_Walker_Comment`)。 + * 核心 `start_lvl()` 固定输出 `class="children"`,而样式表里 + * 几十条规则全按 `.yang-children` 写,类名对不上就全部失效。 + * * @author Yongquan Yang * @license MIT License */ @@ -81,22 +93,41 @@ if ($yang_per_page <= 0) { ?>
    'comment', 'callback' => 'comment_callbacks', + 'walker' => new Yang_Walker_Comment(), 'style' => 'ol', 'max_depth' => $yang_threaded ? $yang_max_depth : 1, 'avatar_size' => 48, - 'per_page' => $yang_paged ? $yang_per_page : 0, - 'page' => 1, - )); + 'per_page' => 0, + 'page' => 0, + ), $yang_page_comments); ?>
$yang_per_page; + $yang_top_count = (int) get_comments(array( + 'post_id' => $yang_post_id, + 'status' => 'approve', + 'parent' => 0, + 'count' => true, + )); + $yang_has_more = $yang_paged && $yang_top_count > $yang_per_page; ?>
>
'; // actions $o[] = ''; // main - $o[] = ''; + + /* 闭合 交给调用方决定。 + wp_list_comments 的 walker 会在 start_el 之后、start_lvl 之前 + 插入子评论容器,所以走列表渲染时这条 **必须先不闭合**, + 否则子评论会被挤到 外面,变成父评论的兄弟节点 —— + HTML 会变成
    这种畸形结构, + CSS 里 "子评论占满整行" 的规则就完全不生效。 + AJAX 单独拼 HTML 时没有 walker,才需要自己闭合。 */ + if ($close_li) { + $o[] = ''; + } return implode('', $o); } +/** + * 评论列表的 walker + * + * 只覆盖两处,其余沿用 Walker_Comment: + * 1. 子评论容器类名用 `yang-children`(CSS 按这个类名写缩进与栅格)。 + * 核心固定输出 `class="children"`,样式对不上。 + * 2. 配合 `comment_callbacks()` 不再自己闭合 , + * 让核心的 end_el 去闭合 —— 这样
      才落在
    1. 内部。 + */ +class Yang_Walker_Comment extends Walker_Comment +{ + public function start_lvl(&$output, $depth = 0, $args = array()) + { + $GLOBALS['comment_depth'] = $depth + 1; + $output .= '
        ' . "\n"; + } +} + /** * wp_list_comments 的回调(列表渲染) * * 只是把参数转交给统一渲染函数。保留这个函数名是因为 * comments.php 里引用了它,且子主题可能覆盖过。 + * + * 注意末尾传 false:不在这里闭合 ,交给 walker 的 end_el。 + * 原因见 yang_comment_html() 里的注释。 */ function comment_callbacks($comment, $args = array(), $depth = 1) { - echo yang_comment_html($comment, $args, $depth, false); + echo yang_comment_html($comment, $args, $depth, false, false); } /** @@ -408,13 +442,85 @@ function yang_comment_count_text($n) return sprintf(__('%s 条评论', 'kratos'), number_format_i18n($n)); } +/** + * 取「第 N 页评论」:按**顶层评论**分页,再把每条的子孙展开成平铺数组 + * + * ── 为什么不直接把 page/per_page 交给 wp_list_comments ────── + * WP 那个分支有缺陷:当 `page`/`per_page` 与它自己从查询变量推导出的 + * 当前页完全相等时,内层 `if` 不成立,`$_comments` 就**一次都没被赋值** + * (源码里那句"fall back on $wp_query->comments"的注释下面并没有回退代码), + * 最终 `paged_walk(null, ...)` 返回空字符串。表现就是: + * 「评论(N)」标题在、输入框在,列表一条不显示。 + * 单页评论的文章(max_num_comment_pages=1)必然命中,多页的反而侥幸正常 —— + * 这也是它为什么看起来"时好时坏"。 + * + * 所以取数由这里负责,`wp_list_comments()` 的第 2 个参数直接收数组, + * 走它的 `null !== $comments` 分支,不碰那段有问题的推导。 + * + * ── 为什么按顶层分页 ──────────────────────────────────────── + * 分页若按"行"算,一条顶层评论和它的 10 条回复可能被切到两页, + * 第 2 页会出现一堆没有父评论的孤儿回复。按顶层 + 整体展开, + * 父子永远同页。 + * + * @param int $post_id 文章 ID + * @param int $page 第几页(从 1 开始) + * @param int $per_page 每页多少条顶层评论;0 = 不分页,全取 + * @return WP_Comment[] 平铺后的评论(父在子前,可直接交给 wp_list_comments) + */ +function yang_comment_page($post_id, $page = 1, $per_page = 0) +{ + $post_id = (int) $post_id; + if ($post_id <= 0) { + return array(); + } + + $order = strtoupper((string) get_option('comment_order', 'asc')) === 'DESC' ? 'DESC' : 'ASC'; + + $args = array( + 'post_id' => $post_id, + 'status' => 'approve', + 'orderby' => 'comment_date_gmt', + 'order' => $order, + 'parent' => 0, + 'hierarchical' => 'threaded', + ); + if ($per_page > 0) { + $args['number'] = (int) $per_page; + $args['offset'] = max(0, ((int) $page - 1) * (int) $per_page); + } + + $top = get_comments($args); + if (!$top) { + return array(); + } + + /* 展开子孙。用 get_children() 而不是读 $comment->children —— + 后者是 protected,而且要先经 hierarchical='threaded' 才会被填充。 */ + $flat = array(); + foreach ($top as $c) { + $flat[] = $c; + $kids = $c->get_children(array( + 'format' => 'flat', + 'status' => 'approve', + 'orderby' => 'comment_date_gmt', + 'order' => $order, + )); + foreach ($kids as $kid) { + $flat[] = $kid; + } + } + return $flat; +} + /** * 「加载更多评论」AJAX * * 旧模板里 `previous_comments_link(__('加载更多'))` 是个普通链接, * 点了整页跳转(还跳到评论分页 URL)。这里改成原地加载。 * - * 分页参数用 WordPress 原生的 cpage,保证"直接访问第 2 页评论"也能工作。 + * 取数与首屏共用 `yang_comment_page()`:以前这里自己写了一份只取顶层、 + * 只渲染顶层的查询,导致点「加载更多」出来的评论**全部没有子回复** + * (实测某篇 10 条顶层名下有 12 条回复被吞掉)。 */ function yang_ajax_load_comments() { @@ -430,15 +536,7 @@ function yang_ajax_load_comments() $per_page = 20; } - $comments = get_comments(array( - 'post_id' => $post_id, - 'status' => 'approve', - 'order' => strtoupper(get_option('comment_order', 'asc')) === 'DESC' ? 'DESC' : 'ASC', - 'number' => $per_page, - 'offset' => ($page - 1) * $per_page, - // 只取顶层,子评论随父一起输出 - 'parent' => 0, - )); + $comments = yang_comment_page($post_id, $page, $per_page); $max_depth = (int) get_option('thread_comments_depth', 5); $args = array( @@ -448,21 +546,41 @@ function yang_ajax_load_comments() 'avatar_size' => 48, ); - $html = ''; - foreach ($comments as $c) { - $html .= yang_comment_html($c, $args, 1, false); - } + /* 渲染走 wp_list_comments + 同一个 walker,和首屏完全同一条路径。 + 以前这里是 foreach 手动拼 yang_comment_html(),没有 walker, + 于是子回复被平铺成父评论的兄弟节点、层级信息全丢 + —— 实测某篇 10 条顶层名下的 12 条回复结构全错。 */ + ob_start(); + wp_list_comments(array( + 'type' => 'comment', + 'callback' => 'comment_callbacks', + 'walker' => new Yang_Walker_Comment(), + 'style' => 'ol', + 'max_depth' => $max_depth > 0 ? $max_depth : 5, + 'avatar_size' => 48, + 'per_page' => 0, + 'page' => 0, + ), $comments); + $html = ob_get_clean(); + + // 分页按顶层算,所以"还有没有更多"也要按顶层比,不能拿总评论数比 + $top_total = (int) get_comments(array( + 'post_id' => $post_id, + 'status' => 'approve', + 'parent' => 0, + 'count' => true, + )); + $loaded_top = $page * $per_page; $total = (int) get_comments_number($post_id); - $loaded = $page * $per_page; wp_send_json(array( 'ok' => true, 'html' => $html, 'page' => $page, - 'has_more' => $loaded < $total, + 'has_more' => $loaded_top < $top_total, 'next_page' => $page + 1, - 'loaded' => $loaded, + 'loaded' => $loaded_top, 'total' => $total, )); } diff --git a/style.css b/style.css index b0b980a..96f141b 100644 --- a/style.css +++ b/style.css @@ -1,7 +1,7 @@ /* Theme Name: Kratos_Yang Text Domain: kratos_Yang -Version: 3.2.18 +Version: 3.2.19 Requires PHP: 7.0 Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。 Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好