fix(admin): replicate reference comment settings page 1:1
- Rewrite post_list/comment schema (PHP + JS) with the reference theme's field set, order, defaults and dependencies; smilie, comment location and quick-reply fields excluded - Map PostDisplay::get_comment_display_settings() to the new keys without legacy fallback: close_comments, comment_paginate_type (ajax_lists), user_edit_comment master switch, WP comment_order for sorting - Wire comment_box_hide visibility gate (signin / vip / vip_2 / auth) - Drop dead comment settings (order/per_page/depth/avatar/hot threshold/ empty text/city), the dead post_close_comments field, and city readers now fully owned by the IP-geo extension - Add comment settings reference contract test
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* 「评论设置」后台设置页契约(对齐参考主题 1:1):
|
||||
* 1) PHP schema(SchemaPostList.php comment section)字段键、顺序、默认值与
|
||||
* JS schema(assets/admin/src/schema/sections/post-list/comment.js)一致;
|
||||
* 2) 参考主题字段全集存在:close_comments / comment_box_hide /
|
||||
* comment_paginate_type / comment_paging_ajax_ias_s /
|
||||
* comment_paging_ajax_ias_max / comment_code / comment_img /
|
||||
* comment_upload_img / comment_link / comment_author_tag /
|
||||
* user_edit_comment / comment_like_s / comment_user_url_s /
|
||||
* comment_corderby / comment_title / comment_submit_text / comment_text;
|
||||
* 3) 插入表情(comment_smilie)、评论地理位置(comment_city_s/comment_city_type,
|
||||
* 由扩展&增强/IP归属地实现)不在本页;
|
||||
* 4) 快捷回复按评论区硬切换契约保持移除(comment_quick_* 不存在);
|
||||
* 5) 旧 AKSRT 私有字段(comment_order / comment_per_page / comment_pagination_type /
|
||||
* comment_nested_depth / comment_avatar_size / comment_close_comments /
|
||||
* comment_edit_window / comment_hot_threshold / comment_empty_text /
|
||||
* post_close_comments)已彻底移除,无双路兼容;
|
||||
* 6) 运行时(PostDisplay::get_comment_display_settings)只读取新键。
|
||||
*/
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const test = require('node:test');
|
||||
|
||||
const root = path.resolve(__dirname, '..', '..');
|
||||
const php = fs.readFileSync(path.join(root, 'src/Admin/Schema/SchemaPostList.php'), 'utf8');
|
||||
const js = fs.readFileSync(path.join(root, 'assets/admin/src/schema/sections/post-list/comment.js'), 'utf8');
|
||||
const runtime = fs.readFileSync(path.join(root, 'src/Settings/PostDisplay.php'), 'utf8');
|
||||
const commentsHelper = fs.readFileSync(path.join(root, 'inc/helpers/aksrt-comments.php'), 'utf8');
|
||||
const geoHelper = fs.readFileSync(path.join(root, 'inc/helpers/comments/geo.php'), 'utf8');
|
||||
const actionsHelper = fs.readFileSync(path.join(root, 'inc/helpers/comments/actions.php'), 'utf8');
|
||||
|
||||
const REFERENCE_KEYS = [
|
||||
'close_comments',
|
||||
'comment_box_hide',
|
||||
'comment_paginate_type',
|
||||
'comment_paging_ajax_ias_s',
|
||||
'comment_paging_ajax_ias_max',
|
||||
'comment_code',
|
||||
'comment_img',
|
||||
'comment_upload_img',
|
||||
'comment_link',
|
||||
'comment_author_tag',
|
||||
'user_edit_comment',
|
||||
'comment_like_s',
|
||||
'comment_user_url_s',
|
||||
'comment_corderby',
|
||||
'comment_title',
|
||||
'comment_submit_text',
|
||||
'comment_text',
|
||||
];
|
||||
|
||||
// 参考主题明确不做 / 本项目不做 / 其他地方实现的字段。
|
||||
const EXCLUDED_KEYS = [
|
||||
'comment_smilie',
|
||||
'comment_city_s',
|
||||
'comment_city_type',
|
||||
'comment_quick_s',
|
||||
'comment_quick_often',
|
||||
];
|
||||
|
||||
// 旧 AKSRT 私有字段(含已并入 WP 讨论设置与死字段 post_close_comments)。
|
||||
const LEGACY_KEYS = [
|
||||
'comment_order',
|
||||
'comment_per_page',
|
||||
'comment_pagination_type',
|
||||
'comment_nested_depth',
|
||||
'comment_avatar_size',
|
||||
'comment_close_comments',
|
||||
'comment_edit_window',
|
||||
'comment_hot_threshold',
|
||||
'comment_empty_text',
|
||||
'post_close_comments',
|
||||
];
|
||||
|
||||
/** Extract the PHP 'comment' => [ ... ] section body (balanced brackets). */
|
||||
function phpCommentSection(src) {
|
||||
const start = src.indexOf("'comment' => [");
|
||||
assert.notEqual(start, -1, 'PHP schema has a comment section');
|
||||
const open = src.indexOf('[', start);
|
||||
let depth = 0;
|
||||
for (let i = open; i < src.length; i++) {
|
||||
const ch = src[i];
|
||||
if (ch === "'" || ch === '"') {
|
||||
const quote = ch;
|
||||
i++;
|
||||
while (i < src.length) {
|
||||
if (src[i] === '\\') { i += 2; continue; }
|
||||
if (src[i] === quote) break;
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (ch === '[') depth++;
|
||||
else if (ch === ']') {
|
||||
depth--;
|
||||
if (depth === 0) return src.slice(open, i + 1);
|
||||
}
|
||||
}
|
||||
throw new Error('unbalanced comment section');
|
||||
}
|
||||
|
||||
const commentPhp = phpCommentSection(php);
|
||||
|
||||
test('PHP comment section 字段键与参考主题一致且顺序相同', () => {
|
||||
// 字段定义均为 ['key' => '...', 'label' => ...] 开头;dependsOn 内的
|
||||
// ['key' => '...', 'value' => ...] 不是字段定义,须排除。
|
||||
const found = [];
|
||||
const re = /'key'\s*=>\s*'([a-z0-9_]+)',\s*'label'/g;
|
||||
let m;
|
||||
while ((m = re.exec(commentPhp)) !== null) found.push(m[1]);
|
||||
assert.deepEqual(found, REFERENCE_KEYS);
|
||||
});
|
||||
|
||||
test('PHP comment section 不含表情/地理位置/快捷回复字段', () => {
|
||||
for (const key of EXCLUDED_KEYS) {
|
||||
assert.doesNotMatch(commentPhp, new RegExp(`'${key}'`), `comment section 不应包含 ${key}`);
|
||||
}
|
||||
});
|
||||
|
||||
test('PHP comment section 默认值对齐参考主题', () => {
|
||||
assert.match(commentPhp, /'close_comments',\s*'label'\s*=>\s*'关闭文章评论功能',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*false/);
|
||||
assert.match(commentPhp, /'comment_box_hide',\s*'label'\s*=>\s*'隐藏评论模块',\s*'type'\s*=>\s*'radio',\s*'default'\s*=>\s*''/);
|
||||
assert.match(commentPhp, /'comment_paginate_type',\s*'label'\s*=>\s*'评论列表翻页模式',\s*'type'\s*=>\s*'radio',\s*'default'\s*=>\s*'default'/);
|
||||
assert.match(commentPhp, /'comment_paging_ajax_ias_s',\s*'label'\s*=>\s*'AJAX翻页自动加载',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*true/);
|
||||
assert.match(commentPhp, /'comment_paging_ajax_ias_max',\s*'label'\s*=>\s*'自动加载页数',\s*'type'\s*=>\s*'number',\s*'default'\s*=>\s*3/);
|
||||
assert.match(commentPhp, /'comment_code',\s*'label'\s*=>\s*'允许插入代码',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*true/);
|
||||
assert.match(commentPhp, /'comment_img',\s*'label'\s*=>\s*'允许插入图片',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*true/);
|
||||
assert.match(commentPhp, /'comment_upload_img',\s*'label'\s*=>\s*'允许上传图片',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*false/);
|
||||
assert.match(commentPhp, /'comment_link',\s*'label'\s*=>\s*'允许插入链接',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*false/);
|
||||
assert.match(commentPhp, /'comment_author_tag',\s*'label'\s*=>\s*'显示“作者”标签',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*true/);
|
||||
assert.match(commentPhp, /'user_edit_comment',\s*'label'\s*=>\s*'允许用户编辑评论',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*true/);
|
||||
assert.match(commentPhp, /'comment_like_s',\s*'label'\s*=>\s*'评论点赞功能',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*true/);
|
||||
assert.match(commentPhp, /'comment_user_url_s',\s*'label'\s*=>\s*'匿名评论允许输入链接',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*false/);
|
||||
assert.match(commentPhp, /'comment_corderby',\s*'label'\s*=>\s*'评论排序功能',\s*'type'\s*=>\s*'switcher',\s*'default'\s*=>\s*true/);
|
||||
assert.match(commentPhp, /'comment_title',\s*'label'\s*=>\s*'自定义评论标题',\s*'type'\s*=>\s*'textarea',\s*'default'\s*=>\s*'评论'/);
|
||||
assert.match(commentPhp, /'comment_submit_text',\s*'label'\s*=>\s*'自定义评论提交按钮文案',\s*'type'\s*=>\s*'textarea',\s*'default'\s*=>\s*'提交评论'/);
|
||||
assert.match(commentPhp, /'comment_text',\s*'label'\s*=>\s*'自定义评论框占位符文案',\s*'type'\s*=>\s*'input',\s*'default'\s*=>\s*'欢迎您留下宝贵的见解!'/);
|
||||
});
|
||||
|
||||
test('PHP comment section 选项与依赖对齐参考主题', () => {
|
||||
// 隐藏评论模块选项。
|
||||
for (const option of ['不隐藏', '登录后显示', '所有会员显示', '二级会员显示', '认证用户显示']) {
|
||||
assert.ok(commentPhp.includes(`'${option}'`), `comment_box_hide 缺少选项 ${option}`);
|
||||
}
|
||||
// 翻页模式选项。
|
||||
for (const option of ['AJAX追加列表翻页', '数字翻页按钮']) {
|
||||
assert.ok(commentPhp.includes(`'${option}'`), `comment_paginate_type 缺少选项 ${option}`);
|
||||
}
|
||||
assert.match(commentPhp, /'comment_box_hide'[\s\S]*?'dependsOn'\s*=>\s*\['key'\s*=>\s*'close_comments',\s*'value'\s*=>\s*false\]/);
|
||||
assert.match(commentPhp, /'comment_paginate_type'[\s\S]*?'dependsOn'\s*=>\s*\['key'\s*=>\s*'close_comments',\s*'value'\s*=>\s*false\]/);
|
||||
assert.match(commentPhp, /'comment_paging_ajax_ias_s'[\s\S]*?'dependsOn'\s*=>\s*\['key'\s*=>\s*'comment_paginate_type',\s*'value'\s*=>\s*'ajax_lists'\]/);
|
||||
assert.match(commentPhp, /'comment_paging_ajax_ias_max'[\s\S]*?'dependsOn'\s*=>\s*\['all'/);
|
||||
assert.match(commentPhp, /'comment_upload_img'[\s\S]*?'dependsOn'\s*=>\s*\['all'/);
|
||||
assert.match(commentPhp, /'comment_corderby'[\s\S]*?'dependsOn'\s*=>\s*\['all'/);
|
||||
// 允许插入链接在参考主题中没有依赖(其后紧跟 comment_author_tag)。
|
||||
const linkIdx = commentPhp.indexOf("'comment_link'");
|
||||
const authorTagIdx = commentPhp.indexOf("'comment_author_tag'");
|
||||
assert.ok(linkIdx !== -1 && authorTagIdx > linkIdx, 'comment_link / comment_author_tag 顺序应符合参考主题');
|
||||
const linkSlice = commentPhp.slice(linkIdx, authorTagIdx);
|
||||
assert.ok(!linkSlice.includes('dependsOn'), 'comment_link 不应有 dependsOn');
|
||||
});
|
||||
|
||||
test('JS schema 与 PHP 字段键一致(ui_only 提示行除外)', () => {
|
||||
// 字段定义为 { key: '...', label: ... };dependsOn 内的 { key, value } 须排除。
|
||||
const keys = [];
|
||||
const re = /key:\s*'([a-z0-9_]+)',\s*label:/g;
|
||||
let m;
|
||||
while ((m = re.exec(js)) !== null) keys.push(m[1]);
|
||||
const persisted = keys.filter((k) => REFERENCE_KEYS.includes(k));
|
||||
assert.deepEqual(persisted, REFERENCE_KEYS);
|
||||
for (const legacy of LEGACY_KEYS) {
|
||||
assert.ok(!keys.includes(legacy), `JS schema 残留旧字段: ${legacy}`);
|
||||
}
|
||||
for (const excluded of EXCLUDED_KEYS) {
|
||||
assert.ok(!keys.includes(excluded), `JS schema 不应包含 ${excluded}`);
|
||||
}
|
||||
// WP 讨论设置指引行承载参考主题 submessage 与【去设置】链接。
|
||||
assert.match(js, /ui_only:\s*true/);
|
||||
assert.match(js, /options-discussion\.php/);
|
||||
assert.match(js, /分页显示评论/);
|
||||
});
|
||||
|
||||
test('JS schema 默认值与选项对齐参考主题', () => {
|
||||
assert.match(js, /close_comments:\s*false/);
|
||||
assert.match(js, /comment_box_hide:\s*''/);
|
||||
assert.match(js, /comment_paginate_type:\s*'default'/);
|
||||
assert.match(js, /comment_paging_ajax_ias_s:\s*true/);
|
||||
assert.match(js, /comment_paging_ajax_ias_max:\s*3/);
|
||||
assert.match(js, /user_edit_comment:\s*true/);
|
||||
assert.match(js, /comment_text:\s*'欢迎您留下宝贵的见解!'/);
|
||||
for (const option of ['AJAX追加列表翻页', '数字翻页按钮', '登录后显示', '所有会员显示', '二级会员显示', '认证用户显示']) {
|
||||
assert.ok(js.includes(option), `JS schema 缺少选项 ${option}`);
|
||||
}
|
||||
assert.match(js, /dependsOn:\s*\{\s*key:\s*'close_comments',\s*value:\s*false\s*\}/);
|
||||
assert.match(js, /dependsOn:\s*\{\s*key:\s*'comment_paginate_type',\s*value:\s*'ajax_lists'\s*\}/);
|
||||
});
|
||||
|
||||
test('旧字段在 schema 与运行时中均已移除(无双路)', () => {
|
||||
for (const legacy of LEGACY_KEYS) {
|
||||
assert.ok(!php.includes(legacy), `PHP schema 残留旧字段: ${legacy}`);
|
||||
// 运行时按主题设置读取的形态 $settings['<legacy>'] 必须消失
|
||||
// (comment_order 允许以 WP 讨论选项 get_option('comment_order') 形态存在)。
|
||||
for (const source of [['PostDisplay', runtime], ['aksrt-comments.php', commentsHelper], ['comments/geo.php', geoHelper], ['comments/actions.php', actionsHelper]]) {
|
||||
assert.ok(!source[1].includes(`$settings['${legacy}']`), `${source[0]} 残留旧字段读取: ${legacy}`);
|
||||
}
|
||||
}
|
||||
// 运行时只读取新键。
|
||||
assert.match(runtime, /\$settings\['close_comments'\]/);
|
||||
assert.match(runtime, /\$settings\['user_edit_comment'\]/);
|
||||
assert.match(runtime, /\$settings\['comment_box_hide'\]/);
|
||||
assert.match(runtime, /Settings::get_value\('comment_paginate_type'/);
|
||||
assert.match(runtime, /return \$mode === 'ajax_lists' \? 'ajax_lists' : 'numbered';/);
|
||||
// 排序回退到 WP 讨论设置(参考主题行为)。
|
||||
assert.match(runtime, /get_option\('comment_order', 'desc'\)/);
|
||||
// 评论区位置显示交由扩展 IP 归属地控制。
|
||||
assert.match(geoHelper, /aksrt_ip_geo_display_enabled\('comment'\)/);
|
||||
assert.match(geoHelper, /aksrt_ip_geo_format_key/);
|
||||
// 编辑权限使用 user_edit 总开关。
|
||||
assert.match(actionsHelper, /\$display\['user_edit'\]/);
|
||||
});
|
||||
Reference in New Issue
Block a user