diff --git a/assets/admin/src/constants/sections/extensions.js b/assets/admin/src/constants/sections/extensions.js index 9d2e2278..806eb887 100644 --- a/assets/admin/src/constants/sections/extensions.js +++ b/assets/admin/src/constants/sections/extensions.js @@ -36,15 +36,6 @@ export const extensionsSection = { canonicalDomain: 'extensions', section: 'push', }), - customPage({ - key: 'extensions-security', - name: 'ExtensionsSecurity', - label: '网站安全', - route: '/extensions/security', - component: 'ExtensionSecurity', - title: '网站安全', - desc: '扩展安全策略和第三方安全集成。', - }), customPage({ key: 'extensions-tools', name: 'ExtensionsTools', diff --git a/assets/admin/src/pages/SiteSettings.vue b/assets/admin/src/pages/SiteSettings.vue deleted file mode 100644 index bc069acd..00000000 --- a/assets/admin/src/pages/SiteSettings.vue +++ /dev/null @@ -1,176 +0,0 @@ - - - diff --git a/assets/admin/src/pages/extensions/ExtensionSecurity.vue b/assets/admin/src/pages/extensions/ExtensionSecurity.vue deleted file mode 100644 index 8885a190..00000000 --- a/assets/admin/src/pages/extensions/ExtensionSecurity.vue +++ /dev/null @@ -1,311 +0,0 @@ - - - - - diff --git a/assets/admin/src/pages/tools/ToolsUpdate.vue b/assets/admin/src/pages/tools/ToolsUpdate.vue index 6b150524..78a7629b 100644 --- a/assets/admin/src/pages/tools/ToolsUpdate.vue +++ b/assets/admin/src/pages/tools/ToolsUpdate.vue @@ -90,7 +90,7 @@ const guides = [ { key: 'meilisearch', title: 'Meilisearch', desc: '配置搜索索引与同步策略', url: '#/global/search' }, { key: 'i18n', title: '多语言翻译', desc: '检查语言切换与术语配置', url: '#/global/i18n' }, { key: 'cdn', title: '静态资源与 CDN', desc: '核对前端资源地址与缓存策略', url: '#/global/common' }, - { key: 'ip-geo', title: 'IP 归属地', desc: '验证 IP 查询服务与密钥配置', url: '#/extensions/security' }, + { key: 'ip-geo', title: 'IP 归属地', desc: '验证 IP 查询服务与密钥配置', url: '#/extensions/ip' }, { key: 'payment', title: '支付与会员', desc: '核对网关、会员与充值配置', url: '#/payment/gateway' }, { key: 'credits', title: '积分与签到', desc: '检查积分规则、签到与邀请奖励', url: '#/users/signin' }, { key: 'badge', title: '等级与徽章', desc: '维护等级、认证与徽章体系', url: '#/users/badge' }, diff --git a/assets/admin/src/pages/users/UsersSignin.vue b/assets/admin/src/pages/users/UsersSignin.vue index 219783d6..81c5cae9 100644 --- a/assets/admin/src/pages/users/UsersSignin.vue +++ b/assets/admin/src/pages/users/UsersSignin.vue @@ -229,14 +229,8 @@ async function load() { const inviteReward = creditData.invite_reward || {} const enabledScenarios = Array.isArray(captchaData.enabled_scenarios) ? captchaData.enabled_scenarios - : null - const disabledScenarios = Array.isArray(captchaData.disabled_scenarios) - ? captchaData.disabled_scenarios : [] - const sceneOn = (key) => { - if (enabledScenarios) return enabledScenarios.includes(key) - return !disabledScenarios.includes(key) - } + const sceneOn = (key) => enabledScenarios.includes(key) creditSnapshot.value = creditData authSnapshot.value = authData diff --git a/assets/admin/src/router/component-loaders/extensions.js b/assets/admin/src/router/component-loaders/extensions.js index efa2ed99..c90b9b72 100644 --- a/assets/admin/src/router/component-loaders/extensions.js +++ b/assets/admin/src/router/component-loaders/extensions.js @@ -1,5 +1,4 @@ export const extensionsPageLoaders = { ExtensionTools: () => import('@/pages/extensions/ExtensionTools.vue'), - ExtensionSecurity: () => import('@/pages/extensions/ExtensionSecurity.vue'), ExtensionAI: () => import('@/pages/extensions/ExtensionAI.vue'), } diff --git a/assets/admin/src/schema/sections/global/common.js b/assets/admin/src/schema/sections/global/common.js index 6f9e9390..c940635b 100644 --- a/assets/admin/src/schema/sections/global/common.js +++ b/assets/admin/src/schema/sections/global/common.js @@ -4,7 +4,6 @@ export const commonSchema = { icon: 'fas fa-cog', description: '管理站点常用开关、懒加载与备案信息等基础配置。', defaults: { - comment_enabled: true, lazyload_enabled: true, lazyload_animation: 'blur', lazyload_placeholder: '', @@ -18,17 +17,10 @@ export const commonSchema = { lazyload_other: true, lazyload_widget: true, icp_filing: '', + police_filing: '', footer_text: '', }, groups: [ - { - key: 'comment', - title: '评论功能', - icon: 'fas fa-comment', - fields: [ - { key: 'comment_enabled', label: '开启评论', type: 'switch', default: true, help: '全局评论开关,关闭后所有文章不再显示评论区' }, - ], - }, { key: 'performance', title: '性能优化', @@ -72,6 +64,7 @@ export const commonSchema = { icon: 'fas fa-shield-alt', fields: [ { key: 'icp_filing', label: 'ICP 备案号', type: 'input', placeholder: '例如:京ICP备12345678号', help: '显示在页脚的备案信息' }, + { key: 'police_filing', label: '公安备案号', type: 'input', placeholder: '例如:公网安备11000000000000号', help: '显示在页脚的备案信息' }, { key: 'footer_text', label: '页脚附加文字', type: 'input', placeholder: '自定义页脚文字', help: '显示在版权信息下方' }, ], }, diff --git a/assets/admin/src/schema/sections/page-display/index.js b/assets/admin/src/schema/sections/page-display/index.js index 237fc00c..1cdca884 100644 --- a/assets/admin/src/schema/sections/page-display/index.js +++ b/assets/admin/src/schema/sections/page-display/index.js @@ -824,9 +824,7 @@ export const pageDisplaySchemas = { footer_columns: 3, footer_copyright: true, footer_icp: true, - icp_number: '', footer_police: true, - police_number: '', footer_theme_custom: false, footer_theme_bg_custom: '', footer_theme_bg: '', @@ -857,9 +855,7 @@ export const pageDisplaySchemas = { { key: 'footer_columns', label: '页脚列数', type: 'number', default: 3, min: 1, max: 4 }, { key: 'footer_copyright', label: '显示版权信息', type: 'switch', default: true }, { key: 'footer_icp', label: '显示ICP备案', type: 'switch', default: true }, - { key: 'icp_number', label: 'ICP备案号', type: 'input', default: '' }, { key: 'footer_police', label: '显示公安备案', type: 'switch', default: true }, - { key: 'police_number', label: '公安备案号', type: 'input', default: '' }, ], }, { diff --git a/assets/admin/src/schema/sections/permissions/index.js b/assets/admin/src/schema/sections/permissions/index.js index cf3d7e9a..955f412b 100644 --- a/assets/admin/src/schema/sections/permissions/index.js +++ b/assets/admin/src/schema/sections/permissions/index.js @@ -20,7 +20,6 @@ export const permissionsSchemas = { 'comment', 'login', 'register', 'bind', 'bind_phone', 'lostpassword', 'change_password', 'change_email', 'verify_email', 'download', 'signin', ], - disabled_scenarios: [], tencent: {}, aliyun: {}, cloudflare: {}, @@ -75,6 +74,7 @@ export const permissionsSchemas = { { label: '邮箱验证', value: 'verify_email' }, { label: '资源下载', value: 'download' }, { label: '每日签到', value: 'signin' }, + { label: '前台投稿', value: 'front_submit' }, ], }, ], diff --git a/assets/admin/src/schema/sections/post-list/submit.js b/assets/admin/src/schema/sections/post-list/submit.js index a17d05c4..eb911895 100644 --- a/assets/admin/src/schema/sections/post-list/submit.js +++ b/assets/admin/src/schema/sections/post-list/submit.js @@ -23,7 +23,6 @@ export const submitSchema = { front_submit_draft_save: true, front_submit_leave_warning: true, front_submit_guest_enabled: false, - front_submit_captcha: false, post_article_btn_txte: '发布文章', post_article_title_strlen_limit_min: 5, post_article_title_strlen_limit_max: 30, @@ -63,7 +62,6 @@ export const submitSchema = { { key: 'post_article_cat', label: '允许投稿分类', type: 'taxonomy_select', taxonomy: 'category', multiple: true, default: [], help: '为空则允许全部分类', dependsOn: { key: 'front_submit_enabled', value: true } }, { key: 'front_submit_guest_enabled', label: '允许免登录投稿', type: 'switch', default: false, help: '开启后访客可投稿;文章归属到下方用户', dependsOn: { key: 'front_submit_enabled', value: true } }, { key: 'post_article_user', label: '免登录归属用户', type: 'user_select', default: 0, help: '免登录投稿时文章归属的用户,搜索选择', dependsOn: { key: 'front_submit_guest_enabled', value: true } }, - { key: 'front_submit_captcha', label: '提交人机验证', type: 'switch', default: false, help: '提交正式投稿时校验人机验证(需在安全扩展启用 captcha)', dependsOn: { key: 'front_submit_enabled', value: true } }, { key: 'front_submit_tags', label: '标签输入', type: 'switch', default: true, dependsOn: { key: 'front_submit_enabled', value: true } }, { key: 'post_article_topics_s', label: '专题选择', type: 'switch', default: false, help: '投稿时可选择专题分类', dependsOn: { key: 'front_submit_enabled', value: true } }, { key: 'post_article_custom_filter_s', label: '高级筛选选择', type: 'switch', default: true, help: '投稿时可选择自定义筛选维度值', dependsOn: { key: 'front_submit_enabled', value: true } }, diff --git a/assets/js/front-submit.js b/assets/js/front-submit.js index 8769eb2d..56d29b8b 100644 --- a/assets/js/front-submit.js +++ b/assets/js/front-submit.js @@ -210,6 +210,11 @@ submit: function (btn, action) { var self = this; + if (action !== 'posts_draft' && !this.requestCaptcha(function () { + self.submit(btn, action); + })) { + return; + } this.isSubmitting = true; var original = btn.innerHTML; btn.disabled = true; @@ -292,6 +297,25 @@ }); }, + requestCaptcha: function (onVerified) { + var verified = this.form.querySelector('input[name="captcha_verified"]'); + if (verified && verified.value === '1') { + return true; + } + var captcha = window.AKSRTCaptchaState && + window.AKSRTCaptchaState.scenes && + window.AKSRTCaptchaState.scenes.front_submit; + if (!captcha || typeof captcha.verify !== 'function') { + return true; + } + captcha.verify(function (passed) { + if (passed) { + onVerified(); + } + }); + return false; + }, + bindDraftDelete: function () { document.addEventListener('click', function (e) { var btn = e.target.closest('.aksrt-submit-drafts__delete'); diff --git a/footer.php b/footer.php index 84ee0e82..b455d6d9 100644 --- a/footer.php +++ b/footer.php @@ -32,9 +32,9 @@ $more_links = $has_settings ? \AKSRT\Settings\Settings::get_more_links() : [] $hot_cat_count = $has_settings ? \AKSRT\Settings\Settings::get_hot_categories_count() : 0; // 备案 / 版权(customize 为空时回退) -$filing = $has_settings ? \AKSRT\Settings\Settings::get_filing_settings() : ['icp_enabled' => true, 'icp_number' => '', 'police_enabled' => true, 'police_number' => '']; -$icp_number = !empty($filing['icp_enabled']) ? (string) ($filing['icp_number'] ?? '') : ''; -$police_number = !empty($filing['police_enabled']) ? (string) ($filing['police_number'] ?? '') : ''; +$filing = $has_settings ? \AKSRT\Settings\Settings::get_filing_settings() : ['icp_enabled' => true, 'icp_filing' => '', 'police_enabled' => true, 'police_filing' => '']; +$icp_filing = !empty($filing['icp_enabled']) ? (string) ($filing['icp_filing'] ?? '') : ''; +$police_filing = !empty($filing['police_enabled']) ? (string) ($filing['police_filing'] ?? '') : ''; $footer_text = $has_settings ? \AKSRT\Settings\Settings::footer_text() : ''; $copyright_text = $has_settings ? \AKSRT\Settings\Settings::get_copyright_text() : ''; @@ -145,11 +145,11 @@ $_has_cols = $_has_brand || $_has_links_col || $_has_mini; $_footer_conter = trim((string) $footer_customize_code); if ($_footer_conter === '') { $footer_bits = []; - if ($icp_number !== '') { - $footer_bits[] = '' . esc_html($icp_number) . ''; + if ($icp_filing !== '') { + $footer_bits[] = '' . esc_html($icp_filing) . ''; } - if ($police_number !== '') { - $footer_bits[] = '' . esc_html($police_number) . ''; + if ($police_filing !== '') { + $footer_bits[] = '' . esc_html($police_filing) . ''; } $copy = '© ' . esc_html(gmdate('Y')) . ' ' . esc_html($blog_name) . '.'; if ($copyright_text !== '') { diff --git a/inc/core-hooks/part-1.php b/inc/core-hooks/part-1.php index 2f821276..bf60c7c4 100644 --- a/inc/core-hooks/part-1.php +++ b/inc/core-hooks/part-1.php @@ -25,9 +25,6 @@ add_filter('comments_open', function ($open, $post_id) { return false; } } - if (!get_option('aksrt_comment_enabled', true)) { - return false; - } return $open; }, 10, 2); diff --git a/inc/helpers/aksrt-comments.php b/inc/helpers/aksrt-comments.php index 5365bcc7..aef17fb5 100644 --- a/inc/helpers/aksrt-comments.php +++ b/inc/helpers/aksrt-comments.php @@ -454,6 +454,19 @@ if (!function_exists('aksrt_comments_render_form')) : ? sanitize_text_field(wp_unslash((string) $_COOKIE['comment_author_email_' . COOKIEHASH])) : ''; $placeholder = (string) $ctx['box_placeholder']; + $post_id = (int) get_the_ID(); + $can_comment = function_exists('aksrt_user_can') + ? aksrt_user_can('comment_add', get_current_user_id(), $post_id) + : $is_logged_in; + + if (!$can_comment) { + if (!$is_logged_in) { + aksrt_comments_render_signarea($ctx); + } else { + echo '

' . esc_html__('当前账号没有发表评论的权限。', 'aksrt') . '

'; + } + return; + } if (function_exists('aksrt_get_comment_virtual_input_html')) { echo aksrt_get_comment_virtual_input_html($placeholder, '#respond'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped diff --git a/inc/modules/captcha.php b/inc/modules/captcha.php index 8d20add9..0daecc29 100644 --- a/inc/modules/captcha.php +++ b/inc/modules/captcha.php @@ -39,6 +39,7 @@ function aksrt_captcha_scenes(): array { 'verify_email' => __('邮箱验证', 'aksrt'), 'download' => __('资源下载', 'aksrt'), 'signin' => __('每日签到', 'aksrt'), + 'front_submit' => __('前台投稿', 'aksrt'), ]; } @@ -46,14 +47,12 @@ function aksrt_captcha_scenes(): array { * 默认配置结构。 */ function aksrt_captcha_default_config(): array { - $all_scenes = array_keys(aksrt_captcha_scenes()); + $default_scenes = array_values(array_diff(array_keys(aksrt_captcha_scenes()), ['front_submit'])); return [ 'enabled' => false, 'active_provider' => '', - // Positive list: checked scenes require captcha. Default all scenes. - 'enabled_scenarios' => $all_scenes, - // Legacy mirror kept for BC consumers / admin summaries. - 'disabled_scenarios' => [], + // Positive list: checked scenes require captcha. Front submissions stay opt-in. + 'enabled_scenarios' => $default_scenes, 'tencent' => [], 'aliyun' => [], 'cloudflare' => [], @@ -85,32 +84,20 @@ function aksrt_captcha_sanitize_scene_list($raw): array { * @return array */ function aksrt_get_captcha_config(): array { - $cfg = get_option('aksrt_captcha_config', []); - if (!is_array($cfg)) { - $cfg = []; - } + $stored = get_option('aksrt_captcha_config', []); + $cfg = array_merge(aksrt_captcha_default_config(), is_array($stored) ? $stored : []); - $all_scenes = array_keys(aksrt_captcha_scenes()); $provider = isset($cfg['active_provider']) ? sanitize_key((string) $cfg['active_provider']) : ''; if (!in_array($provider, aksrt_captcha_providers(), true)) { $provider = ''; } - if (array_key_exists('enabled_scenarios', $cfg)) { - // Explicit positive list (may be empty = no scenes). - $enabled = aksrt_captcha_sanitize_scene_list($cfg['enabled_scenarios']); - } else { - // Legacy: only disabled list stored → all minus disabled. - $disabled_legacy = aksrt_captcha_sanitize_scene_list($cfg['disabled_scenarios'] ?? []); - $enabled = array_values(array_diff($all_scenes, $disabled_legacy)); - } - $disabled = array_values(array_diff($all_scenes, $enabled)); + $enabled = aksrt_captcha_sanitize_scene_list($cfg['enabled_scenarios'] ?? []); $result = [ 'enabled' => !empty($cfg['enabled']), 'active_provider' => $provider, 'enabled_scenarios' => $enabled, - 'disabled_scenarios' => $disabled, ]; foreach (aksrt_captcha_providers() as $p) { $result[$p] = isset($cfg[$p]) && is_array($cfg[$p]) ? $cfg[$p] : []; @@ -174,11 +161,7 @@ function aksrt_is_captcha_enabled_for($scene): bool { return false; } - $enabled = isset($cfg['enabled_scenarios']) && is_array($cfg['enabled_scenarios']) - ? $cfg['enabled_scenarios'] - : array_values(array_diff(array_keys(aksrt_captcha_scenes()), (array) ($cfg['disabled_scenarios'] ?? []))); - - return in_array($scene, $enabled, true); + return in_array($scene, $cfg['enabled_scenarios'], true); } /** diff --git a/src/Admin/ExtensionController.php b/src/Admin/ExtensionController.php index 919b20a1..1b8a6ec2 100644 --- a/src/Admin/ExtensionController.php +++ b/src/Admin/ExtensionController.php @@ -36,27 +36,6 @@ class ExtensionController extends ControllerBase { 'permission_callback' => [$this, 'check_permission'], ]); - // Security settings summary - register_rest_route(self::API_NAMESPACE, '/settings/security', [ - 'methods' => 'GET', - 'callback' => [$this, 'get_security_settings'], - 'permission_callback' => [$this, 'check_permission'], - ]); - - // Security settings — save risk switches - register_rest_route(self::API_NAMESPACE, '/settings/security', [ - 'methods' => 'POST', - 'callback' => [$this, 'save_security_settings'], - 'permission_callback' => [$this, 'check_permission'], - ]); - - // Security audit log - register_rest_route(self::API_NAMESPACE, '/security/audit-log', [ - 'methods' => 'GET', - 'callback' => [$this, 'get_audit_log'], - 'permission_callback' => [$this, 'check_permission'], - ]); - // IP geo test tool register_rest_route(self::API_NAMESPACE, '/extensions/ip-test', [ 'methods' => 'POST', @@ -151,139 +130,6 @@ class ExtensionController extends ControllerBase { ]); } - /** - * GET /settings/security — security settings summary with real service status. - */ - public function get_security_settings(): \WP_REST_Response { - $services = $this->collect_service_statuses(); - $settings = \AKSRT\Settings\Settings::get_all(); - - $email_gate_enabled = true; - if (defined('AKSRT_NO_EMAIL_GATE') && AKSRT_NO_EMAIL_GATE) { - $email_gate_enabled = false; - } - - $captcha = function_exists('aksrt_get_captcha_status_summary') - ? aksrt_get_captcha_status_summary() - : ['enabled' => false, 'provider' => '', 'configured' => false, 'scenes' => []]; - $features = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_cms_features() : []; - $scenes = is_array($captcha['scenes'] ?? null) ? $captcha['scenes'] : []; - - $risk_switches = [ - 'show_unapproved_comments' => !empty($settings['show_unapproved_comments']), - 'skip_submit_moderation' => !empty($settings['skip_submit_moderation']), - 'guest_comment' => !empty($settings['guest_comment']), - ]; - - return $this->success([ - 'data' => [ - 'email_gate_enabled' => $email_gate_enabled, - 'captcha' => [ - 'enabled' => !empty($captcha['enabled']), - 'provider' => (string) ($captcha['provider'] ?? ''), - 'configured' => !empty($captcha['configured']), - 'scenes' => $scenes, - 'download_required' => !empty($scenes['download']), - 'download_active' => !empty($scenes['download']), - ], - 'content_audit' => [ - 'enabled' => !empty($services['audit']['enabled']), - 'configured' => !empty($services['audit']['configured']), - ], - 'ip_geo' => [ - 'enabled' => !empty($services['ip_geo']['enabled']), - 'configured' => !empty($services['ip_geo']['configured']), - ], - 'risk_switches' => $risk_switches, - 'services' => $services, - ], - ]); - } - - /** - * POST /settings/security — save risk switches. - */ - public function save_security_settings(\WP_REST_Request $request): \WP_REST_Response { - $params = $this->get_json_params($request); - $risk_switches = $params['risk_switches'] ?? []; - - if (!is_array($risk_switches)) { - return $this->error('无效的风险设置数据'); - } - - $allowed = [ - 'show_unapproved_comments' => 'bool', - 'skip_submit_moderation' => 'bool', - 'guest_comment' => 'bool', - ]; - - $sanitized = $this->sanitize_fields($risk_switches, $allowed); - - // Merge into main settings - $all = \AKSRT\Settings\Settings::get_all(); - foreach ($sanitized as $key => $val) { - $all[$key] = $val; - } - - update_option('aksrt_settings', $all); - - return $this->success([ - 'message' => __('风险设置已保存', 'aksrt'), - 'data' => $sanitized, - ]); - } - - /** - * GET /security/audit-log — recent security audit entries. - */ - public function get_audit_log(): \WP_REST_Response { - global $wpdb; - - $limit = 20; - $logs = []; - - // Recent user registrations - $recent_users = get_users([ - 'number' => $limit, - 'orderby' => 'registered', - 'order' => 'DESC', - 'fields' => ['ID', 'display_name', 'user_email', 'user_registered'], - ]); - - foreach ($recent_users as $user) { - $logs[] = [ - 'id' => 'reg_' . $user->ID, - 'action' => '用户注册', - 'detail' => sprintf('%s (%s) 完成注册', $user->display_name, $user->user_email), - 'time' => $user->user_registered, - 'type' => 'auth', - ]; - } - - // Content audit log - $audit_log = get_option('aksrt_content_audit_log', []); - foreach (array_slice(array_reverse($audit_log), 0, 10) as $i => $entry) { - $logs[] = [ - 'id' => 'audit_' . $i, - 'action' => '内容审核', - 'detail' => sprintf('%s — %s', $entry['content'] ?? '', ($entry['passed'] ?? false) ? '通过' : '拦截'), - 'time' => $entry['time'] ?? '', - 'type' => 'audit', - ]; - } - - // Sort by time descending - usort($logs, function ($a, $b) { - return strcmp($b['time'] ?? '', $a['time'] ?? ''); - }); - - return $this->success([ - 'data' => [ - 'logs' => array_slice($logs, 0, $limit), - ], - ]); - } - /** * POST /extensions/ip-test — test current IP provider with a given IP. * diff --git a/src/Admin/Schema/GlobalSchema.php b/src/Admin/Schema/GlobalSchema.php index cef6031c..ebc93c2b 100644 --- a/src/Admin/Schema/GlobalSchema.php +++ b/src/Admin/Schema/GlobalSchema.php @@ -20,14 +20,12 @@ class GlobalSchema { 'version' => '1.0.0', 'option_key' => 'aksrt_settings', 'groups' => [ - ['key' => 'comment', 'title' => '评论功能', 'fields' => [ - ['key' => 'comment_enabled', 'label' => '开启评论', 'type' => 'switch', 'default' => true], - ]], ['key' => 'performance', 'title' => '性能优化', 'fields' => [ ['key' => 'lazyload_enabled', 'label' => '图片懒加载', 'type' => 'switch', 'default' => true], ]], ['key' => 'filing', 'title' => '备案信息', 'fields' => [ ['key' => 'icp_filing', 'label' => 'ICP 备案号', 'type' => 'input', 'default' => ''], + ['key' => 'police_filing', 'label' => '公安备案号', 'type' => 'input', 'default' => ''], ['key' => 'footer_text', 'label' => '页脚附加文字', 'type' => 'input', 'default' => ''], ]], ], diff --git a/src/Admin/Schema/SchemaExtensions.php b/src/Admin/Schema/SchemaExtensions.php index 7f6dc87d..f267fb1c 100644 --- a/src/Admin/Schema/SchemaExtensions.php +++ b/src/Admin/Schema/SchemaExtensions.php @@ -17,7 +17,6 @@ class SchemaExtensions { 'ip' => SchemaExtensionsIP::build(), 'audit' => SchemaExtensionsAudit::build(), 'push' => SchemaExtensionsPush::build(), - 'security' => SchemaExtensionsSecurity::build(), ], ]; } diff --git a/src/Admin/Schema/SchemaExtensionsSecurity.php b/src/Admin/Schema/SchemaExtensionsSecurity.php deleted file mode 100644 index 2a9a68f4..00000000 --- a/src/Admin/Schema/SchemaExtensionsSecurity.php +++ /dev/null @@ -1,88 +0,0 @@ - 'security', - 'title' => '网站安全', - 'version' => '1.0.0', - 'option_key' => 'aksrt_settings', - 'groups' => [ - ['key' => 'basic', 'title' => '基础安全', 'fields' => [ - ['key' => 'hide_admin_bar', 'label' => '前台关闭顶部 admin_bar', 'type' => 'switch', 'default' => true], - ['key' => 'remove_emoji', 'label' => '移除Emoji脚本', 'type' => 'switch', 'default' => true], - ['key' => 'remove_open_sans', 'label' => '移除Open Sans字体', 'type' => 'switch', 'default' => true], - ['key' => 'disabled_pingback', 'label' => '禁用Pingback', 'type' => 'switch', 'default' => true], - ['key' => 'disabled_xmlrpc', 'label' => '禁用XML-RPC', 'type' => 'switch', 'default' => true], - ['key' => 'close_attachment_page', 'label' => '关闭附件页面', 'type' => 'switch', 'default' => true], - ['key' => 'user_disable_admin', 'label' => '非管理员禁止进入后台', 'type' => 'switch', 'default' => true], - ]], - ['key' => 'upload', 'title' => '上传设置', 'fields' => [ - ['key' => 'split_upload_s', 'label' => '分片上传', 'type' => 'switch', 'default' => true], - ['key' => 'split_minimum_size', 'label' => '最小分片大小(MB)', 'type' => 'number', 'default' => 20, 'min' => 4, 'max' => 100, 'step' => 2], - ['key' => 'newfilename', 'label' => '上传文件自动重命名', 'type' => 'switch', 'default' => false], - ['key' => 'newfilename_type', 'label' => '重命名格式', 'type' => 'radio', 'default' => 'time', 'options' => [ - ['label' => '随机字符串', 'value' => 'random'], - ['label' => '时间+原文件名', 'value' => 'time'], - ]], - ['key' => 'disabled_large_thumbnail', 'label' => '禁用大缩略图', 'type' => 'switch', 'default' => true], - ]], - ['key' => 'admin', 'title' => '后台设置', 'fields' => [ - ['key' => 'remove_dashboard_widgets', 'label' => 'WP 后台加速:移除站点健康/活动/禁止浏览器&PHP版本检测', 'type' => 'switch', 'default' => true], - ['key' => 'display_wp_update', 'label' => '禁止 WP 检测更新', 'type' => 'switch', 'default' => true], - ['key' => 'close_gutenberg', 'label' => '关闭古腾堡编辑器', 'type' => 'switch', 'default' => false, 'help' => '禁用后编辑器增强全部失效'], - ['key' => 'disabled_autoembed', 'label' => '禁用自动嵌入', 'type' => 'switch', 'default' => true], - ['key' => 'mce_float_toolbar', 'label' => '浮动工具栏', 'type' => 'checkbox', 'default' => ['pc_s', 'm_s'], 'sanitize_type' => 'array', 'options' => [ - ['label' => 'PC', 'value' => 'pc_s'], - ['label' => '移动端', 'value' => 'm_s'], - ]], - ['key' => 'admin_user_del_fields', 'label' => '关闭后台用户编辑多余选项', 'type' => 'switch', 'default' => true], - ['key' => 'admin_frontend_set', 'label' => '前台设置入口', 'type' => 'switch', 'default' => true], - ]], - ['key' => 'format', 'title' => '格式设置', 'fields' => [ - ['key' => 'time_ago_s', 'label' => '时间格式', 'type' => 'switch', 'default' => true], - ['key' => 'time_format', 'label' => '时间显示格式', 'type' => 'input', 'default' => 'n月j日 H:i'], - ['key' => 'remove_more_wp_head', 'label' => '移除WP head多余代码', 'type' => 'switch', 'default' => true], - ]], - ['key' => 'captcha-note', 'title' => '人机验证', 'fields' => [ - ['key' => 'captcha_redirect_hint', 'label' => '配置入口', 'type' => 'notice', 'alertType' => 'info', 'alertContent' => '人机验证(腾讯云 / 阿里云 / Cloudflare / 极验)请到「功能&权限 → 人机验证」统一配置;本页不再维护验证码字段。'], - ]], - ['key' => 'rate-limit', 'title' => '频率限制', 'fields' => [ - ['key' => 'brush_limit_post_enabled', 'label' => '文章发布限制', 'type' => 'switch', 'default' => false], - ['key' => 'brush_limit_post_minutes_10', 'label' => '文章 10 分钟限制', 'type' => 'number', 'default' => 20, 'min' => 1, 'max' => 200], - ['key' => 'brush_limit_post_day_1', 'label' => '文章每日限制', 'type' => 'number', 'default' => 50, 'min' => 1, 'max' => 2000], - ['key' => 'brush_limit_comment_enabled', 'label' => '评论频率限制', 'type' => 'switch', 'default' => false], - ['key' => 'brush_limit_comment_minutes_10', 'label' => '评论 10 分钟限制', 'type' => 'number', 'default' => 20, 'min' => 1, 'max' => 200], - ['key' => 'brush_limit_comment_day_1', 'label' => '评论每日限制', 'type' => 'number', 'default' => 100, 'min' => 1, 'max' => 2000], - ['key' => 'brush_limit_upload_enabled', 'label' => '上传频率限制', 'type' => 'switch', 'default' => false], - ['key' => 'brush_limit_upload_minutes_10', 'label' => '上传 10 分钟限制', 'type' => 'number', 'default' => 50, 'min' => 1, 'max' => 200], - ['key' => 'brush_limit_upload_day_1', 'label' => '上传每日限制', 'type' => 'number', 'default' => 200, 'min' => 1, 'max' => 2000], - ['key' => 'brush_limit_register_enabled', 'label' => '注册频率限制', 'type' => 'switch', 'default' => false], - ['key' => 'brush_limit_register_minutes_10', 'label' => '注册 10 分钟限制', 'type' => 'number', 'default' => 20, 'min' => 1, 'max' => 200], - ['key' => 'brush_limit_register_day_1', 'label' => '注册每日限制', 'type' => 'number', 'default' => 100, 'min' => 1, 'max' => 2000], - ['key' => 'brush_limit_order_enabled', 'label' => '订单频率限制', 'type' => 'switch', 'default' => false], - ['key' => 'brush_limit_order_minutes_10', 'label' => '订单 10 分钟限制', 'type' => 'number', 'default' => 30, 'min' => 1, 'max' => 200], - ['key' => 'brush_limit_order_day_1', 'label' => '订单每日限制', 'type' => 'number', 'default' => 100, 'min' => 1, 'max' => 2000], - ['key' => 'error_frequency_limit', 'label' => '错误频率限制', 'type' => 'switch', 'default' => true], - ]], - ['key' => 'content-audit', 'title' => '内容审核', 'fields' => [ - ['key' => 'audit_comment', 'label' => '审核评论', 'type' => 'switch', 'default' => false], - ['key' => 'audit_new_post', 'label' => '审核新文章', 'type' => 'switch', 'default' => false], - ['key' => 'audit_upload_img', 'label' => '审核上传图片', 'type' => 'switch', 'default' => false], - ['key' => 'audit_user_desc', 'label' => '审核用户简介', 'type' => 'switch', 'default' => false], - ['key' => 'audit_msg_private', 'label' => '审核私信', 'type' => 'switch', 'default' => false], - ['key' => 'audit_be_like_text', 'label' => '文本允许疑似合规', 'type' => 'switch', 'default' => false], - ['key' => 'audit_be_like_img', 'label' => '图片允许疑似合规', 'type' => 'switch', 'default' => false], - ]], - ], - ]; - } -} diff --git a/src/Admin/Schema/SchemaPageDisplay.php b/src/Admin/Schema/SchemaPageDisplay.php index 8c38b776..b321f17a 100644 --- a/src/Admin/Schema/SchemaPageDisplay.php +++ b/src/Admin/Schema/SchemaPageDisplay.php @@ -452,9 +452,7 @@ class SchemaPageDisplay { ['key' => 'footer_columns', 'label' => '页脚列数', 'type' => 'number', 'default' => 3, 'min' => 1, 'max' => 4], ['key' => 'footer_copyright', 'label' => '显示版权信息', 'type' => 'switch', 'default' => true], ['key' => 'footer_icp', 'label' => '显示ICP备案', 'type' => 'switch', 'default' => true], - ['key' => 'icp_number', 'label' => 'ICP备案号', 'type' => 'input', 'default' => '', 'help' => '例如:ICP 备 xxxxxxxx 号'], ['key' => 'footer_police', 'label' => '显示公安备案', 'type' => 'switch', 'default' => true], - ['key' => 'police_number', 'label' => '公安备案号', 'type' => 'input', 'default' => '', 'help' => '例如:公网安备 xxxxxx 号'], ]], ['key' => 'color', 'title' => '页脚颜色', 'fields' => [ ['key' => 'footer_theme_custom', 'label' => '自定义页脚颜色', 'type' => 'switch', 'default' => false], diff --git a/src/Admin/Schema/SchemaPermissions.php b/src/Admin/Schema/SchemaPermissions.php index c8b929b0..863a5368 100644 --- a/src/Admin/Schema/SchemaPermissions.php +++ b/src/Admin/Schema/SchemaPermissions.php @@ -44,6 +44,7 @@ class SchemaPermissions { ['label' => '邮箱验证', 'value' => 'verify_email'], ['label' => '资源下载', 'value' => 'download'], ['label' => '每日签到', 'value' => 'signin'], + ['label' => '前台投稿', 'value' => 'front_submit'], ]], ]], ['key' => 'providers', 'title' => '服务商配置', 'fields' => [ diff --git a/src/Admin/Schema/SchemaPostList.php b/src/Admin/Schema/SchemaPostList.php index 2c38ee72..0be92aa9 100644 --- a/src/Admin/Schema/SchemaPostList.php +++ b/src/Admin/Schema/SchemaPostList.php @@ -354,7 +354,6 @@ class SchemaPostList { ['key' => 'post_article_cat', 'label' => '允许投稿分类', 'type' => 'taxonomy_select', 'taxonomy' => 'category', 'multiple' => true, 'default' => [], 'help' => '为空则允许全部分类'], ['key' => 'front_submit_guest_enabled', 'label' => '允许免登录投稿', 'type' => 'switch', 'default' => false, 'help' => '开启后访客可投稿;文章归属到下方用户'], ['key' => 'post_article_user', 'label' => '免登录归属用户', 'type' => 'user_select', 'default' => 0, 'help' => '免登录投稿时文章归属的用户,搜索选择'], - ['key' => 'front_submit_captcha', 'label' => '提交人机验证', 'type' => 'switch', 'default' => false, 'help' => '提交正式投稿时校验人机验证'], ['key' => 'front_submit_tags', 'label' => '标签输入', 'type' => 'switch', 'default' => true], ['key' => 'post_article_topics_s', 'label' => '专题选择', 'type' => 'switch', 'default' => false, 'help' => '投稿时可选择专题分类'], ['key' => 'post_article_custom_filter_s', 'label' => '高级筛选选择', 'type' => 'switch', 'default' => true, 'help' => '投稿时可选择自定义筛选维度值'], diff --git a/src/Admin/SchemaProvider.php b/src/Admin/SchemaProvider.php index 4bda98ed..75105dcf 100644 --- a/src/Admin/SchemaProvider.php +++ b/src/Admin/SchemaProvider.php @@ -306,10 +306,10 @@ class SchemaProvider { } } - // Captcha: always surface normalized enabled_scenarios (legacy disabled list inverted). - if ($option_key === 'aksrt_captcha_config' && function_exists('aksrt_get_captcha_config')) { - $normalized = aksrt_get_captcha_config(); - foreach (['enabled', 'active_provider', 'enabled_scenarios', 'disabled_scenarios', 'tencent', 'aliyun', 'cloudflare', 'geetest', 'mode'] as $key) { + // Captcha: always surface the normalized positive scene list. + if ($option_key === 'aksrt_captcha_config' && function_exists('aksrt_get_captcha_config')) { + $normalized = aksrt_get_captcha_config(); + foreach (['enabled', 'active_provider', 'enabled_scenarios', 'tencent', 'aliyun', 'cloudflare', 'geetest', 'mode'] as $key) { if (array_key_exists($key, $normalized)) { $data[$key] = $normalized[$key]; } @@ -340,23 +340,12 @@ class SchemaProvider { unset($stored['pay_rebate_withdraw_text_details'], $stored['pay_balance_withdraw_lowest_money']); } - // Captcha: keep enabled_scenarios / disabled_scenarios mirrors in sync. - if ($option_key === 'aksrt_captcha_config' && function_exists('aksrt_captcha_scenes')) { - $all = array_keys(aksrt_captcha_scenes()); - if (array_key_exists('enabled_scenarios', $stored)) { - $enabled = function_exists('aksrt_captcha_sanitize_scene_list') - ? aksrt_captcha_sanitize_scene_list($stored['enabled_scenarios']) - : (array) $stored['enabled_scenarios']; - $stored['enabled_scenarios'] = $enabled; - $stored['disabled_scenarios'] = array_values(array_diff($all, $enabled)); - } elseif (array_key_exists('disabled_scenarios', $stored)) { - $disabled = function_exists('aksrt_captcha_sanitize_scene_list') - ? aksrt_captcha_sanitize_scene_list($stored['disabled_scenarios']) - : (array) $stored['disabled_scenarios']; - $stored['disabled_scenarios'] = $disabled; - $stored['enabled_scenarios'] = array_values(array_diff($all, $disabled)); - } - } + // Captcha stores a single positive scene list. + if ($option_key === 'aksrt_captcha_config' && function_exists('aksrt_captcha_scenes')) { + $stored['enabled_scenarios'] = function_exists('aksrt_captcha_sanitize_scene_list') + ? aksrt_captcha_sanitize_scene_list($stored['enabled_scenarios'] ?? []) + : (array) ($stored['enabled_scenarios'] ?? []); + } $updated = update_option($option_key, $stored); \AKSRT\Settings\Settings::flush_settings_cache(); diff --git a/src/Core/FrontSubmit.php b/src/Core/FrontSubmit.php index bfabfe48..cec7ffdd 100644 --- a/src/Core/FrontSubmit.php +++ b/src/Core/FrontSubmit.php @@ -295,7 +295,7 @@ class FrontSubmit { public function ajax_submit_post(): void { $this->verify_nonce(); - $this->maybe_verify_captcha(); + $this->verify_captcha(); $data = wp_unslash($_POST); $result = $this->persist(is_array($data) ? $data : [], 'posts_save'); @@ -385,21 +385,15 @@ class FrontSubmit { } } - private function maybe_verify_captcha(): void { - $settings = $this->settings(); - if (empty($settings['captcha'])) { - return; - } + private function verify_captcha(): void { if (!function_exists('aksrt_require_captcha')) { return; } - $payload = []; - if (isset($_POST['captcha']) && is_array($_POST['captcha'])) { - $payload = wp_unslash($_POST['captcha']); - } - $verify = aksrt_require_captcha('submit', is_array($payload) ? $payload : []); - if (is_wp_error($verify)) { - wp_send_json_error(['message' => $verify->get_error_message()]); + $verify = aksrt_require_captcha('front_submit', $_POST); + if ($verify !== true) { + wp_send_json_error([ + 'message' => is_string($verify) ? $verify : __('人机验证失败,请重试', 'aksrt'), + ], 400); } } diff --git a/src/Settings/AuthReader.php b/src/Settings/AuthReader.php index 1c5376f4..9546f73f 100644 --- a/src/Settings/AuthReader.php +++ b/src/Settings/AuthReader.php @@ -9,18 +9,8 @@ defined('ABSPATH') || exit; trait AuthReader { - /** 评论是否启用 */ - public static function comment_enabled(): bool { - $s = self::get_all(); - return !isset($s['comment_enabled']) || !empty($s['comment_enabled']); - } - /** 是否要求注册用户才能评论 */ public static function comment_requires_registration(): bool { - if (!self::comment_enabled()) { - return true; - } - $user_id = get_current_user_id(); return !class_exists(Capabilities::class) || !Capabilities::user_can('comment_add', $user_id); } diff --git a/src/Settings/Capabilities.php b/src/Settings/Capabilities.php index 3cb776e1..e73e2cc3 100644 --- a/src/Settings/Capabilities.php +++ b/src/Settings/Capabilities.php @@ -153,48 +153,6 @@ class Capabilities { return false; } - /** - * 获取"网站安全"设置(人机验证见 aksrt_get_captcha_status_summary)。 - */ - public static function get_security_settings(): array { - $s = Settings::get_all(); - - $captcha = function_exists('aksrt_get_captcha_status_summary') - ? aksrt_get_captcha_status_summary() - : ['enabled' => false, 'provider' => '', 'configured' => false, 'scenes' => []]; - - return [ - 'captcha' => $captcha, - 'brush_limit_post' => [ - 'enabled' => !empty($s['brush_limit_post_enabled']), - 'minutes_10' => (int) ($s['brush_limit_post_minutes_10'] ?? 20), - 'day_1' => (int) ($s['brush_limit_post_day_1'] ?? 50), - ], - 'brush_limit_comment' => [ - 'enabled' => !empty($s['brush_limit_comment_enabled']), - 'minutes_10' => (int) ($s['brush_limit_comment_minutes_10'] ?? 20), - 'day_1' => (int) ($s['brush_limit_comment_day_1'] ?? 100), - ], - 'brush_limit_upload' => [ - 'enabled' => !empty($s['brush_limit_upload_enabled']), - 'minutes_10' => (int) ($s['brush_limit_upload_minutes_10'] ?? 50), - 'day_1' => (int) ($s['brush_limit_upload_day_1'] ?? 200), - ], - 'brush_limit_register' => [ - 'enabled' => !empty($s['brush_limit_register_enabled']), - 'minutes_10' => (int) ($s['brush_limit_register_minutes_10'] ?? 20), - 'day_1' => (int) ($s['brush_limit_register_day_1'] ?? 100), - ], - 'brush_limit_order' => [ - 'enabled' => !empty($s['brush_limit_order_enabled']), - 'minutes_10' => (int) ($s['brush_limit_order_minutes_10'] ?? 30), - 'day_1' => (int) ($s['brush_limit_order_day_1'] ?? 100), - ], - 'error_frequency_limit' => !empty($s['error_frequency_limit'] ?? true), - ]; - } - - /** * 获取"系统工具"设置 */ diff --git a/src/Settings/DisplayPageGroups.php b/src/Settings/DisplayPageGroups.php index bac7640b..e3b03867 100644 --- a/src/Settings/DisplayPageGroups.php +++ b/src/Settings/DisplayPageGroups.php @@ -137,7 +137,6 @@ trait DisplayPageGroups { 'header_newposts' => self::get_header_newposts_config(), 'header_theme' => self::get_header_theme_config(), 'friend_links' => self::get_friend_links(), - 'comment_enabled' => self::comment_enabled(), 'cms_features' => self::get_cms_features(), 'page_display' => self::get_page_display_settings(), 'footer_theme' => self::get_footer_theme_config(), diff --git a/src/Settings/DomainGroups.php b/src/Settings/DomainGroups.php index d47305c9..68bfa29f 100644 --- a/src/Settings/DomainGroups.php +++ b/src/Settings/DomainGroups.php @@ -158,13 +158,6 @@ trait DomainGroups { return Capabilities::user_can($cap, $user_id, $context); } - /** - * 获取"网站安全"设置 - */ - public static function get_security_settings(): array { - return Capabilities::get_security_settings(); - } - /** * 获取"系统工具"设置 */ diff --git a/src/Settings/FacadeBulk.php b/src/Settings/FacadeBulk.php index 214bee42..bfae02a8 100644 --- a/src/Settings/FacadeBulk.php +++ b/src/Settings/FacadeBulk.php @@ -362,21 +362,20 @@ trait FacadeBulk { /** - * 获取备案配置(统一 page-display footer schema 和全局设置) - * @return array {icp_enabled, icp_number, police_enabled, police_number} + * 获取备案配置。 + * @return array {icp_enabled, icp_filing, police_enabled, police_filing} */ public static function get_filing_settings(): array { $s = self::get_all(); $icp_enabled = !isset($s['footer_icp']) || !empty($s['footer_icp']); $police_enabled = !isset($s['footer_police']) || !empty($s['footer_police']); - // 优先读 footer schema 的 icp_number,回退到全局 icp_filing - $icp_number = trim((string) ($s['icp_number'] ?? $s['icp_filing'] ?? '')); - $police_number = trim((string) ($s['police_number'] ?? '')); + $icp_filing = trim((string) ($s['icp_filing'] ?? '')); + $police_filing = trim((string) ($s['police_filing'] ?? '')); return [ 'icp_enabled' => $icp_enabled, - 'icp_number' => $icp_number, + 'icp_filing' => $icp_filing, 'police_enabled' => $police_enabled, - 'police_number' => $police_number, + 'police_filing' => $police_filing, ]; } @@ -398,7 +397,7 @@ trait FacadeBulk { /** 获取公安备案号 */ public static function police_filing(): string { - return trim((string) self::get_value('police_number', '')); + return trim((string) self::get_value('police_filing', '')); } diff --git a/src/Settings/HomeCms.php b/src/Settings/HomeCms.php index 2e18ae6c..103fc616 100644 --- a/src/Settings/HomeCms.php +++ b/src/Settings/HomeCms.php @@ -23,8 +23,7 @@ class HomeCms { $s = Settings::get_all(); $bridge_keys = [ - 'footer_columns', 'footer_copyright', 'footer_icp', 'icp_number', - 'footer_police', 'police_number', + 'footer_columns', 'footer_copyright', 'footer_icp', 'footer_police', 'footer_theme_custom', 'footer_theme_bg_custom', 'footer_theme_bg', 'footer_theme_color_custom', 'footer_contact_wechat_img', 'footer_contact_qq', 'footer_contact_weibo', 'footer_contact_email', ]; diff --git a/src/Settings/PostDisplay.php b/src/Settings/PostDisplay.php index f1056a11..64d378cb 100644 --- a/src/Settings/PostDisplay.php +++ b/src/Settings/PostDisplay.php @@ -429,7 +429,6 @@ class PostDisplay { 'editor_mode' => $editor_mode, 'draft_save' => !isset($settings['front_submit_draft_save']) || !empty($settings['front_submit_draft_save']), 'leave_warning' => !isset($settings['front_submit_leave_warning']) || !empty($settings['front_submit_leave_warning']), - 'captcha' => !empty($settings['front_submit_captcha']) || !empty($settings['verification_newposts_s']), 'pay_free_s' => !isset($settings['post_article_pay_free_s']) || !empty($settings['post_article_pay_free_s']), 'pay_price_min' => max(0, (float) ($settings['post_article_pay_price_min'] ?? 0)), 'pay_price_max' => max(0, (float) ($settings['post_article_pay_price_max'] ?? 100)), diff --git a/templates/parts/submit/sidebar-submit.php b/templates/parts/submit/sidebar-submit.php index b22539df..5b7e7c9f 100644 --- a/templates/parts/submit/sidebar-submit.php +++ b/templates/parts/submit/sidebar-submit.php @@ -32,9 +32,9 @@ if ($edit_post && in_array($status, ['publish', 'pending'], true)) {

- +
- +