The theme was renamed Zibll/子比 → AKSRT → Jio, but upstream branding survived the sweeps in CSS classes, the SVG sprite prefix, a persisted widget field ID, JS events, admin Vue class names, test infrastructure and docblocks. Renames: - zib-widget / zib-widget-wrap / zib-slider → jio-widget-box / jio-widget-box-wrap / jio-slider-box (jio-widget is taken by the modern widget shell, jio-box-* by the card primitives) - zib-partners-scroll + zps-* → jio-partners-scroll + jps-* - zib-combo-info-card + zci-* → jio-combo-info-card + jci-* - zibsvg- → jiosvg-, including the exported picker helpers and the fa-zibsvg- family-prefix guard - zibpay_type → pay_type; the dual-read fallback in PostQuery collapses to a single key - [zibajax="submit"] dropped (no PHP emitter); zib_ajax.success → jio_ajax.success - aks-* admin Vue classes → jio-* - zib_palette() → palette() User-facing vendor traces are gone: the floating "more" button default no longer ships a zibll.com link or 子比主题 marketing copy, the notice widget ships no preset promo entries, and the four 官网教程 links are removed from the post-list admin schema. Test infrastructure renamed to neutral names (docker-compose.reference.yml, Caddyfile, article-baseline.json, modern-widgets-contract.test.cjs) with their DB/volume/env/slug identifiers following. Kept intentionally, documented in tests/fixtures/README.md: the golden fixture reference fingerprint (a SHA-256 record of an external directory, read by validate-widget-golden / generate-widget-golden-fixture / audit-widget-system), the doesNotMatch guards that prove the old tokens are gone, and the reference theme's own meta key in the visual fixtures. No backward-compat or data migration: saved widget configs holding old icon keys or the old field ID silently lose them, per the project's rewrite-over-compatibility rule. Verified: 132/132 node contract tests, php tests/widget-system/run.php (146 assertions), audit-admin-contracts, audit-psr4-paths and validate-widget-golden all green; tracked bundles regenerated and in sync. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
233 lines
8.5 KiB
PHP
233 lines
8.5 KiB
PHP
<?php
|
||
/**
|
||
* Public user-home template context builder.
|
||
*
|
||
* Keeps page-user-home.php as a thin shell that only mounts parts.
|
||
*
|
||
* @package Jio
|
||
*/
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
if (!function_exists('jio_get_user_home_page_context')) {
|
||
/**
|
||
* Build the render context for the public user homepage shell.
|
||
*
|
||
* @param WP_User $user Target user.
|
||
* @return array<string, mixed>
|
||
*/
|
||
function jio_get_user_home_page_context(WP_User $user): array {
|
||
$user_id = (int) $user->ID;
|
||
|
||
$dashboard = function_exists('jio_get_user_dashboard_view')
|
||
? jio_get_user_dashboard_view($user_id, ['viewer_id' => get_current_user_id()])
|
||
: [];
|
||
|
||
$is_own_profile = !empty($dashboard['is_own_profile']);
|
||
$user_home_settings = class_exists('\Jio\Settings\Settings')
|
||
? \Jio\Settings\Settings::get_user_home_settings()
|
||
: [
|
||
'tabs' => ['posts', 'favorites', 'comments', 'follow'],
|
||
'sidebar' => false,
|
||
'cover' => true,
|
||
'follow' => true,
|
||
'posts_per_page' => 10,
|
||
];
|
||
|
||
$post_count = (int) ($dashboard['post_count'] ?? 0);
|
||
$comment_count = (int) ($dashboard['comment_count'] ?? 0);
|
||
$favorite_post_ids = $dashboard['favorite_post_ids'] ?? [];
|
||
$favorite_count = (int) ($dashboard['favorite_count'] ?? 0);
|
||
$profile_details = $dashboard['profile_details'] ?? [];
|
||
$per_page = max(1, (int) ($user_home_settings['posts_per_page'] ?? 10));
|
||
$credits_enabled = !empty($dashboard['credits_enabled']);
|
||
$credit_balance = $dashboard['credit_balance'] ?? 0.0;
|
||
$currency_name = $dashboard['currency_name'] ?? __('积分', 'jio');
|
||
|
||
$user_home_manager = class_exists('\Jio\User\Home') ? \Jio\User\Home::get_instance() : null;
|
||
$visible_tabs = $user_home_manager ? $user_home_manager->get_visible_tabs($is_own_profile) : [];
|
||
|
||
$enabled_tabs = array_keys($visible_tabs);
|
||
if (empty($enabled_tabs)) {
|
||
$enabled_tabs = ['posts', 'comments', 'favorites'];
|
||
}
|
||
|
||
// Apply admin-configured display order.
|
||
$order = $user_home_settings['tabs_order'] ?? [];
|
||
$ordered = [];
|
||
foreach ((array) $order as $tab_key) {
|
||
if (in_array($tab_key, $enabled_tabs, true)) {
|
||
$ordered[] = $tab_key;
|
||
}
|
||
}
|
||
foreach ($enabled_tabs as $tab_key) {
|
||
if (!in_array($tab_key, $ordered, true)) {
|
||
$ordered[] = $tab_key;
|
||
}
|
||
}
|
||
$enabled_tabs = $ordered;
|
||
|
||
$pc_hide = $user_home_settings['tabs_pc_hide'] ?? [];
|
||
$mobile_hide = $user_home_settings['tabs_mobile_hide'] ?? [];
|
||
$enabled_tabs_pc = array_values(array_diff($enabled_tabs, (array) $pc_hide));
|
||
$enabled_tabs_mobile = array_values(array_diff($enabled_tabs, (array) $mobile_hide));
|
||
$is_mobile = function_exists('wp_is_mobile') && wp_is_mobile();
|
||
$display_tabs = $is_mobile ? $enabled_tabs_mobile : $enabled_tabs_pc;
|
||
$default_tab = !empty($display_tabs) ? $display_tabs[0] : $enabled_tabs[0];
|
||
|
||
$empty_svgs = jio_empty_state_svgs();
|
||
|
||
$follow_count = 0;
|
||
if (class_exists('\Jio\User\Follow')) {
|
||
$follow_count = (int) \Jio\User\Follow::get_instance()->get_follower_count($user_id);
|
||
}
|
||
|
||
$tab_counts = [
|
||
'posts' => $post_count,
|
||
'comments' => $comment_count,
|
||
'favorites' => $favorite_count,
|
||
'credits' => $credits_enabled && $is_own_profile ? (int) round((float) $credit_balance) : 0,
|
||
'follow' => $follow_count,
|
||
];
|
||
|
||
$tab_labels = [
|
||
'posts' => __('文章', 'jio'),
|
||
'comments' => __('评论', 'jio'),
|
||
'favorites' => __('收藏', 'jio'),
|
||
'credits' => sprintf(__('我的%s', 'jio'), $currency_name),
|
||
'follow' => __('粉丝', 'jio'), // legacy: 粉丝
|
||
];
|
||
foreach ($visible_tabs as $tab_key => $tab_config) {
|
||
if (!empty($tab_config['label'])) {
|
||
$tab_labels[$tab_key] = (string) $tab_config['label'];
|
||
}
|
||
}
|
||
|
||
$active_tab = $default_tab;
|
||
|
||
$home_url = function_exists('jio_get_user_home_url') ? jio_get_user_home_url($user) : home_url('/');
|
||
|
||
return [
|
||
'user' => $user,
|
||
'user_id' => $user_id,
|
||
'dashboard' => $dashboard,
|
||
'is_own_profile' => $is_own_profile,
|
||
'user_home_settings' => $user_home_settings,
|
||
'profile_details' => $profile_details,
|
||
'post_count' => $post_count,
|
||
'comment_count' => $comment_count,
|
||
'favorite_post_ids' => $favorite_post_ids,
|
||
'favorite_count' => $favorite_count,
|
||
'per_page' => $per_page,
|
||
'credits_enabled' => $credits_enabled,
|
||
'credit_balance' => $credit_balance,
|
||
'currency_name' => $currency_name,
|
||
'enabled_tabs' => $enabled_tabs,
|
||
'tabs_pc_hide' => (array) $pc_hide,
|
||
'tabs_mobile_hide' => (array) $mobile_hide,
|
||
'default_tab' => $default_tab,
|
||
'active_tab' => $active_tab,
|
||
'tab_counts' => $tab_counts,
|
||
'tab_labels' => $tab_labels,
|
||
'home_url' => $home_url,
|
||
'posts_page' => 1,
|
||
'comments_page' => 1,
|
||
'favorites_page' => 1,
|
||
'follow_sub' => 'followers',
|
||
'follow_page' => 1,
|
||
'svg_empty_post' => $empty_svgs['post'],
|
||
'svg_empty_comment' => $empty_svgs['comment'],
|
||
'svg_empty_favorite' => $empty_svgs['favorite'],
|
||
'svg_empty_follow' => $empty_svgs['follow'],
|
||
];
|
||
}
|
||
}
|
||
|
||
if (!function_exists('jio_render_user_home_pagination')) {
|
||
/**
|
||
* 渲染公开用户主页面板的无刷新数字分页(按钮驱动,无 URL 参数)。
|
||
*
|
||
* 复用 .profile-pagination / .page-numbers 既有样式契约。
|
||
*
|
||
* @param int $total_pages 总页数。
|
||
* @param int $current 当前页。
|
||
*/
|
||
function jio_render_user_home_pagination(int $total_pages, int $current): void {
|
||
$total_pages = max(1, $total_pages);
|
||
$current = min(max(1, $current), $total_pages);
|
||
if ($total_pages <= 1) {
|
||
return;
|
||
}
|
||
|
||
$items = [];
|
||
for ($i = 1; $i <= $total_pages; $i++) {
|
||
if ($i === 1 || $i === $total_pages || abs($i - $current) <= 1) {
|
||
$items[] = (string) $i;
|
||
} elseif ($items && end($items) !== '…') {
|
||
$items[] = '…';
|
||
}
|
||
}
|
||
|
||
echo '<nav class="profile-pagination uh-pagination" aria-label="' . esc_attr__('分页', 'jio') . '">';
|
||
if ($current > 1) {
|
||
echo '<button type="button" class="page-numbers" data-uh-page="' . esc_attr((string) ($current - 1)) . '"><span aria-hidden="true">‹</span><span class="screen-reader-text">' . esc_html__('上一页', 'jio') . '</span></button>';
|
||
}
|
||
foreach ($items as $item) {
|
||
if ($item === '…') {
|
||
echo '<span class="page-numbers dots">…</span>';
|
||
continue;
|
||
}
|
||
if ((int) $item === $current) {
|
||
echo '<span class="page-numbers current" aria-current="page">' . esc_html($item) . '</span>';
|
||
continue;
|
||
}
|
||
echo '<button type="button" class="page-numbers" data-uh-page="' . esc_attr($item) . '">' . esc_html($item) . '</button>';
|
||
}
|
||
if ($current < $total_pages) {
|
||
echo '<button type="button" class="page-numbers" data-uh-page="' . esc_attr((string) ($current + 1)) . '"><span aria-hidden="true">›</span><span class="screen-reader-text">' . esc_html__('下一页', 'jio') . '</span></button>';
|
||
}
|
||
echo '</nav>';
|
||
}
|
||
}
|
||
|
||
if (!function_exists('jio_get_user_home_follow_placeholder')) {
|
||
/**
|
||
* Skeleton cards used while the public home follow panel is loading.
|
||
*/
|
||
function jio_get_user_home_follow_placeholder(): string {
|
||
$item = '<div class="author-minicard radius8 flex ac uh-follow__placeholder" aria-hidden="true">'
|
||
. '<div class="avatar-img mr10"><div class="avatar placeholder"></div></div>'
|
||
. '<div class="flex1"><div class="placeholder k1 mb6"></div>'
|
||
. '<i><i class="placeholder s1"></i><i class="placeholder s1 ml10"></i></i></div></div>';
|
||
|
||
return '<div class="uh-follow__list uh-follow__list--placeholder" role="status" aria-label="' . esc_attr__('正在加载', 'jio') . '">'
|
||
. str_repeat($item, 6)
|
||
. '</div>';
|
||
}
|
||
}
|
||
|
||
if (!function_exists('jio_capture_user_home_panel')) {
|
||
/**
|
||
* 捕获公开用户主页面板 body(templates/parts/user-home/panel-{tab}.php)。
|
||
*
|
||
* @param string $tab 面板键名。
|
||
* @param array<string, mixed> $ctx jio_get_user_home_page_context() 上下文。
|
||
* @return string 捕获的 HTML,模板不存在时为空串。
|
||
*/
|
||
function jio_capture_user_home_panel(string $tab, array $ctx): string {
|
||
$template = locate_template(['templates/parts/user-home/panel-' . sanitize_key($tab) . '.php'], false, false);
|
||
if (!$template) {
|
||
return '';
|
||
}
|
||
|
||
// 面板 body 依赖的空态/分页助手位于模板侧共享文件,REST 片段上下文不会自动加载。
|
||
if (!function_exists('jio_render_profile_empty')) {
|
||
require_once JIO_DIR . '/templates/parts/user-shared-helpers.php';
|
||
}
|
||
|
||
ob_start();
|
||
load_template($template, false, $ctx);
|
||
return (string) ob_get_clean();
|
||
}
|
||
}
|