From c331b2aeefc10ef7e7f0cbee5e66c391137761f7 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 24 Sep 2026 13:43:51 +0800 Subject: [PATCH] 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 --- .../src/schema/sections/post-list/comment.js | 138 +++++------ inc/helpers/aksrt-comments.php | 29 ++- inc/helpers/aksrt-identity.php | 33 ++- inc/helpers/aksrt-ip-geo.php | 2 +- inc/helpers/comments/actions.php | 9 +- inc/helpers/comments/geo.php | 21 +- src/Admin/Schema/SchemaPostList.php | 72 +++--- src/Core/CommentActions.php | 2 +- src/Settings/PostDisplay.php | 41 +--- ...mment-settings-reference-contract.test.cjs | 224 ++++++++++++++++++ tools/admin-contract-report.json | 11 +- 11 files changed, 382 insertions(+), 200 deletions(-) create mode 100644 tests/admin/comment-settings-reference-contract.test.cjs diff --git a/assets/admin/src/schema/sections/post-list/comment.js b/assets/admin/src/schema/sections/post-list/comment.js index cbcdd281..08b28f70 100644 --- a/assets/admin/src/schema/sections/post-list/comment.js +++ b/assets/admin/src/schema/sections/post-list/comment.js @@ -2,102 +2,80 @@ export const commentSchema = { key: 'post_list.comment', title: '评论设置', icon: 'fa fas fa-comment-dots', - description: '配置评论区的排序、分页、权限、工具栏与互动方式。', + description: '配置评论模块的显隐条件、翻页模式、输入工具栏与互动方式。', defaults: { - comment_order: 'asc', - comment_per_page: 20, - comment_pagination_type: 'numbered', + close_comments: false, + comment_box_hide: '', + comment_paginate_type: 'default', comment_paging_ajax_ias_s: true, comment_paging_ajax_ias_max: 3, - comment_nested_depth: 3, - comment_avatar_size: 48, - comment_close_comments: false, - comment_edit_window: 10, comment_code: true, comment_img: true, comment_upload_img: false, comment_link: false, - comment_like_s: true, - comment_hot_threshold: 10, - comment_city_s: true, - comment_city_type: 'province_city', - comment_user_url_s: false, comment_author_tag: true, + user_edit_comment: true, + comment_like_s: true, + comment_user_url_s: false, comment_corderby: true, - comment_empty_text: '暂无评论,来做第一个评论的人吧~', comment_title: '评论', comment_submit_text: '提交评论', comment_text: '欢迎您留下宝贵的见解!', }, groups: [ { - key: 'display', - title: '评论展示', - icon: 'fa fas fa-comment', + key: 'comment', + title: '', fields: [ - { key: 'comment_order', label: '评论排序', type: 'radio', default: 'asc', options: [ - { label: '正序 (旧→新)', value: 'asc' }, - { label: '倒序 (新→旧)', value: 'desc' }, - ]}, - { key: 'comment_per_page', label: '每页评论数', type: 'number', default: 20, min: 5, max: 100 }, - { key: 'comment_pagination_type', label: '分页方式', type: 'radio', default: 'numbered', options: [ - { label: '翻页', value: 'numbered' }, - { label: '加载更多', value: 'load_more' }, - { label: '无限滚动', value: 'infinite' }, - ]}, - { key: 'comment_paging_ajax_ias_s', label: '评论自动加载', type: 'switch', default: true, help: '评论无限滚动时自动触发加载' }, - { key: 'comment_paging_ajax_ias_max', label: '评论最大加载页数', type: 'number', default: 3, min: 0, max: 10, help: '0 = 不限' }, - { key: 'comment_nested_depth', label: '回复嵌套深度', type: 'number', default: 3, min: 1, max: 10 }, - { key: 'comment_avatar_size', label: '头像大小 (px)', type: 'number', default: 48, min: 24, max: 96 }, - ], - }, - { - key: 'permissions', - title: '评论设置', - icon: 'fa fas fa-lock', - fields: [ - { key: 'comment_close_comments', label: '关闭评论', type: 'switch', default: false }, - { key: 'comment_edit_window', label: '作者自助编辑时限 (分钟)', type: 'number', default: 10, min: 0, max: 1440 }, - ], - }, - { - key: 'toolbar', - title: '评论工具栏', - icon: 'fa fas fa-wrench', - fields: [ - { key: 'comment_code', label: '代码插入', type: 'switch', default: true }, - { key: 'comment_img', label: '图片按钮', type: 'switch', default: true }, - { key: 'comment_link', label: '链接按钮', type: 'switch', default: false }, - { key: 'comment_upload_img', label: '评论图片上传', type: 'switch', default: false }, - ], - }, - { - key: 'interaction', - title: '互动功能', - icon: 'fa fas fa-heart', - fields: [ - { key: 'comment_hot_threshold', label: '神评点赞阈值', type: 'number', default: 10, min: 1, max: 999, help: '点赞数达到该值后显示「神评」徽章', dependsOn: { key: 'comment_like_s', value: true } }, - { key: 'comment_like_s', label: '评论点赞', type: 'switch', default: true }, - { key: 'comment_user_url_s', label: '匿名者网址', type: 'switch', default: false, help: '用户未登录评论时,允许输入用户博客地址' }, - { key: 'comment_city_s', label: '评论城市', type: 'switch', default: true }, - { key: 'comment_city_type', label: '城市显示格式', type: 'radio', default: 'province_city', options: [ - { label: '省份+城市', value: 'province_city' }, - { label: '仅省份', value: 'province' }, - { label: '国家+省份', value: 'country_province' }, - ], dependsOn: { key: 'comment_city_s', value: true } }, - { key: 'comment_author_tag', label: '作者标签', type: 'switch', default: true }, - { key: 'comment_corderby', label: '评论排序切换', type: 'switch', default: true, help: '前台显示最新/最早/最热切换按钮' }, - ], - }, - { - key: 'text', - title: '文案配置', - icon: 'fa fas fa-font', - fields: [ - { key: 'comment_empty_text', label: '空评论提示', type: 'input', default: '暂无评论,来做第一个评论的人吧~' }, - { key: 'comment_title', label: '评论区标题', type: 'input', default: '评论' }, - { key: 'comment_submit_text', label: '提交按钮文案', type: 'input', default: '提交评论' }, - { key: 'comment_text', label: '评论框提示', type: 'input', default: '欢迎您留下宝贵的见解!' }, + { + key: 'comment_discussion_notice', + label: '', + type: 'content', + ui_only: true, + dependsOn: { key: 'close_comments', value: false }, + content: '

WordPress默认关闭评论翻页功能,如需启用请按此进行设置:
1. 进入WP讨论设置,勾选 分页显示评论
2. 设置默认显示 最前一页
3. 设置在每个页面顶部显示 旧的评论
4. 根据需要设置每一页显示数量
5. 根据需要设置评论嵌套(推荐开启并设置为3层)
6. wp默认开启免登陆评论,如需关闭则勾选需要登录后才能发表评论
【去设置】

', + }, + { key: 'close_comments', label: '关闭文章评论功能', type: 'switch', default: false, description: '部分网站无需交互,或需备案审核,可在此关闭所有文章的评论功能。同时每一篇文章可单独关闭评论功能' }, + { + key: 'comment_box_hide', + label: '隐藏评论模块', + type: 'radio', + default: '', + dependsOn: { key: 'close_comments', value: false }, + options: [ + { label: '不隐藏', value: '' }, + { label: '登录后显示', value: 'signin' }, + { label: '所有会员显示', value: 'vip' }, + { label: '二级会员显示', value: 'vip_2' }, + { label: '认证用户显示', value: 'auth' }, + ], + description: '当用户满足条件时,文章评论功能及模块才会显示', + }, + { + key: 'comment_paginate_type', + label: '评论列表翻页模式', + type: 'radio', + default: 'default', + dependsOn: { key: 'close_comments', value: false }, + options: [ + { label: 'AJAX追加列表翻页', value: 'ajax_lists' }, + { label: '数字翻页按钮', value: 'default' }, + ], + }, + { key: 'comment_paging_ajax_ias_s', label: 'AJAX翻页自动加载', type: 'switch', default: true, dependsOn: { key: 'comment_paginate_type', value: 'ajax_lists' }, description: '页面滚动到列表尽头时,自动加载下一页' }, + { key: 'comment_paging_ajax_ias_max', label: '自动加载页数', type: 'number', default: 3, min: 0, max: 10, unit: '页', dependsOn: { all: [{ key: 'comment_paginate_type', value: 'ajax_lists' }, { key: 'comment_paging_ajax_ias_s', value: true }] }, description: 'AJAX翻页自动加载最多加载几页(为0则不限制,直到加载全部评论)' }, + { key: 'comment_code', label: '允许插入代码', type: 'switch', default: true, dependsOn: { key: 'close_comments', value: false }, help: '为了防止恶意评论,建议在后台-设置-讨论:开启“用户必须登录后才能发表评论”' }, + { key: 'comment_img', label: '允许插入图片', type: 'switch', default: true, dependsOn: { key: 'close_comments', value: false } }, + { key: 'comment_upload_img', label: '允许上传图片', type: 'switch', default: false, dependsOn: { all: [{ key: 'close_comments', value: false }, { key: 'comment_img', value: true }] } }, + { key: 'comment_link', label: '允许插入链接', type: 'switch', default: false }, + { key: 'comment_author_tag', label: '显示“作者”标签', type: 'switch', default: true, dependsOn: { key: 'close_comments', value: false } }, + { key: 'user_edit_comment', label: '允许用户编辑评论', type: 'switch', default: true, dependsOn: { key: 'close_comments', value: false } }, + { key: 'comment_like_s', label: '评论点赞功能', type: 'switch', default: true, dependsOn: { key: 'close_comments', value: false } }, + { key: 'comment_user_url_s', label: '匿名评论允许输入链接', type: 'switch', default: false, dependsOn: { key: 'close_comments', value: false }, description: '用户未登录评论时,允许输入用户博客地址' }, + { key: 'comment_corderby', label: '评论排序功能', type: 'switch', default: true, dependsOn: { all: [{ key: 'close_comments', value: false }, { key: 'comment_like_s', value: true }] }, description: '显示“最新、最热”排序按钮' }, + { key: 'comment_title', label: '自定义评论标题', type: 'textarea', default: '评论', rows: 1, dependsOn: { key: 'close_comments', value: false } }, + { key: 'comment_submit_text', label: '自定义评论提交按钮文案', type: 'textarea', default: '提交评论', rows: 1, dependsOn: { key: 'close_comments', value: false } }, + { key: 'comment_text', label: '自定义评论框占位符文案', type: 'input', default: '欢迎您留下宝贵的见解!', dependsOn: { key: 'close_comments', value: false } }, ], }, ], diff --git a/inc/helpers/aksrt-comments.php b/inc/helpers/aksrt-comments.php index f41e3848..a66db40c 100644 --- a/inc/helpers/aksrt-comments.php +++ b/inc/helpers/aksrt-comments.php @@ -63,6 +63,32 @@ add_filter('comments_template_query_args', static function ($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. @@ -116,6 +142,7 @@ if (!function_exists('aksrt_comments_build_context')) : '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() : [], @@ -646,7 +673,7 @@ if (!function_exists('aksrt_comments_render')) : } $ctx = aksrt_comments_build_context(); - if (!empty($ctx['close_comments'])) { + if (!empty($ctx['close_comments']) || !empty($ctx['box_hidden'])) { return; } diff --git a/inc/helpers/aksrt-identity.php b/inc/helpers/aksrt-identity.php index fa9b45de..76c0eed0 100644 --- a/inc/helpers/aksrt-identity.php +++ b/inc/helpers/aksrt-identity.php @@ -23,6 +23,26 @@ if (!function_exists('aksrt_get_user_identity_signals')) { } } +if (!function_exists('aksrt_current_user_is_verified')) { + /** + * Whether the current user carries a verification (认证) signal. + * + * @return bool + */ + function aksrt_current_user_is_verified(): bool { + $user_id = get_current_user_id(); + if ($user_id <= 0 || !function_exists('aksrt_get_user_identity_signals')) { + return false; + } + foreach (aksrt_get_user_identity_signals($user_id) as $signal) { + if ((string) ($signal['type'] ?? '') === 'verify') { + return true; + } + } + return false; + } +} + if (!function_exists('aksrt_render_user_identity_chips')) { /** * Render compact identity chips (verify / level / badges). @@ -537,7 +557,8 @@ if (!function_exists('aksrt_get_worn_medal_icon')) { if (!function_exists('aksrt_is_blog_comment_hot')) { /** - * "神评" for ordinary post comments when likes cross threshold. + * "神评" for ordinary post comments when likes cross the fixed threshold + * (参考主题固定 10 赞,主题不再提供该阈值配置). */ function aksrt_is_blog_comment_hot($comment): bool { $comment_id = $comment instanceof WP_Comment ? (int) $comment->comment_ID : (int) $comment; @@ -548,16 +569,6 @@ if (!function_exists('aksrt_is_blog_comment_hot')) { return true; } $threshold = 10; - if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_comment_display_settings')) { - $display = \AKSRT\Settings\Settings::get_comment_display_settings(); - if (isset($display['hot_threshold'])) { - $threshold = max(1, (int) $display['hot_threshold']); - } - } - $all = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_all() : []; - if (isset($all['comment_hot_threshold'])) { - $threshold = max(1, (int) $all['comment_hot_threshold']); - } $likes = function_exists('aksrt_get_comment_likes') ? aksrt_get_comment_likes($comment_id) : (int) get_comment_meta($comment_id, 'aksrt_comment_likes', true); if ($likes < $threshold) { return false; diff --git a/inc/helpers/aksrt-ip-geo.php b/inc/helpers/aksrt-ip-geo.php index 3d9e8dfa..7b862342 100644 --- a/inc/helpers/aksrt-ip-geo.php +++ b/inc/helpers/aksrt-ip-geo.php @@ -5,7 +5,7 @@ * Gates: * master: ip_geo_enabled * surface: ip_geo_display ∈ {comment, user_home, user_center, post} - * comments: comment_city_s (+ comment_city_type) via comments/geo.php + * comments: display + format fully owned by this extension via comments/geo.php * * Meta: * comment → aksrt_comment_addr {country,province,city} diff --git a/inc/helpers/comments/actions.php b/inc/helpers/comments/actions.php index 932b77a3..0c8e3d95 100644 --- a/inc/helpers/comments/actions.php +++ b/inc/helpers/comments/actions.php @@ -40,15 +40,14 @@ if (!function_exists('aksrt_comment_action_permissions')) : return false; }; - $edit_window = 10; + // 允许用户编辑评论:参考主题 user_edit_comment 总开关(关闭后本人亦不可编辑)。 + $user_edit = true; if (class_exists('\AKSRT\Settings\Settings')) { $display = \AKSRT\Settings\Settings::get_comment_display_settings(); - $edit_window = (int) ($display['edit_window'] ?? 10); + $user_edit = !isset($display['user_edit']) || !empty($display['user_edit']); } - $within_window = $edit_window > 0 - && (time() - strtotime((string) $comment->comment_date_gmt)) < ($edit_window * MINUTE_IN_SECONDS); - $can_edit_own = $is_owner && $within_window && $can('comment_edit'); + $can_edit_own = $is_owner && $user_edit && $can('comment_edit'); $can_edit_others = (!$is_owner) && ( ($is_post_author && $can('comment_edit_my_post')) || $can('comment_edit_other') diff --git a/inc/helpers/comments/geo.php b/inc/helpers/comments/geo.php index 2c333fc4..c4fcb8a7 100644 --- a/inc/helpers/comments/geo.php +++ b/inc/helpers/comments/geo.php @@ -3,7 +3,7 @@ * Comment city / IP geo helpers. * * Meta: aksrt_comment_addr {country,province,city} - * Gates: ip_geo_enabled + ip_geo_display has comment + comment_city_s + * Gates: ip_geo_enabled + ip_geo_display has comment(扩展&增强 / IP归属地统一控制) * * @package AKSRT */ @@ -12,27 +12,14 @@ defined('ABSPATH') || exit; if (!function_exists('aksrt_comment_city_enabled')) : function aksrt_comment_city_enabled(): bool { - if (function_exists('aksrt_ip_geo_display_enabled') && !aksrt_ip_geo_display_enabled('comment')) { - return false; - } - if (!class_exists('\AKSRT\Settings\Settings')) { - return false; - } - $s = \AKSRT\Settings\Settings::get_comment_display_settings(); - return !empty($s['city_s']); + // 评论区位置显示的开关与精度统一由「扩展&增强 / IP归属地」配置提供。 + return function_exists('aksrt_ip_geo_display_enabled') && aksrt_ip_geo_display_enabled('comment'); } endif; if (!function_exists('aksrt_comment_city_type')) : function aksrt_comment_city_type(): string { - if (!class_exists('\AKSRT\Settings\Settings')) { - return function_exists('aksrt_ip_geo_format_key') ? aksrt_ip_geo_format_key() : 'province_city'; - } - $s = \AKSRT\Settings\Settings::get_comment_display_settings(); - $type = sanitize_key((string) ($s['city_type'] ?? 'province_city')); - return in_array($type, ['province_city', 'province', 'country_province'], true) - ? $type - : 'province_city'; + return function_exists('aksrt_ip_geo_format_key') ? aksrt_ip_geo_format_key() : 'province_city'; } endif; diff --git a/src/Admin/Schema/SchemaPostList.php b/src/Admin/Schema/SchemaPostList.php index c3a60c91..d30c7a2c 100644 --- a/src/Admin/Schema/SchemaPostList.php +++ b/src/Admin/Schema/SchemaPostList.php @@ -136,7 +136,6 @@ class SchemaPostList { ['key' => 'post_default_likes_min', 'label' => '默认点赞最小值', 'type' => 'number', 'default' => 5, 'min' => 0, 'max' => 9999], ['key' => 'post_default_likes_max', 'label' => '默认点赞最大值', 'type' => 'number', 'default' => 15, 'min' => 1, 'max' => 9999], ['key' => 'post_views_s', 'label' => '浏览统计', 'type' => 'switch', 'default' => true], - ['key' => 'post_close_comments', 'label' => '关闭评论', 'type' => 'switch', 'default' => false], ]], ], ], @@ -199,53 +198,36 @@ class SchemaPostList { 'comment' => [ 'key' => 'comment', 'title' => '评论设置', - 'version' => '1.0.0', + 'version' => '2.0.0', 'option_key' => 'aksrt_settings', 'groups' => [ - ['key' => 'display', 'title' => '评论展示', 'fields' => [ - ['key' => 'comment_order', 'label' => '评论排序', 'type' => 'radio', 'default' => 'asc', 'options' => [ - ['label' => '正序', 'value' => 'asc'], - ['label' => '倒序', 'value' => 'desc'], + ['key' => 'comment', 'title' => '评论设置', 'fields' => [ + ['key' => 'close_comments', 'label' => '关闭文章评论功能', 'type' => 'switcher', 'default' => false, 'description' => '部分网站无需交互,或需备案审核,可在此关闭所有文章的评论功能。同时每一篇文章可单独关闭评论功能'], + ['key' => 'comment_box_hide', 'label' => '隐藏评论模块', 'type' => 'radio', 'default' => '', 'dependsOn' => ['key' => 'close_comments', 'value' => false], 'options' => [ + ['label' => '不隐藏', 'value' => ''], + ['label' => '登录后显示', 'value' => 'signin'], + ['label' => '所有会员显示', 'value' => 'vip'], + ['label' => '二级会员显示', 'value' => 'vip_2'], + ['label' => '认证用户显示', 'value' => 'auth'], + ], 'description' => '当用户满足条件时,文章评论功能及模块才会显示'], + ['key' => 'comment_paginate_type', 'label' => '评论列表翻页模式', 'type' => 'radio', 'default' => 'default', 'dependsOn' => ['key' => 'close_comments', 'value' => false], 'options' => [ + ['label' => 'AJAX追加列表翻页', 'value' => 'ajax_lists'], + ['label' => '数字翻页按钮', 'value' => 'default'], ]], - ['key' => 'comment_per_page', 'label' => '每页评论数', 'type' => 'number', 'default' => 20, 'min' => 5, 'max' => 100], - ['key' => 'comment_pagination_type', 'label' => '分页方式', 'type' => 'radio', 'default' => 'numbered', 'options' => [ - ['label' => '翻页', 'value' => 'numbered'], - ['label' => '加载更多', 'value' => 'load_more'], - ['label' => '无限滚动', 'value' => 'infinite'], - ]], - ['key' => 'comment_paging_ajax_ias_s', 'label' => '评论自动加载', 'type' => 'switch', 'default' => true, 'description' => '评论无限滚动时自动触发加载'], - ['key' => 'comment_paging_ajax_ias_max', 'label' => '评论最大加载页数', 'type' => 'number', 'default' => 3, 'min' => 0, 'max' => 10, 'description' => '0=不限'], - ['key' => 'comment_nested_depth', 'label' => '回复嵌套深度', 'type' => 'number', 'default' => 3, 'min' => 1, 'max' => 10], - ['key' => 'comment_avatar_size', 'label' => '头像大小', 'type' => 'number', 'default' => 48, 'min' => 24, 'max' => 96], - ]], - ['key' => 'permissions', 'title' => '评论权限', 'fields' => [ - ['key' => 'comment_close_comments', 'label' => '关闭评论', 'type' => 'switch', 'default' => false], - ['key' => 'comment_edit_window', 'label' => '作者自助编辑时限(分钟)', 'type' => 'number', 'default' => 10, 'min' => 0, 'max' => 1440], - ]], - ['key' => 'toolbar', 'title' => '评论工具栏', 'fields' => [ - ['key' => 'comment_code', 'label' => '代码插入', 'type' => 'switch', 'default' => true], - ['key' => 'comment_img', 'label' => '图片按钮', 'type' => 'switch', 'default' => true], - ['key' => 'comment_upload_img', 'label' => '评论图片上传', 'type' => 'switch', 'default' => false], - ['key' => 'comment_link', 'label' => '链接按钮', 'type' => 'switch', 'default' => false], - ]], - ['key' => 'interaction', 'title' => '互动功能', 'fields' => [ - ['key' => 'comment_hot_threshold', 'label' => '神评点赞阈值', 'type' => 'number', 'default' => 10, 'min' => 1, 'max' => 999], - ['key' => 'comment_like_s', 'label' => '评论点赞', 'type' => 'switch', 'default' => true], - ['key' => 'comment_user_url_s', 'label' => '匿名者网址', 'type' => 'switch', 'default' => false, 'description' => '用户未登录评论时,允许输入用户博客地址'], - ['key' => 'comment_city_s', 'label' => '评论城市', 'type' => 'switch', 'default' => true], - ['key' => 'comment_city_type', 'label' => '城市显示格式', 'type' => 'radio', 'default' => 'province_city', 'options' => [ - ['label' => '省份+城市', 'value' => 'province_city'], - ['label' => '仅省份', 'value' => 'province'], - ['label' => '国家+省份', 'value' => 'country_province'], - ]], - ['key' => 'comment_author_tag', 'label' => '作者标签', 'type' => 'switch', 'default' => true], - ['key' => 'comment_corderby', 'label' => '评论排序切换', 'type' => 'switch', 'default' => true, 'description' => '前台显示最新/最早/最热切换按钮'], - ]], - ['key' => 'text', 'title' => '文案配置', 'fields' => [ - ['key' => 'comment_empty_text', 'label' => '空评论提示', 'type' => 'input', 'default' => '暂无评论,来做第一个评论的人吧~'], - ['key' => 'comment_title', 'label' => '评论区标题', 'type' => 'input', 'default' => '评论'], - ['key' => 'comment_submit_text', 'label' => '提交按钮文案', 'type' => 'input', 'default' => '提交评论'], - ['key' => 'comment_text', 'label' => '评论框提示', 'type' => 'input', 'default' => '说点什么吧...'], + ['key' => 'comment_paging_ajax_ias_s', 'label' => 'AJAX翻页自动加载', 'type' => 'switcher', 'default' => true, 'dependsOn' => ['key' => 'comment_paginate_type', 'value' => 'ajax_lists'], 'description' => '页面滚动到列表尽头时,自动加载下一页'], + ['key' => 'comment_paging_ajax_ias_max', 'label' => '自动加载页数', 'type' => 'number', 'default' => 3, 'min' => 0, 'max' => 10, 'unit' => '页', 'dependsOn' => ['all' => [['key' => 'comment_paginate_type', 'value' => 'ajax_lists'], ['key' => 'comment_paging_ajax_ias_s', 'value' => true]]], 'description' => 'AJAX翻页自动加载最多加载几页(为0则不限制,直到加载全部评论)'], + ['key' => 'comment_code', 'label' => '允许插入代码', 'type' => 'switcher', 'default' => true, 'dependsOn' => ['key' => 'close_comments', 'value' => false], 'help' => '为了防止恶意评论,建议在后台-设置-讨论:开启“用户必须登录后才能发表评论”'], + ['key' => 'comment_img', 'label' => '允许插入图片', 'type' => 'switcher', 'default' => true, 'dependsOn' => ['key' => 'close_comments', 'value' => false]], + ['key' => 'comment_upload_img', 'label' => '允许上传图片', 'type' => 'switcher', 'default' => false, 'dependsOn' => ['all' => [['key' => 'close_comments', 'value' => false], ['key' => 'comment_img', 'value' => true]]]], + ['key' => 'comment_link', 'label' => '允许插入链接', 'type' => 'switcher', 'default' => false], + ['key' => 'comment_author_tag', 'label' => '显示“作者”标签', 'type' => 'switcher', 'default' => true, 'dependsOn' => ['key' => 'close_comments', 'value' => false]], + ['key' => 'user_edit_comment', 'label' => '允许用户编辑评论', 'type' => 'switcher', 'default' => true, 'dependsOn' => ['key' => 'close_comments', 'value' => false]], + ['key' => 'comment_like_s', 'label' => '评论点赞功能', 'type' => 'switcher', 'default' => true, 'dependsOn' => ['key' => 'close_comments', 'value' => false]], + ['key' => 'comment_user_url_s', 'label' => '匿名评论允许输入链接', 'type' => 'switcher', 'default' => false, 'dependsOn' => ['key' => 'close_comments', 'value' => false], 'description' => '用户未登录评论时,允许输入用户博客地址'], + ['key' => 'comment_corderby', 'label' => '评论排序功能', 'type' => 'switcher', 'default' => true, 'dependsOn' => ['all' => [['key' => 'close_comments', 'value' => false], ['key' => 'comment_like_s', 'value' => true]]], 'description' => '显示“最新、最热”排序按钮'], + ['key' => 'comment_title', 'label' => '自定义评论标题', 'type' => 'textarea', 'default' => '评论', 'rows' => 1, 'dependsOn' => ['key' => 'close_comments', 'value' => false]], + ['key' => 'comment_submit_text', 'label' => '自定义评论提交按钮文案', 'type' => 'textarea', 'default' => '提交评论', 'rows' => 1, 'dependsOn' => ['key' => 'close_comments', 'value' => false]], + ['key' => 'comment_text', 'label' => '自定义评论框占位符文案', 'type' => 'input', 'default' => '欢迎您留下宝贵的见解!', 'dependsOn' => ['key' => 'close_comments', 'value' => false]], ]], ], ], diff --git a/src/Core/CommentActions.php b/src/Core/CommentActions.php index 0eb09533..2c4cb412 100644 --- a/src/Core/CommentActions.php +++ b/src/Core/CommentActions.php @@ -163,7 +163,7 @@ class CommentActions { } /** - * Permission: can edit? (author within configured window, or moderator) + * Permission: can edit? (author with 允许用户编辑评论 on, or moderator) */ public function check_edit_permission(\WP_REST_Request $request): bool { if (!is_user_logged_in()) return false; diff --git a/src/Settings/PostDisplay.php b/src/Settings/PostDisplay.php index 9cc0c159..01a68cbc 100644 --- a/src/Settings/PostDisplay.php +++ b/src/Settings/PostDisplay.php @@ -339,12 +339,13 @@ class PostDisplay { public static function get_comment_display_settings(): array { $settings = Settings::get_all(); - $order = sanitize_key((string) ($settings['comment_order'] ?? 'desc')); + + // 评论排序由 WP 讨论设置决定(与参考主题一致:主题不再提供排序配置)。 + $order = sanitize_key((string) get_option('comment_order', 'desc')); if (!in_array($order, ['asc', 'desc'], true)) { $order = 'desc'; } - $empty_text = trim((string) ($settings['comment_empty_text'] ?? '')); $submit_text = trim((string) ($settings['comment_submit_text'] ?? '')); $box_placeholder = trim((string) ($settings['comment_text'] ?? '')); $title = trim((string) ($settings['comment_title'] ?? '')); @@ -354,11 +355,8 @@ class PostDisplay { 'pagination_mode' => self::get_comment_pagination_mode(), 'paging_ajax_ias' => !isset($settings['comment_paging_ajax_ias_s']) || !empty($settings['comment_paging_ajax_ias_s']), 'paging_ajax_ias_max'=> max(0, min(10, (int) ($settings['comment_paging_ajax_ias_max'] ?? 3))), - 'per_page' => max(5, min(100, (int) ($settings['comment_per_page'] ?? 20))), - 'nested_depth' => max(1, min(10, (int) ($settings['comment_nested_depth'] ?? 3))), 'require_login' => Settings::comment_requires_registration(), - 'avatar_size' => max(24, min(96, (int) ($settings['comment_avatar_size'] ?? 48))), - 'empty_text' => $empty_text !== '' ? $empty_text : __('暂无评论,来做第一个评论的人吧~', 'aksrt'), + 'box_hide' => sanitize_key((string) ($settings['comment_box_hide'] ?? '')), 'toolbar' => [ 'code' => !isset($settings['comment_code']) || !empty($settings['comment_code']), 'image' => !isset($settings['comment_img']) || !empty($settings['comment_img']), @@ -372,34 +370,15 @@ class PostDisplay { 'like_enabled' => !isset($settings['comment_like_s']) || !empty($settings['comment_like_s']), 'author_tag' => !isset($settings['comment_author_tag']) || !empty($settings['comment_author_tag']), 'corderby' => !isset($settings['comment_corderby']) || !empty($settings['comment_corderby']), - 'edit_window' => max(0, min(1440, (int) ($settings['comment_edit_window'] ?? 10))), + 'user_edit' => !isset($settings['user_edit_comment']) || !empty($settings['user_edit_comment']), 'submit_text' => $submit_text !== '' ? $submit_text : __('提交评论', 'aksrt'), 'box_placeholder' => $box_placeholder !== '' ? $box_placeholder : __('说点什么吧...', 'aksrt'), 'title' => $title !== '' ? $title : __('评论', 'aksrt'), - // Extended legacy-parity settings. - 'close_comments' => !empty($settings['comment_close_comments']), - 'hot_threshold' => max(1, min(999, (int) ($settings['comment_hot_threshold'] ?? 10))), + 'close_comments' => !empty($settings['close_comments']), 'user_url' => !empty($settings['comment_user_url_s']), - 'city_s' => !isset($settings['comment_city_s']) || !empty($settings['comment_city_s']), - 'city_type' => self::normalize_comment_city_type((string) ($settings['comment_city_type'] ?? 'province_city')), ]; } - private static function normalize_comment_city_type(string $type): string { - $type = sanitize_key($type); - // Map legacy legacy pro/city labels. - if ($type === 'pro') { - return 'province'; - } - if ($type === 'city') { - return 'province_city'; - } - return in_array($type, ['province_city', 'province', 'country_province'], true) - ? $type - : 'province_city'; - } - - public static function apply_list_orderby($query): void { if (is_admin() || !($query instanceof \WP_Query) || !$query->is_main_query()) { return; @@ -467,11 +446,9 @@ class PostDisplay { } public static function get_comment_pagination_mode(): string { - $mode = (string) Settings::get_value('comment_pagination_type', 'numbered'); - if ($mode === 'page') { - $mode = 'numbered'; - } - return in_array($mode, ['numbered', 'load_more', 'infinite'], true) ? $mode : 'numbered'; + // 与参考主题一致:ajax_lists = AJAX 追加列表翻页,其余为数字翻页按钮。 + $mode = (string) Settings::get_value('comment_paginate_type', 'default'); + return $mode === 'ajax_lists' ? 'ajax_lists' : 'numbered'; } private static function sanitize_custom_filter_defs($raw): array { diff --git a/tests/admin/comment-settings-reference-contract.test.cjs b/tests/admin/comment-settings-reference-contract.test.cjs new file mode 100644 index 00000000..544f29a1 --- /dev/null +++ b/tests/admin/comment-settings-reference-contract.test.cjs @@ -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[''] 必须消失 + // (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'\]/); +}); diff --git a/tools/admin-contract-report.json b/tools/admin-contract-report.json index 3530a4cc..a7f8d0f8 100644 --- a/tools/admin-contract-report.json +++ b/tools/admin-contract-report.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-09-24T04:13:34+00:00", + "generated_at": "2026-09-24T05:35:38+00:00", "errors": [], "warnings": [ "customPage tools-update section 'tools/update' not in PHP schema (ok if pure operational page)", @@ -8,9 +8,6 @@ "enum incomplete parse for 'avatar_external' (php subset of js): php=[] js=[,gravatar,weavatar,cravatar,geekzu,loli,sep,v2ex]", "enum incomplete parse for 'backup_frequency' (php subset of js): php=[daily] js=[daily,weekly,monthly]", "enum incomplete parse for 'bind_reminder' (php subset of js): php=[email] js=[email,phone,email_phone,close]", - "enum incomplete parse for 'comment_city_type' (php subset of js): php=[province_city] js=[province_city,province,country_province]", - "enum incomplete parse for 'comment_order' (php subset of js): php=[asc] js=[asc,desc]", - "enum incomplete parse for 'comment_pagination_type' (php subset of js): php=[numbered] js=[numbered,load_more,infinite]", "enum incomplete parse for 'content_audit_on_failure' (php subset of js): php=[allow] js=[allow,block]", "enum incomplete parse for 'content_audit_provider' (php subset of js): php=[baidu] js=[baidu,null]", "enum incomplete parse for 'epay_device' (php subset of js): php=[auto] js=[auto,pc,mobile]", @@ -237,7 +234,7 @@ "entry": true, "missing_chunks": [], "chunks": [ - "SchemaPage.C2bnpARq.js", + "SchemaPage.CPZNRYWC.js", "vendor-vue.BYzo-2I-.js", "FaIcon.B3OOcphx.js", "FaIconPicker.DHrC0Y72.js", @@ -252,8 +249,8 @@ "vendor-draggable.YNevSrwY.js", "PageHeader.jmNZVzHG.js", "FooterTabbarSettings.CwSsjNlJ.js", - "PostPageSettings.DZzG8fRg.js", - "CommentSettings.sUF8U6J1.js", + "PostPageSettings.DxiP1RzY.js", + "CommentSettings.C6xJZ_dU.js", "PermissionsCapabilities.BeLUij9c.js", "CmsCredits.CTDJTkG-.js", "ThemeInfoPage.CbJKzVFa.js",