-
-
-
-
-
- - display_name ); ?> - -
- description ) : ?> -description ); ?>
- - -diff --git a/assets/css/routes/profile/layout.css b/assets/css/routes/profile/layout.css index 366e8244..daacaed8 100644 --- a/assets/css/routes/profile/layout.css +++ b/assets/css/routes/profile/layout.css @@ -401,7 +401,8 @@ padding-bottom: 12px; border-bottom: 2px solid var(--color-line-soft, rgba(0,0,0,0.06)); } -.dashboard--public .dashboard-tabs button { +.dashboard--public .dashboard-tabs button, +.dashboard--public .dashboard-tabs a { padding: 8px 16px; border-radius: 8px; font-size: 14px; @@ -413,16 +414,19 @@ transition: all 0.2s ease; position: relative; } -.dashboard--public .dashboard-tabs button:hover { +.dashboard--public .dashboard-tabs button:hover, +.dashboard--public .dashboard-tabs a:hover { color: var(--color-ink); background: var(--surface-2); } -.dashboard--public .dashboard-tabs button.is-active { +.dashboard--public .dashboard-tabs button.is-active, +.dashboard--public .dashboard-tabs a.is-active { color: var(--color-primary); background: var(--color-primary-soft); font-weight: 600; } -.dashboard--public .dashboard-tabs button.is-active::after { +.dashboard--public .dashboard-tabs button.is-active::after, +.dashboard--public .dashboard-tabs a.is-active::after { content: ''; position: absolute; bottom: -14px; @@ -433,7 +437,8 @@ background: var(--color-primary); border-radius: 1px; } -.dashboard--public .dashboard-tabs button.is-active .dashboard-tabs__count { +.dashboard--public .dashboard-tabs button.is-active .dashboard-tabs__count, +.dashboard--public .dashboard-tabs a.is-active .dashboard-tabs__count { color: var(--color-primary); background: var(--color-primary-soft); } @@ -565,3 +570,43 @@ color: #fff; } + +/* 用户中心复用全站 content-layout,避免嵌套网格与双卡片负边距抵消。 */ +.aksrt-profile__layout { + margin-top: 20px; +} +.aksrt-profile__aside.page-owned { + position: static; +} +@media (min-width: 992px) { + .aksrt-profile__aside.page-owned { + position: sticky; + } +} +.aksrt-user-center__notice { + margin-bottom: 16px; + padding: 12px 14px; + border-radius: 8px; + color: #166534; + background: rgba(34, 197, 94, 0.12); +} +.aksrt-user-center__notice--error { + color: var(--color-error, #b91c1c); + background: rgba(239, 68, 68, 0.12); +} +.aksrt-profile .uc-mobile-tabs a { + display: inline-flex; + align-items: center; + padding: 8px 14px; + border-radius: 8px; + color: var(--color-ink-3); + text-decoration: none; +} +.aksrt-profile .uc-mobile-tabs a.is-active { + color: var(--color-primary); + background: var(--color-primary-soft); +} +.aksrt-profile .dashboard-panel > .widget-card:first-child, +.aksrt-profile .profile-form > .widget-card:first-child { + margin-top: 0; +} diff --git a/assets/css/routes/user-center/part-1.css b/assets/css/routes/user-center/part-1.css index 04a667b9..e3788e15 100644 --- a/assets/css/routes/user-center/part-1.css +++ b/assets/css/routes/user-center/part-1.css @@ -17,16 +17,6 @@ padding: 0 0 40px; } -/* ==================== 两栏布局 — 对齐 zibll: 311px 侧栏 ==================== */ -.uc-layout { - display: grid; - grid-template-columns: 311px 1fr; - gap: 20px; - align-items: start; - width: 100%; -} - - .uc-header__actions { position: relative; } diff --git a/assets/css/routes/user-center/part-4.css b/assets/css/routes/user-center/part-4.css index 15e4ecbe..5fdf1ed7 100644 --- a/assets/css/routes/user-center/part-4.css +++ b/assets/css/routes/user-center/part-4.css @@ -82,10 +82,6 @@ /* ==================== 响应式 ==================== */ @media (max-width: 767px) { - .uc-layout { - grid-template-columns: 1fr; - } - .uc-sidebar { position: fixed; top: 0; diff --git a/assets/js/routes/user-center.js b/assets/js/routes/user-center.js index a707044e..76cc7984 100644 --- a/assets/js/routes/user-center.js +++ b/assets/js/routes/user-center.js @@ -18,6 +18,8 @@ var settingsNonce = cfg.settingsNonce || ''; var userId = cfg.userId || 0; var i18n = cfg.i18n || {}; + var tabAliases = cfg.tabAliases || {}; + var tabUrls = cfg.tabUrls || {}; /* ==================== Dashboard 导航 ==================== */ function initDashboardNavigation() { @@ -54,6 +56,10 @@ function switchTo(name) { if (!panels[name]) name = defaultTab; + if (panels[name].panel.dataset.panelLoaded === 'false') { + window.location.assign(tabUrls[name] || panels[name].panel.dataset.tabUrl || ('?tab=' + encodeURIComponent(name))); + return; + } Object.keys(panels).forEach(function(key) { var active = key === name; @@ -72,10 +78,8 @@ function tabFromUrl() { var m = window.location.search.match(/[?&]tab=([^&]+)/); - var name = m ? decodeURIComponent(m[1]) : defaultTab; - if (name === 'signin') return 'credits'; - if (name === 'invite') return 'settings'; - return name; + var name = m ? decodeURIComponent(m[1]) : (cfg.activeTab || defaultTab); + return tabAliases[name] || name; } function updateUrl(name) { @@ -90,16 +94,20 @@ } tabs.forEach(function(tab) { - tab.addEventListener('click', function() { + tab.addEventListener('click', function(e) { var name = this.getAttribute('data-tab'); + if (!panels[name] || panels[name].panel.dataset.panelLoaded === 'false') return; + e.preventDefault(); switchTo(name); updateUrl(name); }); }); sidebarBtns.forEach(function(btn) { - btn.addEventListener('click', function() { + btn.addEventListener('click', function(e) { var name = this.getAttribute('data-tab'); + if (!panels[name] || panels[name].panel.dataset.panelLoaded === 'false') return; + e.preventDefault(); switchTo(name); updateUrl(name); }); diff --git a/author.php b/author.php index c4cf50fb..fe6519f4 100644 --- a/author.php +++ b/author.php @@ -71,7 +71,13 @@ require_once AKSRT_DIR . '/templates/parts/user-shared-helpers.php';
diff --git a/inc/bootstrap.php b/inc/bootstrap.php index e57c0a12..45ca1a49 100644 --- a/inc/bootstrap.php +++ b/inc/bootstrap.php @@ -43,6 +43,7 @@ require_once AKSRT_DIR . '/inc/helpers/menu-decoration.php'; require_once AKSRT_DIR . '/inc/helpers/class-aksrt-nav-walker.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-transactions.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-user-dashboard.php'; +require_once AKSRT_DIR . '/inc/helpers/aksrt-user-center.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-shortcodes.php'; // ============================================================ diff --git a/inc/classes/class-aksrt-user.php b/inc/classes/class-aksrt-user.php index 2674847b..3b99c586 100644 --- a/inc/classes/class-aksrt-user.php +++ b/inc/classes/class-aksrt-user.php @@ -880,60 +880,20 @@ add_action('template_redirect', function () { // AJAX: 保存用户个人资料(显示名称、简介、联系方式) // ============================================================ add_action('wp_ajax_aksrt_save_profile', function () { - // 验证 nonce - if ( ! isset( $_POST['_profile_nonce'] ) || ! wp_verify_nonce( $_POST['_profile_nonce'], 'aksrt_profile_save' ) ) { - wp_send_json_error( array( 'message' => __( '安全验证失败,请刷新页面重试', 'aksrt' ) ) ); + if (!isset($_POST['_profile_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_profile_nonce'])), 'aksrt_profile_save')) { + wp_send_json_error(['message' => __('安全验证失败,请刷新页面重试', 'aksrt')]); } - $user_id = isset( $_POST['user_id'] ) ? (int) $_POST['user_id'] : 0; - if ( ! $user_id || $user_id !== get_current_user_id() ) { - wp_send_json_error( array( 'message' => __( '无权操作', 'aksrt' ) ) ); + $user_id = isset($_POST['user_id']) ? (int) $_POST['user_id'] : 0; + $result = function_exists('aksrt_save_user_center_profile') + ? aksrt_save_user_center_profile($user_id, $_POST) + : new WP_Error('aksrt_profile_unavailable', __('保存失败', 'aksrt')); + + if (is_wp_error($result)) { + wp_send_json_error(['message' => $result->get_error_message()]); } - $errors = array(); - - // === 更新昵称(display_name) === - if ( isset( $_POST['nickname'] ) ) { - $name = sanitize_text_field( $_POST['nickname'] ); - if ( mb_strlen( $name ) < 1 || mb_strlen( $name ) > 50 ) { - $errors[] = __( '昵称长度需在 1-50 字之间', 'aksrt' ); - } else { - wp_update_user( array( 'ID' => $user_id, 'display_name' => $name ) ); - } - } - - // === 更新个人简介 === - if ( isset( $_POST['description'] ) ) { - $desc = sanitize_textarea_field( $_POST['description'] ); - if ( mb_strlen( $desc ) > 500 ) { - $errors[] = __( '个人简介不能超过 500 字', 'aksrt' ); - } else { - wp_update_user( array( 'ID' => $user_id, 'description' => $desc ) ); - } - } - - // === 更新联系方式 === - $contacts = array(); - if ( isset( $_POST['contacts'] ) && is_array( $_POST['contacts'] ) ) { - foreach ( $_POST['contacts'] as $c ) { - $url = isset( $c['url'] ) ? esc_url_raw( $c['url'] ) : ''; - $icon = isset( $c['icon'] ) ? sanitize_key( $c['icon'] ) : ''; - $icon = preg_replace('/^(fab|fas|far)[\s-]*/', '', $icon); - $icon = preg_replace('/^fa[\s-]*/', '', $icon); - $icon = preg_replace('/^[\s-]+/', '', $icon); - $icon = trim( $icon, '- ' ); - if ( ! $url || ! $icon ) continue; - $name = aksrt_icon_key_to_name( $icon ); - $contacts[] = array( 'name' => $name, 'url' => $url, 'icon' => $icon ); - } - } - update_user_meta( $user_id, 'aksrt_user_contacts', $contacts ); - - if ( ! empty( $errors ) ) { - wp_send_json_error( array( 'message' => implode( '
+
+
+
+
+
+ description ); ?>
+ + ++ +
+
-
-
-
-
-
- description ); ?>
- - -