From 3dbd196e06688d84c86ab281af9b1345069a82ec Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Aug 2026 18:31:49 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../schema/sections/users/notifications.js | 2 +- assets/css/frontend/header-userbox.css | 19 +++++++++++++++ inc/helpers/aksrt-user-center.php | 8 +++++-- inc/helpers/header/aksrt-header-navbar.php | 21 +++++++++++++--- inc/helpers/header/aksrt-header-render.php | 6 ++++- src/Admin/Schema/SchemaUsers.php | 17 ++++++------- src/Settings/Integration.php | 17 +++++++------ templates/parts/user/author-hero.php | 10 +++++--- ...notification-preferences-contract.test.cjs | 24 +++++++++++++++++++ 9 files changed, 99 insertions(+), 25 deletions(-) diff --git a/assets/admin/src/schema/sections/users/notifications.js b/assets/admin/src/schema/sections/users/notifications.js index ca5c4d60..c450068d 100644 --- a/assets/admin/src/schema/sections/users/notifications.js +++ b/assets/admin/src/schema/sections/users/notifications.js @@ -22,7 +22,7 @@ export const notificationsSchema = { fields: [ { key: 'message_s', label: '站内通知总开关', type: 'switch', default: true }, { key: 'msg_center_rewrite_slug', label: '消息中心 URL 别名', type: 'input', default: 'message' }, - { key: 'message_icon_show', label: '通知图标位置', type: 'checkbox', default: ['nav_menu'], options: [{ label: '导航菜单', value: 'nav_menu' }, { label: '用户头像', value: 'avatar' }, { label: '移动端底部', value: 'mobile_bar' }] }, + { key: 'message_icon_show', label: '通知图标位置', type: 'checkbox', default: ['nav_menu'], options: [{ label: '导航菜单', value: 'nav_menu' }, { label: '头像下拉面板', value: 'avatar_dropdown' }, { label: '用户中心顶部资料卡', value: 'user_center_header' }, { label: '公开主页顶部资料卡', value: 'user_home_header' }] }, { key: 'message_paginate_type', label: '列表翻页模式', type: 'radio', default: 'ajax_lists', options: [{ label: 'AJAX 追加加载', value: 'ajax_lists' }, { label: '数字翻页按钮', value: 'default' }] }, { key: 'message_user_set', label: '允许用户设置推送', type: 'switch', default: true, help: '允许用户在前台自行设置通知推送偏好' }, ], diff --git a/assets/css/frontend/header-userbox.css b/assets/css/frontend/header-userbox.css index 7ed98344..420b1bae 100644 --- a/assets/css/frontend/header-userbox.css +++ b/assets/css/frontend/header-userbox.css @@ -242,6 +242,25 @@ line-height: 1; } +.aksrt-nav-notification .aksrt-notification-badge { + position: absolute; + top: 2px; + right: 2px; + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 16px; + height: 16px; + padding: 0 4px; + border: 2px solid var(--surface-1); + border-radius: 999px; + background: #e74c3c; + color: #fff; + font-size: 9px; + font-weight: 700; + line-height: 1; +} + .aksrt-header-wallet { display: flex; align-items: center; diff --git a/inc/helpers/aksrt-user-center.php b/inc/helpers/aksrt-user-center.php index 30773a6b..914c8b97 100644 --- a/inc/helpers/aksrt-user-center.php +++ b/inc/helpers/aksrt-user-center.php @@ -463,7 +463,11 @@ if (!function_exists('aksrt_get_user_center_render_context')) { $user_background_url = function_exists('aksrt_get_user_cover_url') ? aksrt_get_user_cover_url($user_id) : ''; $allow_avatar_upload = function_exists('aksrt_is_avatar_upload_enabled') && aksrt_is_avatar_upload_enabled(); $allow_bg_upload = function_exists('aksrt_is_user_cover_upload_enabled') && aksrt_is_user_cover_upload_enabled(); - $messages_enabled = !class_exists('\AKSRT\Settings\Settings') || \AKSRT\Settings\Settings::message_enabled(); + $notification_settings = class_exists('\AKSRT\Settings\Settings') + ? \AKSRT\Settings\Settings::notification_settings() + : ['enabled' => false, 'icon_show' => []]; + $show_header_notification = !empty($notification_settings['enabled']) + && in_array('user_center_header', (array) ($notification_settings['icon_show'] ?? []), true); $follower_count = class_exists('\AKSRT\User\Follow') ? \AKSRT\User\Follow::get_instance()->get_follower_count($user_id) : 0; @@ -529,7 +533,7 @@ if (!function_exists('aksrt_get_user_center_render_context')) { 'allow_bg_upload' => $allow_bg_upload, 'show_avatar_edit' => $allow_avatar_upload, 'notification_unread_count' => function_exists('aksrt_get_user_unread_notification_count') ? aksrt_get_user_unread_notification_count($user_id) : 0, - 'messages_url' => $messages_enabled && function_exists('aksrt_get_messages_page_url') ? aksrt_get_messages_page_url() : '', + 'messages_url' => $show_header_notification && function_exists('aksrt_get_messages_page_url') ? aksrt_get_messages_page_url() : '', 'per_page' => 10, 'posts_page' => max(1, isset($_GET['posts_page']) ? (int) $_GET['posts_page'] : 1), 'post_status_filter' => $post_status_filter, diff --git a/inc/helpers/header/aksrt-header-navbar.php b/inc/helpers/header/aksrt-header-navbar.php index 7b49e386..280b29b2 100644 --- a/inc/helpers/header/aksrt-header-navbar.php +++ b/inc/helpers/header/aksrt-header-navbar.php @@ -173,9 +173,10 @@ if (!function_exists('aksrt_header_user_box_html')) : $badges = function_exists('aksrt_header_user_badges_row') ? aksrt_header_user_badges_row($user_id) : ''; $unread = (int) ($ctx['unread_count'] ?? 0); $msg_url = (string) ($ctx['messages_url'] ?? ''); + $positions = (array) ($ctx['message_icon_positions'] ?? []); $msg_icon = ''; - if ($msg_url !== '') { + if ($msg_url !== '' && in_array('avatar_dropdown', $positions, true)) { $msg_icon = ''; $msg_icon .= ''; if ($unread > 0) { @@ -304,7 +305,21 @@ if (!function_exists('aksrt_menu_button')) : $utility_buttons .= aksrt_get_translate_language_btn('aksrt-navbar-language'); } - // User + search. + // Notifications, user and search. + $notification_but = ''; + $messages_url = (string) ($ctx['messages_url'] ?? ''); + $positions = (array) ($ctx['message_icon_positions'] ?? []); + if ($user_id > 0 && $messages_url !== '' && in_array('nav_menu', $positions, true)) { + $unread = (int) ($ctx['unread_count'] ?? 0); + $notification_but = '
  • ' + . ''; + if ($unread > 0) { + $notification_but .= '' . esc_html((string) min(99, $unread)) . ''; + } + $notification_but .= '
  • '; + } + $sign_but = ''; $user_sub = '
    ' . aksrt_header_user_box_html($ctx) . '
    '; if ('2' === $layout) { @@ -333,7 +348,7 @@ if (!function_exists('aksrt_menu_button')) : $account = ''; + . $notification_but . $sign_but . $search_but . ''; $button = ''; diff --git a/inc/helpers/header/aksrt-header-render.php b/inc/helpers/header/aksrt-header-render.php index 17129cb0..321b337c 100644 --- a/inc/helpers/header/aksrt-header-render.php +++ b/inc/helpers/header/aksrt-header-render.php @@ -68,6 +68,9 @@ if (!function_exists('aksrt_get_header_nav_context')) : $current_user = wp_get_current_user(); $user_id = (int) $current_user->ID; $user_desc = $user_id > 0 && function_exists('aksrt_get_user_description') ? aksrt_get_user_description($user_id) : ''; + $notification_settings = class_exists('\AKSRT\Settings\Settings') + ? \AKSRT\Settings\Settings::notification_settings() + : ['enabled' => false, 'icon_show' => []]; $ctx = [ 'settings' => $settings, @@ -88,7 +91,8 @@ if (!function_exists('aksrt_get_header_nav_context')) : 'unread_count' => ($user_id > 0 && function_exists('aksrt_get_user_unread_notification_count')) ? (int) aksrt_get_user_unread_notification_count($user_id) : 0, - 'messages_url' => function_exists('aksrt_get_messages_page_url') ? aksrt_get_messages_page_url() : '', + 'message_icon_positions' => (array) ($notification_settings['icon_show'] ?? []), + 'messages_url' => !empty($notification_settings['enabled']) && function_exists('aksrt_get_messages_page_url') ? aksrt_get_messages_page_url() : '', 'orders_url' => function_exists('aksrt_get_user_center_tab_url') ? aksrt_get_user_center_tab_url('orders') : '', 'publish_url' => function_exists('aksrt_get_new_post_url') ? aksrt_get_new_post_url() : admin_url('post-new.php'), 'theme_settings_url' => function_exists('aksrt_get_admin_settings_url') diff --git a/src/Admin/Schema/SchemaUsers.php b/src/Admin/Schema/SchemaUsers.php index f9dae3ec..bd6ef940 100644 --- a/src/Admin/Schema/SchemaUsers.php +++ b/src/Admin/Schema/SchemaUsers.php @@ -227,14 +227,15 @@ class SchemaUsers { 'version' => '1.0.0', 'option_key' => 'aksrt_settings', 'groups' => [ - ['key' => 'basic', 'title' => '基础设置', 'fields' => [ - ['key' => 'message_s', 'label' => '站内通知总开关', 'type' => 'switch', 'default' => true], - ['key' => 'msg_center_rewrite_slug', 'label' => '消息中心 URL 别名', 'type' => 'input', 'default' => 'message'], - ['key' => 'message_icon_show', 'label' => '通知图标位置', 'type' => 'checkbox', 'default' => ['nav_menu'], 'options' => [ - ['label' => '导航菜单', 'value' => 'nav_menu'], - ['label' => '用户头像', 'value' => 'avatar'], - ['label' => '移动端底部', 'value' => 'mobile_bar'], - ]], + ['key' => 'basic', 'title' => '基础设置', 'fields' => [ + ['key' => 'message_s', 'label' => '站内通知总开关', 'type' => 'switch', 'default' => true], + ['key' => 'msg_center_rewrite_slug', 'label' => '消息中心 URL 别名', 'type' => 'input', 'default' => 'message'], + ['key' => 'message_icon_show', 'label' => '通知图标位置', 'type' => 'checkbox', 'default' => ['nav_menu'], 'options' => [ + ['label' => '导航菜单', 'value' => 'nav_menu'], + ['label' => '头像下拉面板', 'value' => 'avatar_dropdown'], + ['label' => '用户中心顶部资料卡', 'value' => 'user_center_header'], + ['label' => '公开主页顶部资料卡', 'value' => 'user_home_header'], + ]], ['key' => 'message_paginate_type', 'label' => '列表翻页模式', 'type' => 'radio', 'default' => 'ajax_lists', 'options' => [ ['label' => 'AJAX 追加加载', 'value' => 'ajax_lists'], ['label' => '数字翻页按钮', 'value' => 'default'], diff --git a/src/Settings/Integration.php b/src/Settings/Integration.php index 3f703142..9f7836fb 100644 --- a/src/Settings/Integration.php +++ b/src/Settings/Integration.php @@ -334,7 +334,11 @@ class Integration { return !empty(Settings::get_value('message_s', true)); } - /** 通知基础设置(basic group) */ + /** + * 通知基础设置(basic group) + * + * @return array{enabled:bool,slug:string,icon_show:array,paginate_type:string,user_set:bool} + */ public static function notification_settings(): array { $settings = Settings::get_all(); $slug = sanitize_key((string) ($settings['msg_center_rewrite_slug'] ?? 'message')); @@ -348,14 +352,13 @@ class Integration { } $icon_show = $settings['message_icon_show'] ?? ['nav_menu']; - if (!is_array($icon_show)) { - $icon_show = ['nav_menu']; - } - $allowed_positions = ['nav_menu', 'avatar', 'mobile_bar']; - $icon_show = array_values(array_intersect($icon_show, $allowed_positions)); + $allowed_positions = ['nav_menu', 'avatar_dropdown', 'user_center_header', 'user_home_header']; + $icon_show = is_array($icon_show) + ? array_values(array_intersect($icon_show, $allowed_positions)) + : []; return [ - 'enabled' => !empty($settings['message_s']), + 'enabled' => self::message_enabled(), 'slug' => $slug, 'icon_show' => $icon_show, 'paginate_type' => $paginate, diff --git a/templates/parts/user/author-hero.php b/templates/parts/user/author-hero.php index 6b310f5a..15936f1f 100644 --- a/templates/parts/user/author-hero.php +++ b/templates/parts/user/author-hero.php @@ -35,7 +35,6 @@ $show_follow = !array_key_exists('follow', $settings) || !empty($settings['follo $show_avatar = !array_key_exists('avatar', $settings) || !empty($settings['avatar']); $show_name = !array_key_exists('name', $settings) || !empty($settings['name']); $show_desc = !array_key_exists('desc', $settings) || !empty($settings['desc']); -$show_message = !array_key_exists('message', $settings) || !empty($settings['message']); $profile_details = is_array($dashboard['profile_details'] ?? null) ? $dashboard['profile_details'] : []; // Registration time is always present, so the details dialog always has @@ -55,7 +54,12 @@ if ($follower_count <= 0 && class_exists('\AKSRT\User\Follow')) { $follower_count = (int) \AKSRT\User\Follow::get_instance()->get_follower_count($user_id); } -$messages_url = function_exists('aksrt_get_messages_page_url') ? aksrt_get_messages_page_url() : ''; +$notification_settings = class_exists('\AKSRT\Settings\Settings') + ? \AKSRT\Settings\Settings::notification_settings() + : ['enabled' => false, 'icon_show' => []]; +$show_header_notification = !empty($notification_settings['enabled']) + && in_array('user_home_header', (array) ($notification_settings['icon_show'] ?? []), true); +$messages_url = $show_header_notification && function_exists('aksrt_get_messages_page_url') ? aksrt_get_messages_page_url() : ''; $unread_count = $is_own ? aksrt_get_user_unread_notification_count($user_id) : 0; ?>
    @@ -143,7 +147,7 @@ $unread_count = $is_own ? aksrt_get_user_unread_notification_count($user_id) : 0 - + 0) : ?> diff --git a/tests/widget-system/notification-preferences-contract.test.cjs b/tests/widget-system/notification-preferences-contract.test.cjs index 0aff2370..db5cf69e 100644 --- a/tests/widget-system/notification-preferences-contract.test.cjs +++ b/tests/widget-system/notification-preferences-contract.test.cjs @@ -21,6 +21,30 @@ test('message notification settings are a canonical user/msg inline panel', () = assert.match(routing, /'revenue', 'msg', 'settings'/); }); +test('notification icon positions map to their four render locations', () => { + const phpSchema = read('src/Admin/Schema/SchemaUsers.php'); + const jsSchema = read('assets/admin/src/schema/sections/users/notifications.js'); + const integration = read('src/Settings/Integration.php'); + const header = read('inc/helpers/header/aksrt-header-navbar.php'); + const userCenter = read('inc/helpers/aksrt-user-center.php'); + const userHome = read('templates/parts/user/author-hero.php'); + + for (const source of [phpSchema, jsSchema]) { + assert.match(source, /message_icon_show/); + assert.match(source, /导航菜单/); + assert.match(source, /头像下拉面板/); + assert.match(source, /用户中心顶部资料卡/); + assert.match(source, /公开主页顶部资料卡/); + } + assert.match(integration, /\['nav_menu', 'avatar_dropdown', 'user_center_header', 'user_home_header'\]/); + assert.match(header, /in_array\('nav_menu', \$positions, true\)/); + assert.match(header, /in_array\('avatar_dropdown', \$positions, true\)/); + assert.match(header, /aksrt-nav-icon aksrt-nav-notification/); + assert.match(header, /\$notification_but \. \$sign_but \. \$search_but/); + assert.match(userCenter, /in_array\('user_center_header'/); + assert.match(userHome, /in_array\('user_home_header'/); +}); + test('notification preference endpoint stores only the three boolean categories', () => { const controller = read('src/User/NotificationPreferences.php');