fix(homepage): align shell with zibll and restore post stream

Move header-slider outside main, render fluid zones once, default the
latest stream to plain posts by date, and cut dual-render/perf waste so
published posts and hero/banner structure match the zibll contract.
This commit is contained in:
kate522 committed 2026-07-12 17:49:58 +08:00
1 parent 8be4c5c123
commit 8f19384582
11 files changed
+223 -103

No files matched your search

@@ -644,8 +644,8 @@ trait AKSRT_Scripts_Part_1b {
);
}
// CMS 首页模块系统:仅在首页 + cms 形态加载
$is_cms_home = ($is_home_or_archive && $is_cms_mode) || $is_fixed_homepage;
// Legacy freeform CMS home modules: only for non-fixed CMS archive previews.
$is_cms_home = ($is_home_or_archive && $is_cms_mode) && !$is_fixed_homepage;
// 管理员预览模式(?aksrt_preview=...):无论站点风格都允许加载模块系统资源
$is_preview = is_user_logged_in() && current_user_can('manage_options') && isset($_GET['aksrt_preview']);
@@ -665,6 +665,8 @@ trait AKSRT_Scripts_Part_1b {
}
if ($is_fixed_homepage) {
$enqueue_module('header-components'); // header-slider / hero
$enqueue_module('post-card');
$homepage_css_path = get_template_directory() . '/assets/css/frontend/homepage-fixed.css';
wp_enqueue_style(
'aksrt-homepage-fixed',
@@ -169,9 +169,9 @@ class AKSRT_Settings_Home_Cms {
if (isset($s['home_list1_orderby_option']) && is_array($s['home_list1_orderby_option'])) {
$orderby_option = $s['home_list1_orderby_option'];
}
$default_sort = sanitize_key((string) ($orderby_option['orderby'] ?? $s['homepage_default_sort'] ?? 'modified'));
$default_sort = sanitize_key((string) ($orderby_option['orderby'] ?? $s['homepage_default_sort'] ?? 'date'));
if (!in_array($default_sort, $allowed_sorts, true)) {
$default_sort = 'modified';
$default_sort = 'date';
}
$sort_options_raw = $orderby_option['options'] ?? $s['home_list_sort_options'] ?? [];
if (!is_array($sort_options_raw)) {
@@ -232,13 +232,13 @@ class AKSRT_Settings_Home_Cms {
// AKSRT presentation extras.
'homepage_card_style' => isset($s['homepage_card_style']) ? sanitize_key((string) $s['homepage_card_style']) : 'default',
'homepage_multi_thumb_enabled' => !isset($s['homepage_multi_thumb_enabled']) || !empty($s['homepage_multi_thumb_enabled']),
'homepage_multi_thumb_enabled' => !empty($s['homepage_multi_thumb_enabled']),
'homepage_multi_thumb_min_images' => (int) ($s['homepage_multi_thumb_min_images'] ?? 3),
'homepage_sidebar_mini_enabled' => !isset($s['homepage_sidebar_mini_enabled']) || !empty($s['homepage_sidebar_mini_enabled']),
'homepage_default_view' => isset($s['homepage_default_view']) ? sanitize_key((string) $s['homepage_default_view']) : 'list',
'homepage_sort_ajax_enabled' => !isset($s['homepage_sort_ajax_enabled']) || !empty($s['homepage_sort_ajax_enabled']),
'homepage_sticky_tabs_enabled' => !isset($s['homepage_sticky_tabs_enabled']) || !empty($s['homepage_sticky_tabs_enabled']),
'homepage_content_model' => isset($s['homepage_content_model']) && in_array($s['homepage_content_model'], ['post', 'mixed'], true) ? $s['homepage_content_model'] : 'mixed',
'homepage_content_model' => isset($s['homepage_content_model']) && in_array($s['homepage_content_model'], ['post', 'mixed'], true) ? $s['homepage_content_model'] : 'post',
'home_list_sort_dropdown' => !empty($s['home_list_sort_dropdown']),
'homepage_tab_posts_per_page' => max(1, min(20, (int) ($s['homepage_tab_posts_per_page'] ?? 6))),
'homepage_tab_limit' => max(1, min(12, (int) ($s['homepage_tab_limit'] ?? 4))),
@@ -296,7 +296,7 @@ class AKSRT_Settings_Home_Cms {
public static function homepage_default_sort(): string {
$settings = self::get_homepage_fixed_settings();
return $settings['home_list1_orderby_option']['orderby'] ?? 'modified';
return $settings['home_list1_orderby_option']['orderby'] ?? 'date';
}
public static function homepage_default_view(): string {
+105 -50
View File
@@ -38,21 +38,18 @@ if (!function_exists('aksrt_homepage_get_post_types')) {
* Homepage latest feed post types.
*
* Respects the homepage_content_model setting:
* - 'post': standard posts only
* - 'mixed': posts + resource CPTs (default for existing sites)
* - 'post': standard posts only (default)
* - 'mixed': posts + resource CPTs (explicit opt-in)
*
* @return string[]
*/
function aksrt_homepage_get_post_types(): array {
// Default: plain posts only (zibll main-query feel). Mixed/resource is opt-in.
$content_model = class_exists('AKSRT_Settings')
? AKSRT_Settings::homepage_content_model()
: 'mixed';
: 'post';
if ($content_model === 'post') {
return ['post'];
}
if (function_exists('aksrt_resource_post_types')) {
if ($content_model === 'mixed' && function_exists('aksrt_resource_post_types')) {
return array_values(array_unique(aksrt_resource_post_types()));
}
@@ -206,7 +203,7 @@ if (!function_exists('aksrt_homepage_get_sort_mode')) {
: ['modified', 'date', 'views', 'likes', 'comments', 'favorites', 'downloads', 'rand'];
$default_sort = class_exists('AKSRT_Settings')
? AKSRT_Settings::homepage_default_sort()
: 'modified';
: 'date';
$override_sort = get_query_var('aksrt_homepage_sort_override');
$sort = is_string($override_sort) && $override_sort !== ''
? sanitize_key($override_sort)
@@ -253,30 +250,44 @@ if (!function_exists('aksrt_homepage_apply_sort_args')) {
function aksrt_homepage_apply_sort_args(array $args): array {
$sort_mode = aksrt_homepage_get_sort_mode();
// Meta sorts: keep posts without the meta key via OR NOT EXISTS so lists never collapse empty.
$apply_meta_sort = static function (array $args, string $meta_key): array {
$args['meta_key'] = $meta_key;
$args['orderby'] = [
'meta_value_num' => 'DESC',
'date' => 'DESC',
];
$args['meta_query'] = [
'relation' => 'OR',
[
'key' => $meta_key,
'compare' => 'EXISTS',
],
[
'key' => $meta_key,
'compare' => 'NOT EXISTS',
],
];
return $args;
};
switch ($sort_mode) {
case 'date':
$args['orderby'] = 'date';
case 'modified':
$args['orderby'] = 'modified';
$args['order'] = 'DESC';
break;
case 'downloads':
$args['meta_key'] = '_aksrt_res_download_count';
$args['orderby'] = 'meta_value_num';
$args['order'] = 'DESC';
$args = $apply_meta_sort($args, '_aksrt_res_download_count');
break;
case 'views':
$args['meta_key'] = 'aksrt_post_views';
$args['orderby'] = 'meta_value_num';
$args['order'] = 'DESC';
// Canonical public views key (align hotspot consumers later).
$args = $apply_meta_sort($args, 'aksrt_post_views');
break;
case 'likes':
$args['meta_key'] = '_aksrt_like_count';
$args['orderby'] = 'meta_value_num';
$args['order'] = 'DESC';
$args = $apply_meta_sort($args, '_aksrt_like_count');
break;
case 'favorites':
$args['meta_key'] = '_aksrt_favorite_count';
$args['orderby'] = 'meta_value_num';
$args['order'] = 'DESC';
$args = $apply_meta_sort($args, '_aksrt_favorite_count');
break;
case 'comments':
$args['orderby'] = 'comment_count';
@@ -286,9 +297,9 @@ if (!function_exists('aksrt_homepage_apply_sort_args')) {
$args['orderby'] = 'rand';
unset($args['order']);
break;
case 'modified':
case 'date':
default:
$args['orderby'] = 'modified';
$args['orderby'] = 'date';
$args['order'] = 'DESC';
break;
}
@@ -400,11 +411,12 @@ if (!function_exists('aksrt_homepage_get_latest_query')) {
$query_args = [
'post_type' => aksrt_homepage_get_post_types(),
'post_status' => 'publish',
'posts_per_page' => (int) get_option('posts_per_page'),
'posts_per_page' => max(1, (int) get_option('posts_per_page')),
'paged' => aksrt_homepage_get_current_page(),
'ignore_sticky_posts' => false,
'orderby' => 'date',
'order' => 'DESC',
'no_found_rows' => false,
];
$exclude_ids = class_exists('AKSRT_Settings')
@@ -758,7 +770,8 @@ if (!function_exists('aksrt_homepage_render_posts_grid')) {
$query = $query instanceof WP_Query ? $query : aksrt_homepage_get_latest_query();
if (function_exists('aksrt_render_post_list')) {
aksrt_render_post_list($query, ['mode' => 'list', 'context' => 'home'], true);
// Panel already provides posts-row.ajaxpager; avoid nested wrapper.
aksrt_render_post_list($query, ['mode' => 'list', 'context' => 'home', 'skip_wrapper' => true], true);
} else {
if (!$query->have_posts()) {
echo '<div class="no-results"><p>' . esc_html__('暂无文章', 'aksrt') . '</p></div>';
@@ -798,9 +811,51 @@ if (!function_exists('aksrt_homepage_render_section')) {
}
}
if (!function_exists('aksrt_header_slide_is_show')) {
/**
* Whether the header multi-function slider should render (zibll header-slider contract).
*/
function aksrt_header_slide_is_show(): bool {
if (is_admin()) {
return false;
}
// Match zibll: only first page of the posts index / front page.
if (!(is_front_page() || is_home())) {
return false;
}
if (function_exists('aksrt_homepage_get_current_page') && aksrt_homepage_get_current_page() > 1) {
return false;
}
return function_exists('aksrt_homepage_module_hero_enabled')
? aksrt_homepage_module_hero_enabled()
: true;
}
}
if (!function_exists('aksrt_header_slide')) {
/**
* Render header slider after the site header (outside main).
*/
function aksrt_header_slide(): void {
if (!aksrt_header_slide_is_show()) {
return;
}
// Reuse existing hero partial as the slider implementation.
get_template_part('templates/parts/home-modules/module', 'hero');
}
}
if (!function_exists('aksrt_homepage_render_layout')) {
/**
* Render the fixed homepage layout (Zibll latest-first content stream).
*
* Order (zibll-aligned):
* fluid top → main.container → top content → banner → tabs/list → bottom content → sidebar
* → fluid bottom. Hero/header-slider is rendered from header.php, not here.
*/
function aksrt_homepage_render_layout(): void {
$current_page = aksrt_homepage_get_current_page();
@@ -808,25 +863,19 @@ if (!function_exists('aksrt_homepage_render_layout')) {
$tab_configs = $show_tabs ? aksrt_homepage_get_tab_configs() : [];
$latest_contract = aksrt_homepage_get_latest_panel_contract();
$has_sidebar = aksrt_homepage_has_sidebar();
$hero_on = $show_tabs && aksrt_homepage_module_hero_enabled();
$banner_on = $show_tabs && aksrt_homepage_module_banner_enabled();
$main_list_enabled = !class_exists('AKSRT_Settings') || AKSRT_Settings::home_posts_list_enabled();
$list_title = class_exists('AKSRT_Settings')
? AKSRT_Settings::home_list_title()
: __('最新发布', 'aksrt');
// Fluid zones live outside <main>, once only (removed from header.php).
aksrt_homepage_render_widget_zone(
['all_top_fluid', 'home_top_fluid'],
'fluid-widget-wrap aksrt-homepage__fluid-zone aksrt-homepage__fluid-zone--top'
);
?>
<main id="main-content" role="main" class="site-main container aksrt-homepage" tabindex="-1">
<?php
aksrt_homepage_render_widget_zone(
['all_top_fluid', 'home_top_fluid'],
'fluid-widget-wrap aksrt-homepage__fluid-zone aksrt-homepage__fluid-zone--top'
);
if ($hero_on && function_exists('aksrt_homepage_render_section')) {
aksrt_homepage_render_section('hero');
}
?>
<main id="main-content" role="main" class="container site-main aksrt-homepage" tabindex="-1">
<div class="content-wrap aksrt-homepage__shell">
<div class="content-layout<?php echo $has_sidebar ? '' : ' content-layout--no-sidebar'; ?> aksrt-homepage__content-layout">
<div class="content-layout__primary aksrt-homepage__primary">
@@ -845,7 +894,7 @@ if (!function_exists('aksrt_homepage_render_layout')) {
<section class="aksrt-homepage__stream home-tab-content" aria-label="<?php esc_attr_e('Homepage Content', 'aksrt'); ?>">
<?php if ($show_tabs && !empty($tab_configs)) : ?>
<div class="index-tab affix-header-sm relative home-tab-nav-box aksrt-homepage__tabs mb10" data-sticky-tabs="<?php echo aksrt_homepage_sticky_tabs_enabled() ? 'true' : 'false'; ?>" offset-top="-8">
<ul class="aksrt-homepage__tab-list scroll-x no-scrollbar" role="tablist" data-aksrt-home-tabs style="width:100%;">
<ul class="list-inline scroll-x no-scrollbar aksrt-homepage__tab-list" role="tablist" data-aksrt-home-tabs style="width:100%;">
<li class="aksrt-homepage__tab-item is-active" role="presentation">
<button type="button" class="aksrt-homepage__tab-button" role="tab" aria-selected="true" data-home-tab-target="latest">
<?php echo esc_html($list_title !== '' ? $list_title : __('最新发布', 'aksrt')); ?>
@@ -886,7 +935,7 @@ if (!function_exists('aksrt_homepage_render_layout')) {
<?php aksrt_homepage_render_sortbar(); ?>
<div class="aksrt-homepage__panels tab-content">
<div class="aksrt-homepage__panel posts-row ajaxpager tab-pane is-active" role="tabpanel" data-home-tab-panel="latest" id="index-tab-main">
<div class="aksrt-homepage__panel posts-row ajaxpager tab-pane fade in active is-active" role="tabpanel" data-home-tab-panel="latest" id="index-tab-main">
<div
class="aksrt-homepage__panel-contract"
data-query-context="<?php echo esc_attr($latest_contract['query_context']); ?>"
@@ -901,7 +950,7 @@ if (!function_exists('aksrt_homepage_render_layout')) {
<?php if ($show_tabs && !empty($tab_configs)) : ?>
<?php foreach ($tab_configs as $tab_cfg) : ?>
<div
class="aksrt-homepage__panel ajaxpager tab-pane"
class="aksrt-homepage__panel posts-row ajaxpager tab-pane"
role="tabpanel"
data-home-tab-panel="term-<?php echo (int) $tab_cfg['term_id']; ?>"
data-tab-orderby="<?php echo esc_attr($tab_cfg['orderby']); ?>"
@@ -911,6 +960,15 @@ if (!function_exists('aksrt_homepage_render_layout')) {
<?php endif; ?>
</div>
</section>
<?php else : ?>
<section class="aksrt-homepage__stream home-tab-content aksrt-homepage__stream--disabled" aria-label="<?php esc_attr_e('Homepage Content', 'aksrt'); ?>">
<div class="no-results box-body">
<p><?php esc_html_e('首页主列表已关闭。', 'aksrt'); ?></p>
<?php if (current_user_can('manage_options') && function_exists('aksrt_render_admin_quick_link')) : ?>
<?php aksrt_render_admin_quick_link('page-display/homepage', __('打开首页设置并启用主列表', 'aksrt'), 'aksrt-admin-quicklink'); ?>
<?php endif; ?>
</div>
</section>
<?php endif; ?>
<?php
@@ -924,15 +982,12 @@ if (!function_exists('aksrt_homepage_render_layout')) {
<?php aksrt_homepage_render_sidebar(); ?>
</div>
</div>
<?php
aksrt_homepage_render_widget_zone(
['home_bottom_fluid', 'all_bottom_fluid'],
'fluid-widget-wrap aksrt-homepage__fluid-zone aksrt-homepage__fluid-zone--bottom'
);
?>
</main>
<?php
aksrt_homepage_render_widget_zone(
['home_bottom_fluid', 'all_bottom_fluid'],
'fluid-widget-wrap aksrt-homepage__fluid-zone aksrt-homepage__fluid-zone--bottom'
);
}
}
+17 -7
View File
@@ -494,7 +494,7 @@ if (!function_exists('aksrt_renderer_thumb')) {
if ($has_real_img && !empty($lazy['enabled'])) {
$img_html = '<span class="aksrt-skeleton"></span>'
. '<img class="' . (!empty($cfg['thumb_fit']) && $cfg['thumb_fit'] === 'contain' ? 'fit-contain' : 'fit-cover') . ' aksrt-lazy" data-src="' . esc_url($img) . '" src="' . esc_url($lazy['placeholder_url']) . '" alt="' . esc_attr($title) . '">';
. '<img class="' . (!empty($cfg['thumb_fit']) && $cfg['thumb_fit'] === 'contain' ? 'fit-contain' : 'fit-cover') . ' aksrt-lazy lazyload" data-src="' . esc_url($img) . '" src="' . esc_url($lazy['placeholder_url']) . '" alt="' . esc_attr($title) . '">';
} else {
$img_html = '<img class="' . (!empty($cfg['thumb_fit']) && $cfg['thumb_fit'] === 'contain' ? 'fit-contain' : 'fit-cover') . '" src="' . esc_url($img) . '" alt="' . esc_attr($title) . '"' . ($has_real_img ? ' loading="lazy"' : '') . '>';
}
@@ -542,7 +542,7 @@ if (!function_exists('aksrt_renderer_mult_thumb')) {
$html .= '<span>';
if (!empty($lazy['enabled'])) {
$html .= '<span class="aksrt-skeleton"></span>'
. '<img class="fit-cover aksrt-lazy" data-src="' . esc_url($image) . '" src="' . esc_url($lazy['placeholder_url']) . '" alt="">';
. '<img class="fit-cover aksrt-lazy lazyload" data-src="' . esc_url($image) . '" src="' . esc_url($lazy['placeholder_url']) . '" alt="">';
} else {
$html .= '<img class="fit-cover" src="' . esc_url($image) . '" alt="" loading="lazy">';
}
@@ -850,7 +850,7 @@ if (!function_exists('aksrt_renderer_mini')) {
if ($cfg['show_thumb'] && !empty($data['has_img'])) {
$lazy = $data['lazy'];
$thumb_img = !empty($lazy['enabled']) && !empty($data['has_real_img'])
? '<span class="aksrt-skeleton"></span><img class="' . (!empty($cfg['thumb_fit']) && $cfg['thumb_fit'] === 'contain' ? 'fit-contain' : 'fit-cover') . ' aksrt-lazy" data-src="' . esc_url($data['img_url']) . '" src="' . esc_url($lazy['placeholder_url']) . '" alt="' . esc_attr($data['title']) . '">'
? '<span class="aksrt-skeleton"></span><img class="' . (!empty($cfg['thumb_fit']) && $cfg['thumb_fit'] === 'contain' ? 'fit-contain' : 'fit-cover') . ' aksrt-lazy lazyload" data-src="' . esc_url($data['img_url']) . '" src="' . esc_url($lazy['placeholder_url']) . '" alt="' . esc_attr($data['title']) . '">'
: '<img class="fit-cover" src="' . esc_url($data['img_url']) . '" alt="' . esc_attr($data['title']) . '"' . (!empty($data['has_real_img']) ? ' loading="lazy"' : '') . '>';
$thumb_html = '<a href="' . esc_url($data['permalink']) . '" class="item-thumbnail" aria-label="' . esc_attr($data['title']) . '"' . $target_attr . '>' . $thumb_img . '</a>';
@@ -935,13 +935,17 @@ if (!function_exists('aksrt_render_post_list')) {
}
$data_view = in_array($cfg['mode'], ['card', 'grid-cms'], true) ? 'card' : $cfg['mode'];
// Homepage panel already provides .posts-row.ajaxpager — allow callers to skip nesting.
$skip_wrapper = !empty($config['skip_wrapper']);
$html = '';
if ($query instanceof WP_Query) {
if (!$query->have_posts()) {
$html = '<div class="no-results"><p>' . esc_html__('暂无文章', 'aksrt') . '</p></div>';
} else {
$html .= '<div ' . $wrapper_attr . ' data-view="' . esc_attr($data_view) . '">';
if (!$skip_wrapper) {
$html .= '<div ' . $wrapper_attr . ' data-view="' . esc_attr($data_view) . '">';
}
$number = $cfg['number_offset'];
while ($query->have_posts()) {
$query->the_post();
@@ -952,19 +956,25 @@ if (!function_exists('aksrt_render_post_list')) {
}
$html .= aksrt_render_post($cfg);
}
$html .= '</div>';
if (!$skip_wrapper) {
$html .= '</div>';
}
}
wp_reset_postdata();
} else {
if (!have_posts()) {
$html = '<div class="no-results"><p>' . esc_html__('暂无文章', 'aksrt') . '</p></div>';
} else {
$html .= '<div ' . $wrapper_attr . ' data-view="' . esc_attr($data_view) . '">';
if (!$skip_wrapper) {
$html .= '<div ' . $wrapper_attr . ' data-view="' . esc_attr($data_view) . '">';
}
while (have_posts()) {
the_post();
$html .= aksrt_render_post($cfg);
}
$html .= '</div>';
if (!$skip_wrapper) {
$html .= '</div>';
}
}
}
+29
View File
@@ -116,6 +116,12 @@ if (!function_exists('aksrt_get_banners')):
*/
function aksrt_get_banners($limit = 8, $kind = 'hero') {
$kind = in_array($kind, array('hero', 'banner'), true) ? $kind : 'hero';
$limit = max(1, min(20, (int) $limit));
$cache_key = 'aksrt_banners_' . $kind . '_' . $limit;
$cached = wp_cache_get($cache_key, 'aksrt');
if (is_array($cached)) {
return $cached;
}
$args = array(
'post_type' => 'aksrt_banner',
@@ -123,6 +129,7 @@ function aksrt_get_banners($limit = 8, $kind = 'hero') {
'post_status' => 'publish',
'orderby' => 'menu_order',
'order' => 'ASC',
'no_found_rows' => true,
'meta_query' => 'hero' === $kind
? array(
'relation' => 'OR',
@@ -179,6 +186,7 @@ function aksrt_get_banners($limit = 8, $kind = 'hero') {
wp_reset_postdata();
}
wp_cache_set($cache_key, $banners, 'aksrt', 15 * MINUTE_IN_SECONDS);
return $banners;
}
endif;
@@ -1515,3 +1523,24 @@ function aksrt_user_can(string $cap, int $user_id = 0, ?int $context = null): bo
return AKSRT_Settings::user_can($cap, $user_id, $context);
}
endif;
if (!function_exists('aksrt_flush_banner_cache')) :
/**
* Invalidate banner CPT object-cache keys used by aksrt_get_banners().
*/
function aksrt_flush_banner_cache($post_id = 0) {
if ($post_id && get_post_type($post_id) && get_post_type($post_id) !== 'aksrt_banner') {
return;
}
// Group flush is not available on all object caches; delete common keys.
foreach (array('hero', 'banner') as $kind) {
for ($n = 1; $n <= 20; $n++) {
wp_cache_delete('aksrt_banners_' . $kind . '_' . $n, 'aksrt');
}
}
}
add_action('save_post_aksrt_banner', 'aksrt_flush_banner_cache');
add_action('deleted_post', 'aksrt_flush_banner_cache');
add_action('trashed_post', 'aksrt_flush_banner_cache');
endif;