Merge pull request 'Worktree page profile shell' (#29) from worktree-page-profile-shell into main
Reviewed-on: CYL/wordpress-theme-aksrt#29
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -82,10 +82,6 @@
|
||||
|
||||
/* ==================== 响应式 ==================== */
|
||||
@media (max-width: 767px) {
|
||||
.uc-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.uc-sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
+7
-1
@@ -71,7 +71,13 @@ require_once AKSRT_DIR . '/templates/parts/user-shared-helpers.php';
|
||||
<?php if (have_posts()) : ?>
|
||||
<div class="aksrt-author-page__posts">
|
||||
<?php while (have_posts()) : the_post(); ?>
|
||||
<?php get_template_part('templates/parts/content', 'profile-list-item'); ?>
|
||||
<?php get_template_part('templates/parts/content', 'profile-list-item', [
|
||||
'action' => [
|
||||
'type' => 'view',
|
||||
'url' => get_permalink(),
|
||||
'label' => __('阅读', 'aksrt'),
|
||||
],
|
||||
]); ?>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
// ============================================================
|
||||
|
||||
@@ -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( '<br>', $errors ) ) );
|
||||
}
|
||||
|
||||
wp_send_json_success( array( 'message' => __( '保存成功!', 'aksrt' ) ) );
|
||||
wp_send_json_success(['message' => __('保存成功!', 'aksrt')]);
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
|
||||
@@ -0,0 +1,412 @@
|
||||
<?php
|
||||
/**
|
||||
* User center helpers.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_normalize_user_contacts')) {
|
||||
/**
|
||||
* Sanitize the editable public contact list.
|
||||
*
|
||||
* @param mixed $raw_contacts Submitted contact rows.
|
||||
* @return array<int, array{name:string,url:string,icon:string}>
|
||||
*/
|
||||
function aksrt_normalize_user_contacts($raw_contacts): array {
|
||||
$contacts = [];
|
||||
if (!is_array($raw_contacts)) {
|
||||
return $contacts;
|
||||
}
|
||||
|
||||
foreach ($raw_contacts as $contact) {
|
||||
if (!is_array($contact)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url = isset($contact['url']) ? esc_url_raw(wp_unslash($contact['url'])) : '';
|
||||
$icon = isset($contact['icon']) ? sanitize_key(wp_unslash($contact['icon'])) : '';
|
||||
$icon = preg_replace('/^(fab|fas|far)[\s-]*/', '', $icon);
|
||||
$icon = preg_replace('/^fa[\s-]*/', '', (string) $icon);
|
||||
$icon = trim(preg_replace('/^[\s-]+/', '', (string) $icon), '- ');
|
||||
if (!$url || !$icon) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$contacts[] = [
|
||||
'name' => aksrt_icon_key_to_name($icon),
|
||||
'url' => $url,
|
||||
'icon' => $icon,
|
||||
];
|
||||
}
|
||||
|
||||
return $contacts;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_save_user_center_profile')) {
|
||||
/**
|
||||
* Save the user-center profile form for both AJAX and no-JS requests.
|
||||
*
|
||||
* @param int $user_id User being updated.
|
||||
* @param array $input Untrusted request data.
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
function aksrt_save_user_center_profile(int $user_id, array $input) {
|
||||
if (!$user_id || $user_id !== get_current_user_id()) {
|
||||
return new WP_Error('aksrt_profile_forbidden', __('无权操作', 'aksrt'));
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
$update = ['ID' => $user_id];
|
||||
|
||||
if (isset($input['nickname'])) {
|
||||
$name = sanitize_text_field(wp_unslash($input['nickname']));
|
||||
if (mb_strlen($name) < 1 || mb_strlen($name) > 50) {
|
||||
$errors[] = __('昵称长度需在 1-50 字之间', 'aksrt');
|
||||
} else {
|
||||
$update['display_name'] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($input['description'])) {
|
||||
$description = sanitize_textarea_field(wp_unslash($input['description']));
|
||||
if (mb_strlen($description) > 500) {
|
||||
$errors[] = __('个人简介不能超过 500 字', 'aksrt');
|
||||
} else {
|
||||
$update['description'] = $description;
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
return new WP_Error('aksrt_profile_invalid', implode('<br>', $errors));
|
||||
}
|
||||
|
||||
if (count($update) > 1) {
|
||||
$result = wp_update_user($update);
|
||||
if (is_wp_error($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
update_user_meta($user_id, 'aksrt_user_contacts', aksrt_normalize_user_contacts($input['contacts'] ?? []));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_get_user_center_tab_url')) {
|
||||
/**
|
||||
* Build a canonical full-page user-center tab URL.
|
||||
*/
|
||||
function aksrt_get_user_center_tab_url(string $tab): string {
|
||||
$url = remove_query_arg([
|
||||
'tab', 'posts_page', 'comments_page', 'favorites_page', 'credits_page',
|
||||
'post_status', 'saved', 'profile_error',
|
||||
], aksrt_get_user_center_url());
|
||||
|
||||
return add_query_arg('tab', sanitize_key($tab), $url);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_normalize_user_center_tabs')) {
|
||||
/**
|
||||
* Normalize the dashboard tab contract.
|
||||
*/
|
||||
function aksrt_normalize_user_center_tabs(array $tabs): array {
|
||||
$normalized = [];
|
||||
foreach ($tabs as $key => $tab) {
|
||||
$key = sanitize_key((string) $key);
|
||||
if (!$key || !is_array($tab)) {
|
||||
continue;
|
||||
}
|
||||
$normalized[$key] = [
|
||||
'label' => (string) ($tab['label'] ?? $key),
|
||||
'icon' => sanitize_html_class((string) ($tab['icon'] ?? 'circle')),
|
||||
'template' => isset($tab['template']) ? (string) $tab['template'] : '',
|
||||
'context_callback' => $tab['context_callback'] ?? null,
|
||||
];
|
||||
}
|
||||
return $normalized;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_capture_user_center_view')) {
|
||||
/**
|
||||
* Render an internal user-center view into an inert HTML payload.
|
||||
*/
|
||||
function aksrt_capture_user_center_view(string $view, array $context): string {
|
||||
$path = AKSRT_DIR . '/inc/helpers/user-center-renderers/profile-' . sanitize_file_name($view) . '.php';
|
||||
if (!is_file($path)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
ob_start();
|
||||
$args = ['context' => $context];
|
||||
require $path;
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_capture_user_center_panel')) {
|
||||
/**
|
||||
* Capture a built-in or registered user-center panel body.
|
||||
*/
|
||||
function aksrt_capture_user_center_panel(string $tab_key, array $tab, array $context): string {
|
||||
$built_in_tabs = ['profile', 'posts', 'comments', 'favorites', 'credits', 'settings'];
|
||||
if (in_array($tab_key, $built_in_tabs, true)) {
|
||||
return aksrt_capture_user_center_view($tab_key, $context);
|
||||
}
|
||||
|
||||
$panel_context = $context;
|
||||
if (is_callable($tab['context_callback'] ?? null)) {
|
||||
$custom_context = call_user_func($tab['context_callback'], $context, $tab_key);
|
||||
if (is_array($custom_context)) {
|
||||
$panel_context = array_merge($panel_context, $custom_context);
|
||||
}
|
||||
}
|
||||
|
||||
$template = ltrim((string) ($tab['template'] ?? ''), '/');
|
||||
if ($template === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$template_path = locate_template([$template . '.php', $template], false, false);
|
||||
if (!$template_path) {
|
||||
return '';
|
||||
}
|
||||
|
||||
ob_start();
|
||||
load_template($template_path, false, ['context' => $panel_context]);
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_build_user_center_render_context')) {
|
||||
/**
|
||||
* Assemble all runtime data before template parts are entered.
|
||||
*/
|
||||
function aksrt_build_user_center_render_context(array $context): array {
|
||||
$active_tab = (string) ($context['active_tab'] ?? 'profile');
|
||||
$context['header_html'] = aksrt_capture_user_center_view('header', $context);
|
||||
$context['sidebar_html'] = aksrt_capture_user_center_view('sidebar', $context);
|
||||
$context['mobile_tabs'] = [];
|
||||
foreach ((array) ($context['dashboard_tabs'] ?? []) as $tab_key => $tab) {
|
||||
$context['mobile_tabs'][] = [
|
||||
'key' => (string) $tab_key,
|
||||
'label' => (string) ($tab['label'] ?? $tab_key),
|
||||
'url' => aksrt_get_user_center_tab_url((string) $tab_key),
|
||||
'is_active' => $active_tab === $tab_key,
|
||||
];
|
||||
}
|
||||
|
||||
$context['panels'] = [];
|
||||
foreach ((array) ($context['dashboard_tabs'] ?? []) as $tab_key => $tab) {
|
||||
$context['panels'][$tab_key] = [
|
||||
'key' => (string) $tab_key,
|
||||
'url' => aksrt_get_user_center_tab_url((string) $tab_key),
|
||||
'is_active' => $active_tab === $tab_key,
|
||||
'is_loaded' => $active_tab === $tab_key,
|
||||
'html' => $active_tab === $tab_key
|
||||
? aksrt_capture_user_center_panel((string) $tab_key, (array) $tab, $context)
|
||||
: '',
|
||||
];
|
||||
}
|
||||
|
||||
$context['account_modals_html'] = 'settings' === $active_tab
|
||||
? aksrt_capture_user_center_view('account-modals', $context)
|
||||
: '';
|
||||
return $context;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_get_user_center_render_context')) {
|
||||
/**
|
||||
* Resolve the current user's complete render context outside template files.
|
||||
*/
|
||||
function aksrt_get_user_center_render_context(WP_User $current_user): array {
|
||||
$user_id = (int) $current_user->ID;
|
||||
$user_center_settings = class_exists('AKSRT_Settings')
|
||||
? AKSRT_Settings::get_user_center_settings()
|
||||
: [
|
||||
'tabs' => ['profile', 'posts', 'comments', 'favorites'],
|
||||
'avatar_upload' => true,
|
||||
'cover_upload' => true,
|
||||
'social_links' => true,
|
||||
];
|
||||
$dashboard_tabs = class_exists('AKSRT_User_Center')
|
||||
? AKSRT_User_Center::get_instance()->get_dashboard_tabs()
|
||||
: [
|
||||
'profile' => ['label' => __('个人信息', 'aksrt'), 'icon' => 'user'],
|
||||
'posts' => ['label' => __('我的文章', 'aksrt'), 'icon' => 'file-alt'],
|
||||
'comments' => ['label' => __('我的评论', 'aksrt'), 'icon' => 'comment'],
|
||||
'favorites' => ['label' => __('我的收藏', 'aksrt'), 'icon' => 'star'],
|
||||
'settings' => ['label' => __('账号设置', 'aksrt'), 'icon' => 'cog'],
|
||||
];
|
||||
$dashboard_tabs = aksrt_normalize_user_center_tabs($dashboard_tabs);
|
||||
$dashboard_tab_keys = array_keys($dashboard_tabs);
|
||||
$default_dashboard_tab = in_array('profile', $dashboard_tab_keys, true) ? 'profile' : ($dashboard_tab_keys[0] ?? 'profile');
|
||||
$active_tab = isset($_GET['tab']) ? sanitize_key(wp_unslash($_GET['tab'])) : $default_dashboard_tab;
|
||||
if ('signin' === $active_tab) {
|
||||
$active_tab = 'credits';
|
||||
} elseif ('invite' === $active_tab) {
|
||||
$active_tab = 'settings';
|
||||
}
|
||||
if (!in_array($active_tab, $dashboard_tab_keys, true)) {
|
||||
$active_tab = $default_dashboard_tab;
|
||||
}
|
||||
|
||||
$dashboard = function_exists('aksrt_get_user_dashboard_view')
|
||||
? aksrt_get_user_dashboard_view($user_id, [
|
||||
'viewer_id' => $user_id,
|
||||
'include_recent_posts' => false,
|
||||
'include_governance' => false,
|
||||
])
|
||||
: [];
|
||||
$target_user = $current_user;
|
||||
$post_count = (int) ($dashboard['post_count'] ?? count_user_posts($user_id, 'post', true));
|
||||
$comment_count = (int) ($dashboard['comment_count'] ?? get_comments(['user_id' => $user_id, 'count' => true, 'status' => 'approve']));
|
||||
$favorite_post_ids = $dashboard['favorite_post_ids'] ?? [];
|
||||
$favorite_count = (int) ($dashboard['favorite_count'] ?? count($favorite_post_ids));
|
||||
$user_contacts = $dashboard['user_contacts'] ?? get_user_meta($user_id, 'aksrt_user_contacts', true);
|
||||
$user_contacts = is_array($user_contacts) ? $user_contacts : [];
|
||||
$profile_signals = $dashboard['profile_signals'] ?? [];
|
||||
$user_background_url = (string) ($dashboard['background_url'] ?? get_user_meta($user_id, 'aksrt_background_image', true));
|
||||
$allow_bg_upload = !empty($user_center_settings['cover_upload']) && class_exists('AKSRT_Settings') && aksrt_get_setting('allow_background_upload', false);
|
||||
$show_avatar_edit = !empty($user_center_settings['avatar_upload']);
|
||||
$avatar_settings_url = admin_url('profile.php');
|
||||
$notification_unread_count = function_exists('aksrt_get_user_unread_notification_count') ? aksrt_get_user_unread_notification_count($user_id) : 0;
|
||||
$messages_url = function_exists('aksrt_get_messages_url')
|
||||
? aksrt_get_messages_url()
|
||||
: aksrt_get_user_center_url('notif');
|
||||
$per_page = 10;
|
||||
$posts_page = max(1, isset($_GET['posts_page']) ? (int) $_GET['posts_page'] : 1);
|
||||
$comments_page = max(1, isset($_GET['comments_page']) ? (int) $_GET['comments_page'] : 1);
|
||||
$favorites_page = max(1, isset($_GET['favorites_page']) ? (int) $_GET['favorites_page'] : 1);
|
||||
$post_status_filter = isset($_GET['post_status']) ? sanitize_key(wp_unslash($_GET['post_status'])) : 'publish';
|
||||
if (!in_array($post_status_filter, ['all', 'publish', 'draft', 'pending', 'private'], true)) {
|
||||
$post_status_filter = 'publish';
|
||||
}
|
||||
$user_status_counts = ['publish' => 0, 'draft' => 0, 'pending' => 0, 'private' => 0];
|
||||
if ('posts' === $active_tab) {
|
||||
global $wpdb;
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT post_status, COUNT(*) AS num FROM {$wpdb->posts} WHERE post_author = %d AND post_type = 'post' AND post_status IN ('publish','draft','pending','private') GROUP BY post_status",
|
||||
$user_id
|
||||
));
|
||||
foreach ((array) $rows as $row) {
|
||||
$user_status_counts[$row->post_status] = (int) $row->num;
|
||||
}
|
||||
$post_count = (int) array_sum($user_status_counts);
|
||||
}
|
||||
|
||||
$svg_empty_post = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>';
|
||||
$svg_empty_comment = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>';
|
||||
$svg_empty_favorite = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>';
|
||||
require_once AKSRT_DIR . '/templates/parts/user-shared-helpers.php';
|
||||
|
||||
$vip_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_payment_vip_settings() : [];
|
||||
$affiliate_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_payment_affiliate_settings() : [];
|
||||
$orders_url = function_exists('aksrt_get_orders_page_url') ? aksrt_get_orders_page_url() : '';
|
||||
$show_vip = !empty($vip_settings['enabled']);
|
||||
$show_credit_tabs = (bool) ($dashboard['credits_enabled'] ?? false);
|
||||
$affiliate_enabled = $show_credit_tabs && !empty($affiliate_settings['enabled']);
|
||||
$currency_name = (string) ($dashboard['currency_name'] ?? __('积分', 'aksrt'));
|
||||
$tab_urls = [];
|
||||
foreach ($dashboard_tab_keys as $tab_key) {
|
||||
$tab_urls[$tab_key] = aksrt_get_user_center_tab_url($tab_key);
|
||||
}
|
||||
|
||||
$render_context = [
|
||||
'user_center_settings' => $user_center_settings,
|
||||
'dashboard_tabs' => $dashboard_tabs,
|
||||
'dashboard_tab_keys' => $dashboard_tab_keys,
|
||||
'default_dashboard_tab' => $default_dashboard_tab,
|
||||
'active_tab' => $active_tab,
|
||||
'dashboard' => $dashboard,
|
||||
'target_user' => $target_user,
|
||||
'user_id' => $user_id,
|
||||
'post_count' => $post_count,
|
||||
'comment_count' => $comment_count,
|
||||
'favorite_post_ids' => $favorite_post_ids,
|
||||
'favorite_count' => $favorite_count,
|
||||
'user_contacts' => $user_contacts,
|
||||
'profile_signals' => $profile_signals,
|
||||
'user_background_url' => $user_background_url,
|
||||
'allow_bg_upload' => $allow_bg_upload,
|
||||
'show_avatar_edit' => $show_avatar_edit,
|
||||
'avatar_settings_url' => $avatar_settings_url,
|
||||
'notification_unread_count' => $notification_unread_count,
|
||||
'messages_url' => $messages_url,
|
||||
'per_page' => $per_page,
|
||||
'posts_page' => $posts_page,
|
||||
'comments_page' => $comments_page,
|
||||
'favorites_page' => $favorites_page,
|
||||
'post_status_filter' => $post_status_filter,
|
||||
'user_status_counts' => $user_status_counts,
|
||||
'svg_empty_post' => $svg_empty_post,
|
||||
'svg_empty_comment' => $svg_empty_comment,
|
||||
'svg_empty_favorite' => $svg_empty_favorite,
|
||||
'orders_url' => $orders_url,
|
||||
'show_vip' => $show_vip,
|
||||
'show_credit_tabs' => $show_credit_tabs,
|
||||
'affiliate_enabled' => $affiliate_enabled,
|
||||
'currency_name' => $currency_name,
|
||||
'credit_balance' => (float) ($dashboard['credit_balance'] ?? 0.0),
|
||||
'credits_enabled' => $show_credit_tabs,
|
||||
'vip_settings' => $vip_settings,
|
||||
'show_invite_section' => $show_credit_tabs
|
||||
&& class_exists('AKSRT_Settings')
|
||||
&& AKSRT_Settings::invite_enabled()
|
||||
&& AKSRT_Settings::invite_registration_enabled(),
|
||||
'user_email' => (string) $current_user->user_email,
|
||||
];
|
||||
$render_context['runtime_config'] = [
|
||||
'ajaxUrl' => admin_url('admin-ajax.php'),
|
||||
'publicNonce' => wp_create_nonce('aksrt_public_nonce'),
|
||||
'settingsNonce' => wp_create_nonce('aksrt_account_settings'),
|
||||
'userId' => $user_id,
|
||||
'defaultTab' => $default_dashboard_tab,
|
||||
'activeTab' => $active_tab,
|
||||
'tabAliases' => ['signin' => 'credits', 'invite' => 'settings'],
|
||||
'tabUrls' => $tab_urls,
|
||||
'i18n' => [
|
||||
'contactUrlPlaceholder' => __('链接 URL', 'aksrt'),
|
||||
'deleteLabel' => __('删除', 'aksrt'),
|
||||
'saving' => __('保存中…', 'aksrt'),
|
||||
'saveBtn' => __('保存修改', 'aksrt'),
|
||||
'saved' => __('已保存', 'aksrt'),
|
||||
'saveFailed' => __('保存失败', 'aksrt'),
|
||||
'networkError' => __('网络错误,请重试', 'aksrt'),
|
||||
'confirmUnfavorite' => __('确定取消收藏这篇文章?', 'aksrt'),
|
||||
'unfavorited' => __('已取消收藏', 'aksrt'),
|
||||
'operationFailed' => __('操作失败', 'aksrt'),
|
||||
'confirmUnbind' => __('确定解除绑定?', 'aksrt'),
|
||||
'unbinding' => __('解除中...', 'aksrt'),
|
||||
'unbindSuccess' => __('解除成功', 'aksrt'),
|
||||
'unbindFailed' => __('解除失败', 'aksrt'),
|
||||
'unbind' => __('解除', 'aksrt'),
|
||||
],
|
||||
];
|
||||
$render_context['cover_upload_config'] = $allow_bg_upload ? [
|
||||
'enabled' => true,
|
||||
'restUrl' => rest_url('aksrt/v1/user/background'),
|
||||
'restNonce' => wp_create_nonce('wp_rest'),
|
||||
'buttonId' => 'aksrt-upload-bg-btn',
|
||||
'inputId' => 'aksrt-bg-file-input',
|
||||
'imageId' => 'aksrt-cover-img',
|
||||
'fieldName' => 'background',
|
||||
'maxSize' => 2097152,
|
||||
'fallbackImage' => AKSRT_URI . '/assets/img/person_background.png',
|
||||
'idleText' => __('编辑', 'aksrt'),
|
||||
'loadingText' => __('上传中…', 'aksrt'),
|
||||
'tooLargeText' => __('图片大小不能超过 2MB', 'aksrt'),
|
||||
'successText' => __('背景图已更新', 'aksrt'),
|
||||
'errorText' => __('上传失败', 'aksrt'),
|
||||
'networkErrorText' => __('网络错误,请重试', 'aksrt'),
|
||||
] : [];
|
||||
$render_context = aksrt_build_user_center_render_context($render_context);
|
||||
|
||||
return $render_context;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,10 @@ defined('ABSPATH') || exit;
|
||||
* Get aggregated dashboard view data for a user.
|
||||
*
|
||||
* @param int $user_id Target user ID.
|
||||
* @param array $args Optional. 'viewer_id' => current viewer ID.
|
||||
* @param array $args Optional. Supported keys:
|
||||
* - viewer_id: Current viewer ID.
|
||||
* - include_recent_posts: Whether to query recent posts.
|
||||
* - include_governance: Whether to resolve notice/report data.
|
||||
* @return array {
|
||||
* @type int $post_count Published post count.
|
||||
* @type int $comment_count Approved comment count.
|
||||
@@ -31,8 +34,10 @@ defined('ABSPATH') || exit;
|
||||
* }
|
||||
*/
|
||||
function aksrt_get_user_dashboard_view(int $user_id, array $args = []): array {
|
||||
$viewer_id = (int) ($args['viewer_id'] ?? get_current_user_id());
|
||||
$is_own_profile = is_user_logged_in() && $viewer_id === $user_id;
|
||||
$viewer_id = (int) ($args['viewer_id'] ?? get_current_user_id());
|
||||
$include_recent_posts = !array_key_exists('include_recent_posts', $args) || (bool) $args['include_recent_posts'];
|
||||
$include_governance = !array_key_exists('include_governance', $args) || (bool) $args['include_governance'];
|
||||
$is_own_profile = is_user_logged_in() && $viewer_id === $user_id;
|
||||
|
||||
$post_count = (int) count_user_posts($user_id, 'post', true);
|
||||
$comment_count = (int) get_comments([
|
||||
@@ -45,15 +50,17 @@ function aksrt_get_user_dashboard_view(int $user_id, array $args = []): array {
|
||||
? aksrt_get_user_interaction_posts('_aksrt_favorite_posts', $user_id)
|
||||
: [];
|
||||
$favorite_count = count($favorite_post_ids);
|
||||
$recent_posts = get_posts([
|
||||
'author' => $user_id,
|
||||
'post_type' => 'post',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => 5,
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'no_found_rows' => true,
|
||||
]);
|
||||
$recent_posts = $include_recent_posts
|
||||
? get_posts([
|
||||
'author' => $user_id,
|
||||
'post_type' => 'post',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => 5,
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'no_found_rows' => true,
|
||||
])
|
||||
: [];
|
||||
|
||||
$user_contacts = get_user_meta($user_id, 'aksrt_user_contacts', true) ?: [];
|
||||
if (!is_array($user_contacts)) {
|
||||
@@ -74,7 +81,9 @@ function aksrt_get_user_dashboard_view(int $user_id, array $args = []): array {
|
||||
? AKSRT_Settings::get_currency_name()
|
||||
: __('积分', 'aksrt');
|
||||
|
||||
$user_home_manager = class_exists('AKSRT_User_Home') ? AKSRT_User_Home::get_instance() : null;
|
||||
$user_home_manager = $include_governance && class_exists('AKSRT_User_Home')
|
||||
? AKSRT_User_Home::get_instance()
|
||||
: null;
|
||||
$profile_signals = $user_home_manager ? $user_home_manager->get_profile_signals($user_id) : [];
|
||||
$profile_notice = $user_home_manager ? $user_home_manager->get_profile_notice($user_id) : [];
|
||||
$show_report = $user_home_manager ? $user_home_manager->show_report_entry() : false;
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/** Internal account modal renderer. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
?>
|
||||
<!-- ==================== 修改密码弹窗 ==================== -->
|
||||
<div id="pwd-modal" class="aksrt-modal" role="dialog" aria-modal="true" aria-label="<?php esc_attr_e( '修改密码', 'aksrt' ); ?>">
|
||||
<div class="aksrt-modal__overlay" data-close-modal></div>
|
||||
<div class="aksrt-modal__box">
|
||||
<div class="aksrt-modal__header">
|
||||
<div class="aksrt-modal__title-wrap">
|
||||
<span class="aksrt-modal__icon"><i class="fas fa-lock" aria-hidden="true"></i></span>
|
||||
<h4><?php esc_html_e( '修改密码', 'aksrt' ); ?></h4>
|
||||
</div>
|
||||
<button type="button" class="aksrt-modal__close" data-close-modal title="<?php esc_attr_e( '关闭', 'aksrt' ); ?>"><i class="fas fa-times" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
<form id="pwd-form" autocomplete="off" novalidate>
|
||||
<div class="modal-field">
|
||||
<label for="pwd-old"><?php esc_html_e( '原密码', 'aksrt' ); ?></label>
|
||||
<input type="password" id="pwd-old" name="old_password" required minlength="1">
|
||||
<button type="button" class="toggle-pwd" data-target="pwd-old"></button>
|
||||
</div>
|
||||
<div class="modal-field">
|
||||
<label for="pwd-new"><?php esc_html_e( '新密码', 'aksrt' ); ?></label>
|
||||
<input type="password" id="pwd-new" name="new_password" required minlength="6" placeholder="<?php esc_attr_e( '至少6位字符', 'aksrt' ); ?>">
|
||||
<button type="button" class="toggle-pwd" data-target="pwd-new"></button>
|
||||
<div class="pwd-strength" id="pwd-strength-bar">
|
||||
<div class="pwd-strength__fill"></div>
|
||||
</div>
|
||||
<span class="pwd-strength__text" id="pwd-strength-text"></span>
|
||||
</div>
|
||||
<div class="modal-field">
|
||||
<label for="pwd-new-confirm"><?php esc_html_e( '确认新密码', 'aksrt' ); ?></label>
|
||||
<input type="password" id="pwd-new-confirm" name="new_password_confirm" required minlength="6" placeholder="<?php esc_attr_e( '再次输入新密码', 'aksrt' ); ?>">
|
||||
<button type="button" class="toggle-pwd" data-target="pwd-new-confirm"></button>
|
||||
</div>
|
||||
<div class="modal-field modal-field--code">
|
||||
<label for="pwd-code"><?php esc_html_e( '当前邮箱验证码', 'aksrt' ); ?></label>
|
||||
<div class="code-input-group">
|
||||
<input type="text" id="pwd-code" name="email_code" maxlength="6" inputmode="numeric" pattern="[0-9]*" placeholder="6位数字验证码" required>
|
||||
<button type="button" class="btn-ghost btn-sm code-send-btn" id="pwd-send-code"><?php esc_html_e( '发送到当前邮箱', 'aksrt' ); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php aksrt_render_captcha('change_password'); ?>
|
||||
|
||||
<div class="aksrt-modal__footer">
|
||||
<button type="button" class="btn-ghost btn-sm" data-close-modal><?php esc_html_e( '取消', 'aksrt' ); ?></button>
|
||||
<button type="submit" class="btn-primary btn-sm" id="pwd-submit"><?php esc_html_e( '确认修改', 'aksrt' ); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== 更改邮箱弹窗 ==================== -->
|
||||
<div id="email-modal" class="aksrt-modal" role="dialog" aria-modal="true" aria-label="<?php esc_attr_e( '更改邮箱', 'aksrt' ); ?>">
|
||||
<div class="aksrt-modal__overlay" data-close-modal></div>
|
||||
<div class="aksrt-modal__box">
|
||||
<div class="aksrt-modal__header">
|
||||
<div class="aksrt-modal__title-wrap">
|
||||
<span class="aksrt-modal__icon"><i class="far fa-envelope" aria-hidden="true"></i></span>
|
||||
<h4><?php esc_html_e( '更改邮箱', 'aksrt' ); ?></h4>
|
||||
</div>
|
||||
<button type="button" class="aksrt-modal__close" data-close-modal title="<?php esc_attr_e( '关闭', 'aksrt' ); ?>"><i class="fas fa-times" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
<form id="email-form" autocomplete="off" novalidate>
|
||||
<div class="modal-field">
|
||||
<label><?php esc_html_e( '当前邮箱', 'aksrt' ); ?></label>
|
||||
<div class="readonly-display"><?php echo esc_html( $user_email ); ?></div>
|
||||
</div>
|
||||
<div class="modal-field">
|
||||
<label for="email-current-password"><?php esc_html_e( '当前密码', 'aksrt' ); ?></label>
|
||||
<input type="password" id="email-current-password" name="current_password" required minlength="1" placeholder="<?php esc_attr_e( '请输入当前登录密码', 'aksrt' ); ?>">
|
||||
<button type="button" class="toggle-pwd" data-target="email-current-password"></button>
|
||||
</div>
|
||||
<div class="modal-field">
|
||||
<label for="email-new"><?php esc_html_e( '新邮箱', 'aksrt' ); ?></label>
|
||||
<input type="email" id="email-new" name="new_email" required placeholder="<?php esc_attr_e( '请输入新的邮箱地址', 'aksrt' ); ?>">
|
||||
</div>
|
||||
<div class="modal-field modal-field--code">
|
||||
<label for="email-code"><?php esc_html_e( '新邮箱验证码', 'aksrt' ); ?></label>
|
||||
<div class="code-input-group">
|
||||
<input type="text" id="email-code" name="email_code" maxlength="6" inputmode="numeric" pattern="[0-9]*" placeholder="6位数字验证码" required>
|
||||
<button type="button" class="btn-ghost btn-sm code-send-btn" id="email-send-code"><?php esc_html_e( '发送到新邮箱', 'aksrt' ); ?></button>
|
||||
</div>
|
||||
<p class="settings-hint settings-hint--bottom"><?php esc_html_e( '验证码将发送到你填写的新邮箱,验证通过后才会正式切换。', 'aksrt' ); ?></p>
|
||||
</div>
|
||||
|
||||
<?php aksrt_render_captcha('change_email'); ?>
|
||||
|
||||
<div class="aksrt-modal__footer">
|
||||
<button type="button" class="btn-ghost btn-sm" data-close-modal><?php esc_html_e( '取消', 'aksrt' ); ?></button>
|
||||
<button type="submit" class="btn-primary btn-sm" id="email-submit"><?php esc_html_e( '确认更改', 'aksrt' ); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* User center profile comments part.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
?>
|
||||
<!-- ==================== 我的评论 ==================== -->
|
||||
<div class="widget-card">
|
||||
<div class="profile-list-header">
|
||||
<h3 class="widget-title widget-title--inline">
|
||||
<?php printf( esc_html__( '我的评论(%d 条)', 'aksrt' ), $comment_count ); ?>
|
||||
</h3>
|
||||
</div>
|
||||
<?php
|
||||
$comments_total = $comment_count;
|
||||
$cs = get_comments( [
|
||||
'user_id' => $user_id,
|
||||
'number' => $per_page,
|
||||
'offset' => ( $comments_page - 1 ) * $per_page,
|
||||
'status' => 'approve',
|
||||
'update_comment_meta_cache' => false,
|
||||
] );
|
||||
if ( $cs ) : ?>
|
||||
<div class="profile-comment-list">
|
||||
<?php foreach ( $cs as $c ) :
|
||||
get_template_part('templates/parts/content', 'profile-comment-item', ['comment' => $c]);
|
||||
endforeach; ?>
|
||||
</div>
|
||||
<?php
|
||||
$comments_total_pages = (int) ceil( $comments_total / $per_page );
|
||||
aksrt_render_profile_pagination( $comments_total_pages, $comments_page, 'comments_page' );
|
||||
?>
|
||||
<?php else :
|
||||
aksrt_render_profile_empty(
|
||||
$svg_empty_comment,
|
||||
__( '暂无评论', 'aksrt' ),
|
||||
__( '在你感兴趣的文章下留下你的看法吧。', 'aksrt' )
|
||||
);
|
||||
endif; ?>
|
||||
</div>
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
/**
|
||||
* User center profile credits part.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
?>
|
||||
<?php
|
||||
$balance = (float) ($credit_balance ?? 0.0);
|
||||
$credits_enabled = ! empty( $credits_enabled );
|
||||
$vip_settings = is_array( $vip_settings ?? null ) ? $vip_settings : [];
|
||||
$show_vip_card = ! empty( $vip_settings['enabled'] );
|
||||
$is_vip_user = function_exists( 'aksrt_is_vip' ) && aksrt_is_vip( $user_id );
|
||||
$vip_badge_text = function_exists( 'aksrt_get_vip_badge_text' ) ? aksrt_get_vip_badge_text() : 'VIP';
|
||||
?>
|
||||
<!-- ==================== 账户余额 ==================== -->
|
||||
|
||||
<!-- 余额卡片 -->
|
||||
<div class="uc-balance-card">
|
||||
<div class="uc-balance-card__bg"></div>
|
||||
<div class="uc-balance-card__content">
|
||||
<div class="uc-balance-card__header">
|
||||
<span class="uc-balance-card__label"><?php esc_html_e( '账户余额', 'aksrt' ); ?></span>
|
||||
<span class="uc-balance-card__currency"><?php echo esc_html( $currency_name ); ?></span>
|
||||
</div>
|
||||
<div class="uc-balance-card__amount">
|
||||
<span class="uc-balance-card__value"><?php echo esc_html( aksrt_format_credits( $balance ) ); ?></span>
|
||||
</div>
|
||||
<?php if ( $credits_enabled ) : ?>
|
||||
<div class="uc-balance-card__actions" data-aksrt-signin>
|
||||
<span class="uc-balance-card__sign-status" data-signin-status></span>
|
||||
<button type="button" class="uc-balance-card__sign-btn" data-signin-btn disabled>
|
||||
<i class="fas fa-calendar-check" aria-hidden="true"></i>
|
||||
<span><?php esc_html_e( '签到', 'aksrt' ); ?></span>
|
||||
</button>
|
||||
</div>
|
||||
<p class="uc-balance-card__tip" data-signin-tip></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( $show_vip_card ) : ?>
|
||||
<!-- VIP 会员卡片 -->
|
||||
<div class="uc-vip-card<?php echo $is_vip_user ? ' uc-vip-card--active' : ''; ?>">
|
||||
<div class="uc-vip-card__bg"></div>
|
||||
<div class="uc-vip-card__content">
|
||||
<div class="uc-vip-card__header">
|
||||
<div class="uc-vip-card__icon">
|
||||
<i class="fas fa-crown" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="uc-vip-card__info">
|
||||
<span class="uc-vip-card__label"><?php echo esc_html( $vip_settings['name'] ?? __( 'VIP会员', 'aksrt' ) ); ?></span>
|
||||
<?php if ( $is_vip_user ) : ?>
|
||||
<span class="uc-vip-card__status uc-vip-card__status--active"><?php esc_html_e( '已开通', 'aksrt' ); ?></span>
|
||||
<?php else : ?>
|
||||
<span class="uc-vip-card__status"><?php esc_html_e( '未开通', 'aksrt' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ( $is_vip_user ) : ?>
|
||||
<div class="uc-vip-card__benefits">
|
||||
<span class="uc-vip-card__benefit"><i class="fas fa-download" aria-hidden="true"></i> <?php esc_html_e( '免费下载', 'aksrt' ); ?></span>
|
||||
<span class="uc-vip-card__benefit"><i class="fas fa-crown" aria-hidden="true"></i> <?php esc_html_e( '专属身份', 'aksrt' ); ?></span>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="uc-vip-card__benefits">
|
||||
<span class="uc-vip-card__benefit"><i class="fas fa-download" aria-hidden="true"></i> <?php esc_html_e( '解锁免费下载', 'aksrt' ); ?></span>
|
||||
<span class="uc-vip-card__benefit"><i class="fas fa-tag" aria-hidden="true"></i> <?php esc_html_e( '享专属折扣', 'aksrt' ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! $is_vip_user ) : ?>
|
||||
<a href="<?php echo esc_url( aksrt_get_user_center_url( 'credits' ) ); ?>" class="uc-vip-card__btn">
|
||||
<?php esc_html_e( '立即开通', 'aksrt' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $credits_enabled && function_exists('aksrt_is_captcha_enabled_for') && aksrt_is_captcha_enabled_for('signin') ) : ?>
|
||||
<div class="aksrt-signin-captcha" data-signin-captcha style="margin-bottom:16px;">
|
||||
<?php aksrt_render_captcha('signin'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
// 签到日历可视化
|
||||
$signin_dates = [];
|
||||
if ($credits_enabled && class_exists('AKSRT_Signin')) {
|
||||
$signin_log = AKSRT_Signin::get_instance()->get_recent_signins($user_id, 30);
|
||||
$signin_dates = array_map(function ($entry) {
|
||||
return $entry['signin_date'] ?? '';
|
||||
}, $signin_log);
|
||||
$signin_dates = array_filter($signin_dates);
|
||||
}
|
||||
?>
|
||||
<?php if (!empty($signin_dates)) : ?>
|
||||
<div class="uc-signin-calendar" style="margin-bottom:16px;">
|
||||
<h4 class="uc-signin-calendar__title">
|
||||
<i class="fas fa-calendar-alt" aria-hidden="true"></i>
|
||||
<?php esc_html_e('最近 30 天签到', 'aksrt'); ?>
|
||||
</h4>
|
||||
<div data-aksrt-signin-calendar='<?php echo esc_attr(wp_json_encode(array_values($signin_dates))); ?>'></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 积分流水 -->
|
||||
<div class="uc-transactions">
|
||||
<div class="uc-transactions__header">
|
||||
<h3 class="uc-transactions__title">
|
||||
<i class="fas fa-list-ul" aria-hidden="true"></i>
|
||||
<?php echo esc_html( sprintf( __( '%s明细', 'aksrt' ), $currency_name ) ); ?>
|
||||
</h3>
|
||||
</div>
|
||||
<?php
|
||||
$credits_page = max(1, isset($_GET['credits_page']) ? (int) $_GET['credits_page'] : 1);
|
||||
if ( class_exists( 'AKSRT_Credits' ) ) {
|
||||
$log = AKSRT_Credits::get_log( [ 'user_id' => $user_id, 'page' => $credits_page, 'per_page' => 10 ] );
|
||||
} else {
|
||||
$log = [ 'items' => [], 'total' => 0 ];
|
||||
}
|
||||
if ( ! empty( $log['items'] ) ) :
|
||||
?>
|
||||
<div class="uc-transactions__list">
|
||||
<?php foreach ( $log['items'] as $row ) :
|
||||
$delta = (int) $row['delta'];
|
||||
$delta_class = $delta >= 0 ? 'is-positive' : 'is-negative';
|
||||
?>
|
||||
<div class="uc-transactions__item">
|
||||
<div class="uc-transactions__icon <?php echo esc_attr( $delta_class ); ?>">
|
||||
<i class="fas fa-<?php echo $delta >= 0 ? 'arrow-up' : 'arrow-down'; ?>" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="uc-transactions__info">
|
||||
<div class="uc-transactions__reason">
|
||||
<?php echo esc_html( aksrt_credits_label( (string) $row['reason'] ) ); ?>
|
||||
<?php if ( ! empty( $row['remark'] ) ) : ?>
|
||||
<span class="uc-transactions__remark">(<?php echo esc_html( (string) $row['remark'] ); ?>)</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="uc-transactions__time">
|
||||
<?php echo esc_html( get_date_from_gmt( (string) $row['created_at'], 'Y-m-d H:i' ) ); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uc-transactions__amount">
|
||||
<span class="uc-transactions__delta <?php echo esc_attr( $delta_class ); ?>">
|
||||
<?php echo esc_html( ( $delta > 0 ? '+' : '' ) . $delta ); ?>
|
||||
</span>
|
||||
<span class="uc-transactions__balance">
|
||||
<?php
|
||||
/* translators: %s: 余额 */
|
||||
printf( esc_html__( '余额 %s', 'aksrt' ), esc_html( (string) (int) $row['balance_after'] ) );
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php
|
||||
$total_pages = (int) ceil( (int) ($log['total'] ?? 0) / 10 );
|
||||
if ( $total_pages > 1 ) {
|
||||
aksrt_render_profile_pagination( $total_pages, $credits_page, 'credits_page' );
|
||||
}
|
||||
?>
|
||||
<?php else : ?>
|
||||
<div class="uc-transactions__empty">
|
||||
<div class="uc-transactions__empty-icon">
|
||||
<i class="fas fa-receipt" aria-hidden="true"></i>
|
||||
</div>
|
||||
<p><?php echo esc_html( sprintf( __( '还没有任何%s流水', 'aksrt' ), $currency_name ) ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* User center profile favorites part.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
?>
|
||||
<!-- ==================== 我的收藏 ==================== -->
|
||||
<div class="widget-card">
|
||||
<div class="profile-list-header">
|
||||
<h3 class="widget-title widget-title--inline">
|
||||
<?php printf( esc_html__( '我的收藏(%d 篇)', 'aksrt' ), $favorite_count ); ?>
|
||||
</h3>
|
||||
</div>
|
||||
<?php if ( ! empty( $favorite_post_ids ) ) :
|
||||
$favorites_query = new WP_Query( [
|
||||
'post_type' => 'post',
|
||||
'post_status' => 'publish',
|
||||
'post__in' => $favorite_post_ids,
|
||||
'orderby' => 'post__in',
|
||||
'posts_per_page' => $per_page,
|
||||
'paged' => $favorites_page,
|
||||
'ignore_sticky_posts' => true,
|
||||
'no_found_rows' => false,
|
||||
'update_post_meta_cache' => false,
|
||||
] );
|
||||
if ( $favorites_query->have_posts() ) : ?>
|
||||
<div class="profile-list" data-list="favorites">
|
||||
<?php while ( $favorites_query->have_posts() ) : $favorites_query->the_post();
|
||||
get_template_part('templates/parts/content', 'profile-list-item', [
|
||||
'action' => [
|
||||
'type' => 'unfavorite',
|
||||
'url' => '#',
|
||||
'label' => __('取消收藏', 'aksrt'),
|
||||
],
|
||||
]);
|
||||
endwhile; ?>
|
||||
</div>
|
||||
<?php aksrt_render_profile_pagination( (int) $favorites_query->max_num_pages, $favorites_page, 'favorites_page' ); ?>
|
||||
<?php
|
||||
wp_reset_postdata();
|
||||
else :
|
||||
aksrt_render_profile_empty(
|
||||
$svg_empty_favorite,
|
||||
__( '收藏列表为空', 'aksrt' ),
|
||||
__( '点击文章页面的星标收藏喜欢的内容。', 'aksrt' ),
|
||||
home_url( '/' ),
|
||||
__( '去发现好文', 'aksrt' )
|
||||
);
|
||||
endif;
|
||||
else :
|
||||
aksrt_render_profile_empty(
|
||||
$svg_empty_favorite,
|
||||
__( '收藏列表为空', 'aksrt' ),
|
||||
__( '点击文章页面的星标收藏喜欢的内容。', 'aksrt' ),
|
||||
home_url( '/' ),
|
||||
__( '去发现好文', 'aksrt' )
|
||||
);
|
||||
endif; ?>
|
||||
</div>
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* User center profile form part.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
?>
|
||||
<!-- ==================== 个人信息(可编辑) ==================== -->
|
||||
<form class="profile-form" id="profile-form" method="post">
|
||||
<?php wp_nonce_field( 'aksrt_profile_save', '_profile_nonce' ); ?>
|
||||
<input type="hidden" name="action" value="aksrt_save_profile">
|
||||
<input type="hidden" name="user_id" value="<?php echo (int) $user_id; ?>">
|
||||
|
||||
<!-- 昵称 -->
|
||||
<div class="widget-card">
|
||||
<h3 class="widget-title"><?php esc_html_e( '昵称', 'aksrt' ); ?></h3>
|
||||
<input type="text" name="nickname" id="profile-nickname"
|
||||
value="<?php echo esc_attr( $target_user->display_name ); ?>"
|
||||
class="profile-input" maxlength="50" required>
|
||||
<p class="profile-hint"><?php esc_html_e( '修改后会同步更新个人主页地址', 'aksrt' ); ?></p>
|
||||
</div>
|
||||
|
||||
<!-- 个人简介 -->
|
||||
<div class="widget-card">
|
||||
<h3 class="widget-title"><?php esc_html_e( '个人简介', 'aksrt' ); ?></h3>
|
||||
<textarea name="description" id="profile-bio" class="profile-input profile-textarea"
|
||||
rows="4" maxlength="500" placeholder="<?php esc_attr_e( '介绍一下自己…', 'aksrt' ); ?>"><?php echo esc_textarea( $target_user->description ); ?></textarea>
|
||||
<p class="profile-hint"><?php esc_html_e( '显示在你的公开用户主页上,最多 500 字', 'aksrt' ); ?></p>
|
||||
</div>
|
||||
|
||||
<?php if ( ! empty( $user_center_settings['social_links'] ) ) : ?>
|
||||
<!-- 联系方式 -->
|
||||
<div class="widget-card">
|
||||
<h3 class="widget-title"><?php esc_html_e( '联系方式', 'aksrt' ); ?></h3>
|
||||
<p class="profile-hint profile-hint--top"><?php esc_html_e( '添加你的社交链接,显示在公开用户主页', 'aksrt' ); ?></p>
|
||||
<div id="contacts-list">
|
||||
<?php foreach ( $user_contacts as $i => $contact ) : ?>
|
||||
<div class="contact-row" data-index="<?php echo (int) $i; ?>">
|
||||
<select name="contacts[<?php echo (int) $i; ?>][icon]" class="profile-input contact-icon">
|
||||
<?php echo aksrt_contact_icon_options( $contact['icon'] ?? '' ); ?>
|
||||
</select>
|
||||
<input type="hidden" name="contacts[<?php echo (int) $i; ?>][name]" value="">
|
||||
<input type="url" name="contacts[<?php echo (int) $i; ?>][url]"
|
||||
value="<?php echo esc_url( $contact['url'] ?? '' ); ?>"
|
||||
class="profile-input contact-url" placeholder="<?php esc_attr_e( '链接 URL', 'aksrt' ); ?>">
|
||||
<button type="button" class="contact-remove" onclick="this.parentElement.remove()" title="<?php esc_attr_e( '删除', 'aksrt' ); ?>">×</button>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<button type="button" class="btn-ghost btn-sm profile-add-contact" id="add-contact-btn">+ <?php esc_html_e( '添加联系方式', 'aksrt' ); ?></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 保存按钮 -->
|
||||
<div class="profile-form__submit">
|
||||
<button type="submit" class="btn-primary btn-lg" id="profile-save-btn">
|
||||
<?php esc_html_e( '保存修改', 'aksrt' ); ?>
|
||||
</button>
|
||||
<span id="profile-save-msg" class="profile-form__submit-msg"></span>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* User center profile header part.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
?>
|
||||
<!-- 头图 + 用户卡 -->
|
||||
<div class="uc-header">
|
||||
<div class="uc-header__cover">
|
||||
<img id="aksrt-cover-img" class="uc-header__cover-img" src="<?php echo esc_url( $user_background_url ? $user_background_url : get_theme_file_uri( 'assets/img/person_background.png' ) ); ?>" alt="">
|
||||
<div class="uc-header__cover-mask"></div>
|
||||
<?php if ( $allow_bg_upload ) : ?>
|
||||
<button type="button" class="uc-header__cover-upload" id="aksrt-upload-bg-btn" title="<?php esc_attr_e( '编辑背景图', 'aksrt' ); ?>">
|
||||
<i class="fas fa-pen" aria-hidden="true"></i>
|
||||
<span><?php esc_html_e( '编辑', 'aksrt' ); ?></span>
|
||||
</button>
|
||||
<input type="file" id="aksrt-bg-file-input" accept="image/jpeg,image/png,image/webp,image/gif" style="display:none">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="uc-header__content">
|
||||
<div class="uc-header__avatar">
|
||||
<?php echo get_avatar( $user_id, 120, '', $target_user->display_name ); ?>
|
||||
</div>
|
||||
<div class="uc-header__info">
|
||||
<h1 class="uc-header__name">
|
||||
<?php echo esc_html( $target_user->display_name ); ?>
|
||||
<?php
|
||||
$vip_badge = function_exists('aksrt_render_vip_badge') ? aksrt_render_vip_badge($user_id) : '';
|
||||
if ($vip_badge) echo $vip_badge; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
?>
|
||||
</h1>
|
||||
<?php if ( $target_user->description ) : ?>
|
||||
<p class="uc-header__desc"><?php echo esc_html( $target_user->description ); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $profile_signals ) ) : ?>
|
||||
<div class="aksrt-identity-chips">
|
||||
<?php foreach ( $profile_signals as $signal ) : ?>
|
||||
<span class="aksrt-identity-chip aksrt-identity-chip--<?php echo esc_attr( $signal['tone'] ); ?>">
|
||||
<i class="fas fa-<?php echo esc_attr( $signal['icon'] ); ?>" aria-hidden="true"></i>
|
||||
<span><?php echo esc_html( $signal['label'] ); ?></span>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="uc-header__meta">
|
||||
<span class="uc-header__meta-item" title="<?php esc_attr_e( '用户名', 'aksrt' ); ?>">
|
||||
<i class="fas fa-user" aria-hidden="true"></i> <?php echo esc_html( $target_user->user_login ); ?>
|
||||
</span>
|
||||
<?php if ( $target_user->user_email ) : ?>
|
||||
<span class="uc-header__meta-item" title="<?php esc_attr_e( '邮箱', 'aksrt' ); ?>">
|
||||
<i class="fas fa-envelope" aria-hidden="true"></i> <?php echo esc_html( $target_user->user_email ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="uc-header__actions">
|
||||
<a href="<?php echo esc_url( $messages_url ); ?>" class="btn-ghost btn-sm">
|
||||
<i class="fas fa-bell" aria-hidden="true"></i> <?php esc_html_e( '消息通知', 'aksrt' ); ?>
|
||||
<?php if ( $notification_unread_count > 0 ) : ?>
|
||||
<span class="uc-header__action-badge"><?php echo esc_html( (string) $notification_unread_count ); ?></span>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
<?php if ( $show_avatar_edit ) : ?>
|
||||
<a href="<?php echo esc_url( $avatar_settings_url ); ?>" class="btn-ghost btn-sm">
|
||||
<i class="fas fa-camera" aria-hidden="true"></i> <?php esc_html_e( '更换头像', 'aksrt' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<a href="<?php echo esc_url( aksrt_get_user_home_url() ); ?>" class="btn-ghost btn-sm">
|
||||
<i class="fas fa-map-marker-alt" aria-hidden="true"></i> <?php esc_html_e( '我的主页', 'aksrt' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/**
|
||||
* User center profile posts part.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
?>
|
||||
<!-- ==================== 我的文章 ==================== -->
|
||||
<div class="widget-card">
|
||||
<div class="profile-list-header">
|
||||
<h3 class="widget-title widget-title--inline">
|
||||
<?php
|
||||
/* translators: %d: post count */
|
||||
printf( esc_html__( '我的文章(%d 篇)', 'aksrt' ), $post_count );
|
||||
?>
|
||||
</h3>
|
||||
<?php
|
||||
$status_chip_defs = [
|
||||
'publish' => __( '已发布', 'aksrt' ),
|
||||
'draft' => __( '草稿', 'aksrt' ),
|
||||
'pending' => __( '待审', 'aksrt' ),
|
||||
'private' => __( '私密', 'aksrt' ),
|
||||
'all' => __( '全部', 'aksrt' ),
|
||||
];
|
||||
?>
|
||||
<div class="profile-status-filter" role="tablist" aria-label="<?php esc_attr_e( '文章状态筛选', 'aksrt' ); ?>">
|
||||
<?php foreach ( $status_chip_defs as $status_key => $status_text ) :
|
||||
$count_for_chip = ( 'all' === $status_key )
|
||||
? $post_count
|
||||
: ( $user_status_counts[ $status_key ] ?? 0 );
|
||||
if ( 'publish' !== $status_key && 'all' !== $status_key && $count_for_chip < 1 ) {
|
||||
continue;
|
||||
}
|
||||
$chip_url = add_query_arg( [
|
||||
'tab' => 'posts',
|
||||
'post_status' => $status_key,
|
||||
'posts_page' => 1,
|
||||
], remove_query_arg( [ 'posts_page' ] ) );
|
||||
$chip_active = ( $post_status_filter === $status_key );
|
||||
?>
|
||||
<a href="<?php echo esc_url( $chip_url ); ?>" class="profile-status-chip<?php echo $chip_active ? ' is-active' : ''; ?>" role="tab" aria-selected="<?php echo $chip_active ? 'true' : 'false'; ?>">
|
||||
<?php echo esc_html( $status_text ); ?>
|
||||
<span class="profile-status-chip__count"><?php echo esc_html( (string) $count_for_chip ); ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$ps_args = [
|
||||
'author' => $user_id,
|
||||
'post_status' => ( 'all' === $post_status_filter )
|
||||
? [ 'publish', 'draft', 'pending', 'private' ]
|
||||
: $post_status_filter,
|
||||
'posts_per_page' => $per_page,
|
||||
'paged' => $posts_page,
|
||||
'no_found_rows' => false,
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => true,
|
||||
];
|
||||
$q = new WP_Query( $ps_args );
|
||||
if ( $q->have_posts() ) : ?>
|
||||
<div class="profile-list">
|
||||
<?php while ( $q->have_posts() ) : $q->the_post();
|
||||
$st = get_post_status();
|
||||
$status_label = '';
|
||||
if ( 'publish' !== $st ) {
|
||||
$st_map = [
|
||||
'draft' => __( '草稿', 'aksrt' ),
|
||||
'pending' => __( '待审', 'aksrt' ),
|
||||
'private' => __( '私密', 'aksrt' ),
|
||||
'future' => __( '定时', 'aksrt' ),
|
||||
];
|
||||
$status_label = $st_map[ $st ] ?? $st;
|
||||
}
|
||||
|
||||
$edit_link = get_edit_post_link();
|
||||
get_template_part('templates/parts/content', 'profile-list-item', [
|
||||
'action' => $edit_link ? ['type' => 'edit', 'url' => $edit_link, 'label' => __('编辑', 'aksrt')] : [],
|
||||
'status' => $status_label,
|
||||
]);
|
||||
endwhile; ?>
|
||||
</div>
|
||||
<?php aksrt_render_profile_pagination( (int) $q->max_num_pages, $posts_page, 'posts_page' ); ?>
|
||||
<?php
|
||||
wp_reset_postdata();
|
||||
else :
|
||||
aksrt_render_profile_empty(
|
||||
$svg_empty_post,
|
||||
__( '还没有文章', 'aksrt' ),
|
||||
__( '试试发布你的第一篇文章吧。', 'aksrt' ),
|
||||
admin_url( 'post-new.php' ),
|
||||
__( '写文章', 'aksrt' )
|
||||
);
|
||||
endif; ?>
|
||||
</div>
|
||||
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
/**
|
||||
* User center profile settings part.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
?>
|
||||
<!-- ==================== 账号设置 ==================== -->
|
||||
<?php
|
||||
$oauth = AKSRT_OAuth::get_instance();
|
||||
$oauth_data = $oauth->get_frontend_bindings_data($user_id);
|
||||
$user_email = $target_user->user_email ?: '';
|
||||
$binding_name_map = [
|
||||
'github' => 'GitHub',
|
||||
'gitee' => 'Gitee',
|
||||
'qq' => 'QQ',
|
||||
'google' => 'Google',
|
||||
];
|
||||
$binding_rows = [];
|
||||
foreach ( (array) ( $oauth_data['bindings'] ?? [] ) as $binding ) {
|
||||
$key = $binding['key'] ?? '';
|
||||
if ( ! $key ) continue;
|
||||
$binding_rows[ $key ] = [
|
||||
'key' => $key,
|
||||
'name' => $binding_name_map[ $key ] ?? ( $binding['name'] ?? ucfirst( $key ) ),
|
||||
'icon' => $binding['icon'] ?? '',
|
||||
'is_bound' => true,
|
||||
'url' => '',
|
||||
];
|
||||
}
|
||||
foreach ( (array) ( $oauth_data['available'] ?? [] ) as $binding ) {
|
||||
$key = $binding['key'] ?? '';
|
||||
if ( ! $key ) continue;
|
||||
$binding_rows[ $key ] = [
|
||||
'key' => $key,
|
||||
'name' => $binding_name_map[ $key ] ?? ( $binding['name'] ?? ucfirst( $key ) ),
|
||||
'icon' => $binding['icon'] ?? '',
|
||||
'is_bound' => false,
|
||||
'url' => $binding['url'] ?? '',
|
||||
];
|
||||
}
|
||||
?>
|
||||
|
||||
<!-- 第三方绑定区域 -->
|
||||
<div class="settings-section">
|
||||
<div class="settings-section__header">
|
||||
<span class="settings-icon"><i class="fas fa-link" aria-hidden="true"></i></span>
|
||||
<h3 class="widget-title settings-section__title"><?php esc_html_e( '社交账号绑定', 'aksrt' ); ?></h3>
|
||||
</div>
|
||||
|
||||
<?php if ( ! empty( $binding_rows ) ) : ?>
|
||||
<p class="settings-hint settings-hint--top"><?php esc_html_e( '点击下方按钮管理第三方账号绑定状态:', 'aksrt' ); ?></p>
|
||||
<div class="binding-list">
|
||||
<?php foreach ( $binding_rows as $binding ) : ?>
|
||||
<?php if ( ! empty( $binding['is_bound'] ) ) : ?>
|
||||
<div class="binding-item">
|
||||
<span class="binding-item__icon"><?php echo $binding['icon']; ?></span>
|
||||
<span class="binding-item__meta">
|
||||
<span class="binding-status">
|
||||
<i class="fas fa-check-circle badge__icon" aria-hidden="true"></i>
|
||||
<?php esc_html_e( '已绑定', 'aksrt' ); ?>
|
||||
</span>
|
||||
<span class="binding-item__name"><?php echo esc_html( $binding['name'] ); ?></span>
|
||||
</span>
|
||||
<button type="button" class="binding-unbind-btn" data-provider="<?php echo esc_attr( $binding['key'] ); ?>">
|
||||
<?php esc_html_e( '解绑', 'aksrt' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<a href="<?php echo esc_url( $binding['url'] ); ?>" class="binding-item binding-item--linkable" target="_self">
|
||||
<span class="binding-item__icon"><?php echo $binding['icon']; ?></span>
|
||||
<span class="binding-item__meta">
|
||||
<span class="binding-status binding-status--idle"><?php esc_html_e( '未绑定', 'aksrt' ); ?></span>
|
||||
<span class="binding-item__name"><?php echo esc_html( $binding['name'] ); ?></span>
|
||||
</span>
|
||||
<span class="badge badge--bind"><?php esc_html_e( '绑定', 'aksrt' ); ?></span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<p class="settings-empty"><?php esc_html_e( '暂无可用的第三方登录服务', 'aksrt' ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- 安全设置区域 -->
|
||||
<div class="settings-section">
|
||||
<div class="settings-section__header">
|
||||
<span class="settings-icon"><i class="fas fa-lock" aria-hidden="true"></i></span>
|
||||
<h3 class="widget-title settings-section__title"><?php esc_html_e( '安全设置', 'aksrt' ); ?></h3>
|
||||
</div>
|
||||
<div class="security-actions">
|
||||
<!-- 修改密码 -->
|
||||
<div class="security-action-item">
|
||||
<div class="security-action-info">
|
||||
<span class="security-action-icon"><i class="fas fa-lock" aria-hidden="true"></i></span>
|
||||
<div class="security-action-text">
|
||||
<span class="security-action-title"><?php esc_html_e( '修改密码', 'aksrt' ); ?></span>
|
||||
<span class="security-action-desc"><?php esc_html_e( '通过邮箱验证码验证后可更改登录密码', 'aksrt' ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn-primary btn-sm security-trigger" data-modal="pwd-modal">
|
||||
<?php esc_html_e( '修改', 'aksrt' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
<!-- 更改邮箱 -->
|
||||
<div class="security-action-item">
|
||||
<div class="security-action-info">
|
||||
<span class="security-action-icon"><i class="far fa-envelope" aria-hidden="true"></i></span>
|
||||
<div class="security-action-text">
|
||||
<span class="security-action-title"><?php esc_html_e( '更改邮箱', 'aksrt' ); ?></span>
|
||||
<span class="security-action-desc"><?php esc_html_e( '更新用于接收通知和找回密码的邮箱地址', 'aksrt' ); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn-primary btn-sm security-trigger" data-modal="email-modal">
|
||||
<?php esc_html_e( '更改', 'aksrt' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( $show_invite_section ) : ?>
|
||||
<div class="settings-section">
|
||||
<div class="settings-section__header">
|
||||
<span class="settings-icon"><i class="fas fa-user-plus" aria-hidden="true"></i></span>
|
||||
<h3 class="widget-title settings-section__title"><?php esc_html_e( '邀请好友', 'aksrt' ); ?></h3>
|
||||
</div>
|
||||
<div class="aksrt-invite-panel" data-aksrt-invite>
|
||||
<div class="aksrt-invite-hero">
|
||||
<div class="aksrt-invite-hero__main">
|
||||
<span class="aksrt-invite-kicker"><?php esc_html_e( '邀请奖励', 'aksrt' ); ?></span>
|
||||
<p class="aksrt-invite-desc">
|
||||
<?php echo esc_html( sprintf( __( '将专属链接分享给好友,好友完成注册与验证后即可获得双向%s奖励。', 'aksrt' ), $currency_name ) ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<div class="aksrt-invite-code-card">
|
||||
<span><?php esc_html_e( '邀请码', 'aksrt' ); ?></span>
|
||||
<strong data-invite-code>--</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aksrt-invite-link-row">
|
||||
<input type="text" class="aksrt-invite-link" data-invite-link readonly value="" aria-label="<?php esc_attr_e( '邀请链接', 'aksrt' ); ?>">
|
||||
<button type="button" class="btn-primary btn-sm aksrt-invite-copy" data-invite-copy>
|
||||
<i class="fas fa-copy" aria-hidden="true"></i>
|
||||
<span><?php esc_html_e( '复制链接', 'aksrt' ); ?></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="aksrt-invite-stats" data-invite-stats>
|
||||
<div class="aksrt-invite-stat">
|
||||
<span><?php esc_html_e( '已注册', 'aksrt' ); ?></span>
|
||||
<strong data-stat="registered">0</strong>
|
||||
<small><?php esc_html_e( '通过链接完成注册', 'aksrt' ); ?></small>
|
||||
</div>
|
||||
<div class="aksrt-invite-stat">
|
||||
<span><?php esc_html_e( '已验证', 'aksrt' ); ?></span>
|
||||
<strong data-stat="verified">0</strong>
|
||||
<small><?php esc_html_e( '完成邮箱验证', 'aksrt' ); ?></small>
|
||||
</div>
|
||||
<div class="aksrt-invite-stat">
|
||||
<span><?php esc_html_e( '已奖励', 'aksrt' ); ?></span>
|
||||
<strong data-stat="rewarded">0</strong>
|
||||
<small><?php esc_html_e( '奖励已发放', 'aksrt' ); ?></small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aksrt-invite-records">
|
||||
<div class="aksrt-invite-records__header">
|
||||
<h4><?php esc_html_e( '邀请记录', 'aksrt' ); ?></h4>
|
||||
<span data-invite-total><?php esc_html_e( '加载中', 'aksrt' ); ?></span>
|
||||
</div>
|
||||
<div class="aksrt-invite-record-list is-loading" data-invite-list>
|
||||
<div class="aksrt-invite-record-empty">
|
||||
<?php esc_html_e( '正在加载邀请记录...', 'aksrt' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 隐藏字段 -->
|
||||
<input type="hidden" id="aksrt-settings-nonce" value="<?php echo wp_create_nonce( 'aksrt_account_settings' ); ?>">
|
||||
<input type="hidden" id="aksrt-oauth-unbind-nonce" value="<?php echo wp_create_nonce( 'aksrt_oauth_unbind' ); ?>">
|
||||
<input type="hidden" id="aksrt-user-email" value="<?php echo esc_attr( $user_email ); ?>">
|
||||
<input type="hidden" id="aksrt-ajax-url" value="<?php echo admin_url( 'admin-ajax.php' ); ?>">
|
||||
<input type="hidden" id="aksrt-login-url" value="<?php echo esc_attr( aksrt_get_login_url() ); ?>">
|
||||
<input type="hidden" id="aksrt-public-nonce" value="<?php echo wp_create_nonce( 'aksrt_public_nonce' ); ?>">
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* User center profile sidebar part.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
?>
|
||||
<!-- 数据统计 -->
|
||||
<div class="uc-sidebar__section">
|
||||
<div class="uc-sidebar__title"><?php esc_html_e( '数据统计', 'aksrt' ); ?></div>
|
||||
<div class="uc-stats">
|
||||
<?php foreach ( [ 'posts', 'comments', 'favorites' ] as $stat_tab ) : ?>
|
||||
<?php if ( ! isset( $dashboard_tabs[ $stat_tab ] ) ) { continue; } ?>
|
||||
<?php
|
||||
$stat_count = 'posts' === $stat_tab
|
||||
? $post_count
|
||||
: ( 'comments' === $stat_tab ? $comment_count : $favorite_count );
|
||||
?>
|
||||
<a class="uc-stats__item" href="<?php echo esc_url( add_query_arg( 'tab', $stat_tab, remove_query_arg( 'tab' ) ) ); ?>">
|
||||
<span class="uc-stats__value"><?php echo esc_html( (string) $stat_count ); ?></span>
|
||||
<span class="uc-stats__label"><?php echo esc_html( $dashboard_tabs[ $stat_tab ]['label'] ); ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
<a class="uc-stats__item" href="<?php echo esc_url( $messages_url ); ?>">
|
||||
<span class="uc-stats__value"><?php echo esc_html( (string) $notification_unread_count ); ?></span>
|
||||
<span class="uc-stats__label"><?php esc_html_e( '通知', 'aksrt' ); ?></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 我的服务 -->
|
||||
<div class="uc-sidebar__section">
|
||||
<div class="uc-sidebar__title"><?php esc_html_e( '我的服务', 'aksrt' ); ?></div>
|
||||
<div class="uc-sidebar__buttons">
|
||||
<?php foreach ( $dashboard_tabs as $tab_key => $tab ) : ?>
|
||||
<a class="uc-sidebar__btn<?php echo $active_tab === $tab_key ? ' is-active' : ''; ?>" href="<?php echo esc_url(aksrt_get_user_center_tab_url($tab_key)); ?>" data-tab="<?php echo esc_attr($tab_key); ?>">
|
||||
<i class="fas fa-<?php echo esc_attr( $tab['icon'] ); ?>" aria-hidden="true"></i>
|
||||
<span><?php echo esc_html( $tab['label'] ); ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
<a href="<?php echo esc_url( $messages_url ); ?>" class="uc-sidebar__btn">
|
||||
<i class="fas fa-bell" aria-hidden="true"></i>
|
||||
<span><?php esc_html_e( '消息通知', 'aksrt' ); ?></span>
|
||||
<?php if ( $notification_unread_count > 0 ) : ?>
|
||||
<span class="uc-sidebar__badge"><?php echo esc_html( (string) $notification_unread_count ); ?></span>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 交易服务 -->
|
||||
|
||||
<?php if ($orders_url || $show_vip || $show_credit_tabs) : ?>
|
||||
<div class="uc-sidebar__section">
|
||||
<div class="uc-sidebar__title"><?php esc_html_e('权益与消费', 'aksrt'); ?></div>
|
||||
<div class="uc-sidebar__buttons">
|
||||
<?php if ($orders_url) : ?>
|
||||
<a href="<?php echo esc_url($orders_url); ?>" class="uc-sidebar__btn">
|
||||
<i class="fas fa-receipt" aria-hidden="true"></i>
|
||||
<span><?php esc_html_e('我的订单', 'aksrt'); ?></span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if ($show_vip) : ?>
|
||||
<a class="uc-sidebar__btn<?php echo $active_tab === 'credits' ? ' is-active' : ''; ?>" href="<?php echo esc_url(aksrt_get_user_center_tab_url('credits')); ?>" data-tab="credits">
|
||||
<i class="fas fa-crown" aria-hidden="true"></i>
|
||||
<span><?php esc_html_e('VIP 会员', 'aksrt'); ?></span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if ($show_credit_tabs) : ?>
|
||||
<a class="uc-sidebar__btn<?php echo $active_tab === 'credits' ? ' is-active' : ''; ?>" href="<?php echo esc_url(aksrt_get_user_center_tab_url('credits')); ?>" data-tab="credits">
|
||||
<i class="fas fa-coins" aria-hidden="true"></i>
|
||||
<span><?php echo esc_html($currency_name); ?></span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if ($affiliate_enabled) : ?>
|
||||
<a class="uc-sidebar__btn<?php echo $active_tab === 'credits' ? ' is-active' : ''; ?>" href="<?php echo esc_url(aksrt_get_user_center_tab_url('credits')); ?>" data-tab="credits">
|
||||
<i class="fas fa-share-alt" aria-hidden="true"></i>
|
||||
<span><?php esc_html_e('推广返佣', 'aksrt'); ?></span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 功能设置 -->
|
||||
<!-- 移动端抽屉触发器 -->
|
||||
<button type="button" class="uc-sidebar__drawer-trigger" id="uc-drawer-trigger" aria-label="<?php esc_attr_e( '打开导航', 'aksrt' ); ?>">
|
||||
<i class="fas fa-bars" aria-hidden="true"></i>
|
||||
</button>
|
||||
+44
-1389
File diff suppressed because it is too large
Load Diff
@@ -174,20 +174,19 @@ $home_url = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url
|
||||
<div class="profile-list">
|
||||
<?php while ($author_posts->have_posts()) : $author_posts->the_post(); ?>
|
||||
<?php
|
||||
set_query_var('aksrt_profile_item_action', [
|
||||
'type' => 'view',
|
||||
'url' => get_permalink(),
|
||||
'label' => __('阅读', 'aksrt'),
|
||||
]);
|
||||
set_query_var('aksrt_profile_item_status', '');
|
||||
get_template_part('templates/parts/content', 'profile-list-item');
|
||||
get_template_part('templates/parts/content', 'profile-list-item', [
|
||||
'action' => [
|
||||
'type' => 'view',
|
||||
'url' => get_permalink(),
|
||||
'label' => __('阅读', 'aksrt'),
|
||||
],
|
||||
]);
|
||||
?>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<?php
|
||||
aksrt_render_profile_pagination((int) $author_posts->max_num_pages, $posts_page, 'posts_page');
|
||||
wp_reset_postdata();
|
||||
set_query_var('aksrt_profile_item_action', []);
|
||||
else :
|
||||
aksrt_render_profile_empty($svg_empty_post, __('TA 还没有发布文章', 'aksrt'));
|
||||
endif;
|
||||
@@ -211,11 +210,9 @@ $home_url = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url
|
||||
<div class="profile-comment-list">
|
||||
<?php foreach ($user_comments as $c) : ?>
|
||||
<?php
|
||||
set_query_var('aksrt_profile_comment', $c);
|
||||
get_template_part('templates/parts/content', 'profile-comment-item');
|
||||
get_template_part('templates/parts/content', 'profile-comment-item', ['comment' => $c]);
|
||||
?>
|
||||
<?php endforeach; ?>
|
||||
<?php set_query_var('aksrt_profile_comment', null); ?>
|
||||
</div>
|
||||
<?php
|
||||
$cm_total_pages = (int) ceil($comment_count / $per_page);
|
||||
@@ -247,20 +244,19 @@ $home_url = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url
|
||||
<div class="profile-list">
|
||||
<?php while ($favorites_query->have_posts()) : $favorites_query->the_post(); ?>
|
||||
<?php
|
||||
set_query_var('aksrt_profile_item_action', [
|
||||
'type' => 'view',
|
||||
'url' => get_permalink(),
|
||||
'label' => __('阅读', 'aksrt'),
|
||||
get_template_part('templates/parts/content', 'profile-list-item', [
|
||||
'action' => [
|
||||
'type' => 'view',
|
||||
'url' => get_permalink(),
|
||||
'label' => __('阅读', 'aksrt'),
|
||||
],
|
||||
]);
|
||||
set_query_var('aksrt_profile_item_status', '');
|
||||
get_template_part('templates/parts/content', 'profile-list-item');
|
||||
?>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<?php
|
||||
aksrt_render_profile_pagination((int) $favorites_query->max_num_pages, $favorites_page, 'favorites_page');
|
||||
wp_reset_postdata();
|
||||
set_query_var('aksrt_profile_item_action', []);
|
||||
else :
|
||||
aksrt_render_profile_empty($svg_empty_favorite, __('TA 还没有收藏文章', 'aksrt'));
|
||||
endif;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Profile Comment List Item — image-less comment row for user center.
|
||||
*
|
||||
* 通过 set_query_var() 接收:
|
||||
* 通过 get_template_part() 的 $args 接收(保留 query var 兼容):
|
||||
* - aksrt_profile_comment: WP_Comment 对象
|
||||
*
|
||||
* @package AKSRT
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$comment = get_query_var('aksrt_profile_comment');
|
||||
$comment = $args['comment'] ?? get_query_var('aksrt_profile_comment');
|
||||
if (!$comment instanceof WP_Comment) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* 用于:
|
||||
* - 我的文章 / 我的收藏 / 公开主页文章列表
|
||||
*
|
||||
* 通过 set_query_var() 接收以下参数(可选):
|
||||
* 通过 get_template_part() 的 $args 接收以下参数(保留 query var 兼容):
|
||||
* - aksrt_profile_item_action: ['type'=>'edit'|'view'|'unfavorite', 'url'=>'...', 'label'=>'...']
|
||||
* - aksrt_profile_item_status: 文章状态徽章文本(如 "草稿" / "私密")
|
||||
*
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$action = get_query_var('aksrt_profile_item_action', []);
|
||||
$action = isset($args['action']) ? $args['action'] : get_query_var('aksrt_profile_item_action', []);
|
||||
if (!is_array($action)) {
|
||||
$action = [];
|
||||
}
|
||||
@@ -22,7 +22,7 @@ $action_type = isset($action['type']) ? (string) $action['type'] : '';
|
||||
$action_url = isset($action['url']) ? (string) $action['url'] : '';
|
||||
$action_label = isset($action['label']) ? (string) $action['label'] : '';
|
||||
|
||||
$status_label = (string) get_query_var('aksrt_profile_item_status', '');
|
||||
$status_label = isset($args['status']) ? (string) $args['status'] : (string) get_query_var('aksrt_profile_item_status', '');
|
||||
|
||||
$post_id = get_the_ID();
|
||||
$permalink = get_permalink();
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
/** User center account modals. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
echo $context['account_modals_html'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
/** User center header. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
echo $context['header_html'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
/** User center mobile tabs. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
?>
|
||||
<div class="dashboard-tabs uc-mobile-tabs" role="tablist">
|
||||
<?php foreach (($context['mobile_tabs'] ?? []) as $tab) : ?>
|
||||
<a class="<?php echo !empty($tab['is_active']) ? 'is-active' : ''; ?>" href="<?php echo esc_url($tab['url']); ?>" data-tab="<?php echo esc_attr($tab['key']); ?>" role="tab" aria-selected="<?php echo !empty($tab['is_active']) ? 'true' : 'false'; ?>"><?php echo esc_html($tab['label']); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/** User center comments panel. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$panel = is_array($args['panel'] ?? null) ? $args['panel'] : [];
|
||||
?>
|
||||
<div id="panel-<?php echo esc_attr($panel['key'] ?? 'comments'); ?>" class="dashboard-panel<?php echo !empty($panel['is_active']) ? ' is-active' : ''; ?>" role="tabpanel"<?php echo empty($panel['is_active']) ? ' hidden' : ''; ?> data-panel-loaded="<?php echo !empty($panel['is_loaded']) ? 'true' : 'false'; ?>" data-tab-url="<?php echo esc_url($panel['url'] ?? ''); ?>">
|
||||
<?php echo $panel['html'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/** User center credits panel. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$panel = is_array($args['panel'] ?? null) ? $args['panel'] : [];
|
||||
?>
|
||||
<div id="panel-<?php echo esc_attr($panel['key'] ?? 'credits'); ?>" class="dashboard-panel<?php echo !empty($panel['is_active']) ? ' is-active' : ''; ?>" role="tabpanel"<?php echo empty($panel['is_active']) ? ' hidden' : ''; ?> data-panel-loaded="<?php echo !empty($panel['is_loaded']) ? 'true' : 'false'; ?>" data-tab-url="<?php echo esc_url($panel['url'] ?? ''); ?>">
|
||||
<?php echo $panel['html'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/** User center favorites panel. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$panel = is_array($args['panel'] ?? null) ? $args['panel'] : [];
|
||||
?>
|
||||
<div id="panel-<?php echo esc_attr($panel['key'] ?? 'favorites'); ?>" class="dashboard-panel<?php echo !empty($panel['is_active']) ? ' is-active' : ''; ?>" role="tabpanel"<?php echo empty($panel['is_active']) ? ' hidden' : ''; ?> data-panel-loaded="<?php echo !empty($panel['is_loaded']) ? 'true' : 'false'; ?>" data-tab-url="<?php echo esc_url($panel['url'] ?? ''); ?>">
|
||||
<?php echo $panel['html'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/** User center posts panel. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$panel = is_array($args['panel'] ?? null) ? $args['panel'] : [];
|
||||
?>
|
||||
<div id="panel-<?php echo esc_attr($panel['key'] ?? 'posts'); ?>" class="dashboard-panel<?php echo !empty($panel['is_active']) ? ' is-active' : ''; ?>" role="tabpanel"<?php echo empty($panel['is_active']) ? ' hidden' : ''; ?> data-panel-loaded="<?php echo !empty($panel['is_loaded']) ? 'true' : 'false'; ?>" data-tab-url="<?php echo esc_url($panel['url'] ?? ''); ?>">
|
||||
<?php echo $panel['html'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/** User center profile panel. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$panel = is_array($args['panel'] ?? null) ? $args['panel'] : [];
|
||||
?>
|
||||
<div id="panel-<?php echo esc_attr($panel['key'] ?? 'profile'); ?>" class="dashboard-panel<?php echo !empty($panel['is_active']) ? ' is-active' : ''; ?>" role="tabpanel"<?php echo empty($panel['is_active']) ? ' hidden' : ''; ?> data-panel-loaded="<?php echo !empty($panel['is_loaded']) ? 'true' : 'false'; ?>" data-tab-url="<?php echo esc_url($panel['url'] ?? ''); ?>">
|
||||
<?php echo $panel['html'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/** User center settings panel. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$panel = is_array($args['panel'] ?? null) ? $args['panel'] : [];
|
||||
?>
|
||||
<div id="panel-<?php echo esc_attr($panel['key'] ?? 'settings'); ?>" class="dashboard-panel<?php echo !empty($panel['is_active']) ? ' is-active' : ''; ?>" role="tabpanel"<?php echo empty($panel['is_active']) ? ' hidden' : ''; ?> data-panel-loaded="<?php echo !empty($panel['is_loaded']) ? 'true' : 'false'; ?>" data-tab-url="<?php echo esc_url($panel['url'] ?? ''); ?>">
|
||||
<?php echo $panel['html'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* Generic user-center panel wrapper for registered extensions.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$panel = is_array($args['panel'] ?? null) ? $args['panel'] : [];
|
||||
?>
|
||||
<div id="panel-<?php echo esc_attr($panel['key'] ?? 'custom'); ?>" class="dashboard-panel<?php echo !empty($panel['is_active']) ? ' is-active' : ''; ?>" role="tabpanel"<?php echo empty($panel['is_active']) ? ' hidden' : ''; ?> data-panel-loaded="<?php echo !empty($panel['is_loaded']) ? 'true' : 'false'; ?>" data-tab-url="<?php echo esc_url($panel['url'] ?? ''); ?>">
|
||||
<?php echo $panel['html'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
/** User center runtime configuration. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
?>
|
||||
<script>window.aksrtUserCenter=<?php echo wp_json_encode($context['runtime_config'] ?? []); ?>;</script>
|
||||
<?php if (!empty($context['cover_upload_config'])) : ?>
|
||||
<script>window.aksrtAuthorPage=Object.assign({},window.aksrtAuthorPage||{},{coverUpload:<?php echo wp_json_encode($context['cover_upload_config']); ?>});</script>
|
||||
<?php endif; ?>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
/** User center sidebar. @package AKSRT */
|
||||
defined('ABSPATH') || exit;
|
||||
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
||||
echo $context['sidebar_html'] ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
Reference in New Issue
Block a user