3.2.19: 修复关闭 wpDiscuz 后评论列表整段不显示
现象:#5264 等文章标题「评论(4)」与输入框都在,但 <ol> 内 0 字节。 只有单页评论的文章必现,多页文章反而正常。 根因:3.2.18 给 wp_list_comments() 传了 page=1 / per_page=10, 进入核心的"独立查询"分支。当这两个值与核心自己推导的 current_cpage / comments_per_page 恰好相等时,内层 if 不成立, $_comments 一次都没被赋值(源码注释说会回退到 $wp_query->comments, 但那句注释下面没有回退代码),结果 paged_walk(null) 返回空串。 修复: - 新增 yang_comment_page():按顶层评论分页 + get_children() 展平子孙。 按顶层分页可避免父子被切到两页产生孤儿回复。 - comments.php 把结果当第二参数显式传给 wp_list_comments, 走 null !== $comments 分支,绕开有问题的推导。 连带修掉的三处: - Walker_Comment::end_el() 总会补 </li>,callback 再写一个导致 </li></li>,子容器被挤成父评论的兄弟节点、CSS 栅格失效。 yang_comment_html() 新增 $close_li,列表路径交给 walker 闭合。 - 核心 start_lvl() 固定输出 class="children",而样式表按 .yang-children 写,类名不符导致缩进/栅格全失效。 新增 Yang_Walker_Comment 覆盖 start_lvl()。 - AJAX「加载更多」原先只取顶层、只渲染顶层,吞掉全部子回复 (实测某篇 10 条顶层名下 12 条回复丢失)。改为走同一 walker, has_more 也改成与首屏同口径的顶层计数。
This commit is contained in:
+36
-5
@@ -17,6 +17,18 @@
|
|||||||
*
|
*
|
||||||
* 4. **提交按钮的禁用态由 JS 控制**,模板里给出 `.is-loading` 的样式钩子。
|
* 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 <yangyq.net>
|
* @author Yongquan Yang <yangyq.net>
|
||||||
* @license MIT License
|
* @license MIT License
|
||||||
*/
|
*/
|
||||||
@@ -81,22 +93,41 @@ if ($yang_per_page <= 0) {
|
|||||||
?>
|
?>
|
||||||
<ol class="yang-comment-list" id="yang-comment-list">
|
<ol class="yang-comment-list" id="yang-comment-list">
|
||||||
<?php
|
<?php
|
||||||
|
/* 取数自己来,不让 wp_list_comments 去推导分页。
|
||||||
|
原因见 inc/theme-comments.php 里 yang_comment_page() 的注释:
|
||||||
|
当它推导出的当前页与传入的 page 相等时,内部 $_comments
|
||||||
|
不会被赋值,列表直接是空的。显式传数组就绕开了那段逻辑。 */
|
||||||
|
$yang_page_comments = yang_comment_page(
|
||||||
|
$yang_post_id,
|
||||||
|
1,
|
||||||
|
$yang_paged ? $yang_per_page : 0
|
||||||
|
);
|
||||||
|
|
||||||
wp_list_comments(array(
|
wp_list_comments(array(
|
||||||
'type' => 'comment',
|
'type' => 'comment',
|
||||||
'callback' => 'comment_callbacks',
|
'callback' => 'comment_callbacks',
|
||||||
|
'walker' => new Yang_Walker_Comment(),
|
||||||
'style' => 'ol',
|
'style' => 'ol',
|
||||||
'max_depth' => $yang_threaded ? $yang_max_depth : 1,
|
'max_depth' => $yang_threaded ? $yang_max_depth : 1,
|
||||||
'avatar_size' => 48,
|
'avatar_size' => 48,
|
||||||
'per_page' => $yang_paged ? $yang_per_page : 0,
|
'per_page' => 0,
|
||||||
'page' => 1,
|
'page' => 0,
|
||||||
));
|
), $yang_page_comments);
|
||||||
?>
|
?>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
/* 加载更多:只在「有分页」且「总数超过一页」时出现。
|
/* 加载更多:只在「有分页」且「顶层评论数超过一页」时出现。
|
||||||
|
判据必须与 AJAX 的 has_more 同口径(都按顶层算),
|
||||||
|
否则会出现"按钮还在、点了却什么都没有"。
|
||||||
旧模板无条件输出,即使只有 1 条评论也显示一个点不动的按钮。 */
|
旧模板无条件输出,即使只有 1 条评论也显示一个点不动的按钮。 */
|
||||||
$yang_has_more = $yang_paged && $yang_comment_count > $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;
|
||||||
?>
|
?>
|
||||||
<div class="comments-more" id="yang-comments-more"<?php echo $yang_has_more ? '' : ' hidden'; ?>>
|
<div class="comments-more" id="yang-comments-more"<?php echo $yang_has_more ? '' : ' hidden'; ?>>
|
||||||
<button type="button" class="comments-more-btn" data-page="2">
|
<button type="button" class="comments-more-btn" data-page="2">
|
||||||
|
|||||||
+137
-19
@@ -65,9 +65,12 @@ function yang_comments_plugin_active()
|
|||||||
* @param array $args wp_list_comments 传入的参数(深度等)
|
* @param array $args wp_list_comments 传入的参数(深度等)
|
||||||
* @param int $depth 当前深度
|
* @param int $depth 当前深度
|
||||||
* @param bool $is_ajax 是否是被 AJAX 返回的新评论
|
* @param bool $is_ajax 是否是被 AJAX 返回的新评论
|
||||||
|
* @param bool $close_li 是否在末尾闭合 </li>
|
||||||
|
* —— 走 wp_list_comments 时必须传 false,
|
||||||
|
* 否则子评论会被挤到 </li> 外面(详见下方注释)
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
function yang_comment_html($comment, $args = array(), $depth = 1, $is_ajax = false)
|
function yang_comment_html($comment, $args = array(), $depth = 1, $is_ajax = false, $close_li = true)
|
||||||
{
|
{
|
||||||
if (!($comment instanceof WP_Comment)) {
|
if (!($comment instanceof WP_Comment)) {
|
||||||
return '';
|
return '';
|
||||||
@@ -180,20 +183,51 @@ function yang_comment_html($comment, $args = array(), $depth = 1, $is_ajax = fal
|
|||||||
|
|
||||||
$o[] = '</div>'; // actions
|
$o[] = '</div>'; // actions
|
||||||
$o[] = '</div>'; // main
|
$o[] = '</div>'; // main
|
||||||
|
|
||||||
|
/* 闭合 </li> 交给调用方决定。
|
||||||
|
wp_list_comments 的 walker 会在 start_el 之后、start_lvl 之前
|
||||||
|
插入子评论容器,所以走列表渲染时这条 </li> **必须先不闭合**,
|
||||||
|
否则子评论会被挤到 </li> 外面,变成父评论的兄弟节点 ——
|
||||||
|
HTML 会变成 </li></li><ol class="children"> 这种畸形结构,
|
||||||
|
CSS 里 "子评论占满整行" 的规则就完全不生效。
|
||||||
|
AJAX 单独拼 HTML 时没有 walker,才需要自己闭合。 */
|
||||||
|
if ($close_li) {
|
||||||
$o[] = '</li>';
|
$o[] = '</li>';
|
||||||
|
}
|
||||||
|
|
||||||
return implode('', $o);
|
return implode('', $o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论列表的 walker
|
||||||
|
*
|
||||||
|
* 只覆盖两处,其余沿用 Walker_Comment:
|
||||||
|
* 1. 子评论容器类名用 `yang-children`(CSS 按这个类名写缩进与栅格)。
|
||||||
|
* 核心固定输出 `class="children"`,样式对不上。
|
||||||
|
* 2. 配合 `comment_callbacks()` 不再自己闭合 </li>,
|
||||||
|
* 让核心的 end_el 去闭合 —— 这样 <ol> 才落在 <li> 内部。
|
||||||
|
*/
|
||||||
|
class Yang_Walker_Comment extends Walker_Comment
|
||||||
|
{
|
||||||
|
public function start_lvl(&$output, $depth = 0, $args = array())
|
||||||
|
{
|
||||||
|
$GLOBALS['comment_depth'] = $depth + 1;
|
||||||
|
$output .= '<ol class="yang-children">' . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wp_list_comments 的回调(列表渲染)
|
* wp_list_comments 的回调(列表渲染)
|
||||||
*
|
*
|
||||||
* 只是把参数转交给统一渲染函数。保留这个函数名是因为
|
* 只是把参数转交给统一渲染函数。保留这个函数名是因为
|
||||||
* comments.php 里引用了它,且子主题可能覆盖过。
|
* comments.php 里引用了它,且子主题可能覆盖过。
|
||||||
|
*
|
||||||
|
* 注意末尾传 false:不在这里闭合 </li>,交给 walker 的 end_el。
|
||||||
|
* 原因见 yang_comment_html() 里的注释。
|
||||||
*/
|
*/
|
||||||
function comment_callbacks($comment, $args = array(), $depth = 1)
|
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));
|
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
|
* 「加载更多评论」AJAX
|
||||||
*
|
*
|
||||||
* 旧模板里 `previous_comments_link(__('加载更多'))` 是个普通链接,
|
* 旧模板里 `previous_comments_link(__('加载更多'))` 是个普通链接,
|
||||||
* 点了整页跳转(还跳到评论分页 URL)。这里改成原地加载。
|
* 点了整页跳转(还跳到评论分页 URL)。这里改成原地加载。
|
||||||
*
|
*
|
||||||
* 分页参数用 WordPress 原生的 cpage,保证"直接访问第 2 页评论"也能工作。
|
* 取数与首屏共用 `yang_comment_page()`:以前这里自己写了一份只取顶层、
|
||||||
|
* 只渲染顶层的查询,导致点「加载更多」出来的评论**全部没有子回复**
|
||||||
|
* (实测某篇 10 条顶层名下有 12 条回复被吞掉)。
|
||||||
*/
|
*/
|
||||||
function yang_ajax_load_comments()
|
function yang_ajax_load_comments()
|
||||||
{
|
{
|
||||||
@@ -430,15 +536,7 @@ function yang_ajax_load_comments()
|
|||||||
$per_page = 20;
|
$per_page = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
$comments = get_comments(array(
|
$comments = yang_comment_page($post_id, $page, $per_page);
|
||||||
'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,
|
|
||||||
));
|
|
||||||
|
|
||||||
$max_depth = (int) get_option('thread_comments_depth', 5);
|
$max_depth = (int) get_option('thread_comments_depth', 5);
|
||||||
$args = array(
|
$args = array(
|
||||||
@@ -448,21 +546,41 @@ function yang_ajax_load_comments()
|
|||||||
'avatar_size' => 48,
|
'avatar_size' => 48,
|
||||||
);
|
);
|
||||||
|
|
||||||
$html = '';
|
/* 渲染走 wp_list_comments + 同一个 walker,和首屏完全同一条路径。
|
||||||
foreach ($comments as $c) {
|
以前这里是 foreach 手动拼 yang_comment_html(),没有 walker,
|
||||||
$html .= yang_comment_html($c, $args, 1, false);
|
于是子回复被平铺成父评论的兄弟节点、层级信息全丢
|
||||||
}
|
—— 实测某篇 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);
|
$total = (int) get_comments_number($post_id);
|
||||||
$loaded = $page * $per_page;
|
|
||||||
|
|
||||||
wp_send_json(array(
|
wp_send_json(array(
|
||||||
'ok' => true,
|
'ok' => true,
|
||||||
'html' => $html,
|
'html' => $html,
|
||||||
'page' => $page,
|
'page' => $page,
|
||||||
'has_more' => $loaded < $total,
|
'has_more' => $loaded_top < $top_total,
|
||||||
'next_page' => $page + 1,
|
'next_page' => $page + 1,
|
||||||
'loaded' => $loaded,
|
'loaded' => $loaded_top,
|
||||||
'total' => $total,
|
'total' => $total,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Theme Name: Kratos_Yang
|
Theme Name: Kratos_Yang
|
||||||
Text Domain: kratos_Yang
|
Text Domain: kratos_Yang
|
||||||
Version: 3.2.18
|
Version: 3.2.19
|
||||||
Requires PHP: 7.0
|
Requires PHP: 7.0
|
||||||
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
|
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
|
||||||
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好
|
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好
|
||||||
|
|||||||
Reference in New Issue
Block a user