Refine homepage skeleton layout

This commit is contained in:
2026-07-04 07:48:34 +08:00
parent 3247db7ed1
commit 0e95dbe4d6
7 changed files with 212 additions and 85 deletions
@@ -116,6 +116,20 @@
================================================================ */
@media (max-width: 640px) {
.aksrt-homepage__stream-header {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
.aksrt-homepage__stream-title {
font-size: 20px;
}
.aksrt-homepage__stream-subtitle {
font-size: 13px;
}
.aksrt-homepage__tabs,
.aksrt-homepage__titlebox {
margin-bottom: 8px;
@@ -130,6 +130,23 @@
margin-bottom: 20px;
}
.aksrt-homepage__content-zone--operated,
.aksrt-homepage__content-zone--mid,
.aksrt-homepage__content-zone--supplement {
margin-bottom: 20px;
}
.aksrt-homepage__content-zone--operated.home-modules,
.aksrt-homepage__content-zone--mid.home-modules,
.aksrt-homepage__content-zone--supplement.home-modules {
gap: 24px;
padding-bottom: 0;
}
.aksrt-homepage__content-zone--supplement {
padding-top: 4px;
}
.aksrt-homepage__content-zone--featured.home-modules {
gap: 24px;
padding-bottom: 0;
@@ -176,6 +193,43 @@
4. STREAM CONTAINER
================================================================ */
.aksrt-homepage__stream-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
margin-bottom: 14px;
padding: 0;
}
.aksrt-homepage__stream-intro {
min-width: 0;
}
.aksrt-homepage__stream-kicker {
margin-bottom: 6px;
color: var(--color-primary, var(--color-primary));
font-size: 12px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.aksrt-homepage__stream-title {
margin: 0;
color: var(--color-ink);
font-size: 24px;
font-weight: 700;
line-height: 1.25;
}
.aksrt-homepage__stream-subtitle {
margin: 8px 0 0;
color: var(--color-ink-3, #777);
font-size: 14px;
line-height: 1.6;
}
.aksrt-homepage__stream,
.aksrt-homepage__stream.widget-card {
overflow: visible;
@@ -66,14 +66,14 @@
transition: opacity 0.3s ease;
}
.aksrt-homepage__panel.is-active,
.aksrt-homepage__panel:not([hidden]) {
opacity: 1;
.aksrt-homepage__panel-contract {
display: none;
}
.aksrt-homepage__posts.post-grid--home {
gap: 0;
}
/* ================================================================
9. POST LIST — LIST MODE
================================================================ */
.aksrt-homepage__posts {
display: block;
+4 -1
View File
@@ -1,6 +1,9 @@
<?php
/**
* 首页模板:最新文章在首页时走列表;静态首页走页面内容
* Homepage entry template.
*
* Front page requests are always delegated to the fixed homepage skeleton so
* the site reads as a primary Zibll-style operation hub instead of a page body.
*
* @package AKSRT
*/
+128 -73
View File
@@ -52,7 +52,6 @@ if (!function_exists('aksrt_homepage_get_post_types')) {
return ['post'];
}
// Mixed mode: include resource CPTs
if (function_exists('aksrt_resource_post_types')) {
return array_values(array_unique(aksrt_resource_post_types()));
}
@@ -145,7 +144,6 @@ if (!function_exists('aksrt_homepage_get_tab_terms')) {
if (count($configs) >= $limit) {
break;
}
// Skip excluded categories
if (isset($excluded_cat_ids[$tab['term_id']])) {
continue;
}
@@ -181,10 +179,6 @@ if (!function_exists('aksrt_homepage_get_tab_terms')) {
if (!function_exists('aksrt_homepage_get_tab_posts_per_page')) {
/**
* Per-tab homepage post count.
*
* Reads from AKSRT_Settings::homepage_tab_posts_per_page() first;
* falls back to the legacy module config bridge for old installs
* that haven't saved the new setting yet.
*/
function aksrt_homepage_get_tab_posts_per_page(): int {
if (class_exists('AKSRT_Settings')) {
@@ -194,7 +188,6 @@ if (!function_exists('aksrt_homepage_get_tab_posts_per_page')) {
}
}
// Legacy fallback for sites that haven't migrated yet
$legacy = aksrt_homepage_get_legacy_tabs_config();
$count = (int) apply_filters('aksrt_homepage_tab_posts_per_page', $legacy['posts_per_page']);
@@ -307,10 +300,6 @@ if (!function_exists('aksrt_homepage_get_sort_items')) {
if (!function_exists('aksrt_homepage_apply_sort_args')) {
/**
* Apply sort args to a query configuration.
* Supports all 8 homepage sort modes.
*
* @param array<string,mixed> $args
* @return array<string,mixed>
*/
function aksrt_homepage_apply_sort_args(array $args): array {
$sort_mode = aksrt_homepage_get_sort_mode();
@@ -362,10 +351,6 @@ if (!function_exists('aksrt_homepage_apply_sort_args')) {
if (!function_exists('aksrt_homepage_apply_named_sort_args')) {
/**
* Apply a specific named sort to query args (used by per-tab orderby).
*
* @param array<string,mixed> $args
* @param string $sort_mode
* @return array<string,mixed>
*/
function aksrt_homepage_apply_named_sort_args(array $args, string $sort_mode): array {
$allowed = class_exists('AKSRT_Settings')
@@ -376,7 +361,6 @@ if (!function_exists('aksrt_homepage_apply_named_sort_args')) {
$sort_mode = 'date';
}
// Temporarily override the global sort mode
$previous = get_query_var('aksrt_homepage_sort_override');
set_query_var('aksrt_homepage_sort_override', $sort_mode);
$result = aksrt_homepage_apply_sort_args($args);
@@ -389,8 +373,6 @@ if (!function_exists('aksrt_homepage_apply_named_sort_args')) {
if (!function_exists('aksrt_homepage_render_sortbar')) {
/**
* Render the main-stream sort bar.
* Only renders when home_list_sort_enabled is true.
* Supports inline links or dropdown mode.
*/
function aksrt_homepage_render_sortbar(): void {
if (class_exists('AKSRT_Settings') && !AKSRT_Settings::home_list_sort_enabled()) {
@@ -459,7 +441,6 @@ if (!function_exists('aksrt_homepage_render_sortbar')) {
if (!function_exists('aksrt_homepage_get_latest_query')) {
/**
* Homepage main-stream query.
* Applies sort, exclusion filters, and content model.
*/
function aksrt_homepage_get_latest_query(): WP_Query {
static $query = null;
@@ -478,7 +459,6 @@ if (!function_exists('aksrt_homepage_get_latest_query')) {
'order' => 'DESC',
];
// Exclude specific posts (both main stream and tabs)
$exclude_ids = class_exists('AKSRT_Settings')
? AKSRT_Settings::home_exclude_post_ids()
: [];
@@ -486,7 +466,6 @@ if (!function_exists('aksrt_homepage_get_latest_query')) {
$query_args['post__not_in'] = $exclude_ids;
}
// Exclude specific categories (main stream only)
$exclude_cat_ids = class_exists('AKSRT_Settings')
? AKSRT_Settings::home_exclude_category_ids()
: [];
@@ -503,11 +482,6 @@ if (!function_exists('aksrt_homepage_get_latest_query')) {
if (!function_exists('aksrt_homepage_get_tab_query')) {
/**
* Build a category-tab query.
* Uses the tab's own orderby instead of the main stream sort.
* Applies post exclusion but NOT category exclusion (tabs bind to specific categories).
*
* @param int $term_id Category term ID.
* @param string $orderby Per-tab orderby override.
*/
function aksrt_homepage_get_tab_query(int $term_id, string $orderby = 'date'): WP_Query {
static $queries = [];
@@ -530,7 +504,6 @@ if (!function_exists('aksrt_homepage_get_tab_query')) {
'no_found_rows' => true,
];
// Exclude specific posts (shared with main stream)
$exclude_ids = class_exists('AKSRT_Settings')
? AKSRT_Settings::home_exclude_post_ids()
: [];
@@ -538,7 +511,6 @@ if (!function_exists('aksrt_homepage_get_tab_query')) {
$query_args['post__not_in'] = $exclude_ids;
}
// Apply per-tab orderby (NOT the main stream sort)
$queries[$cache_key] = new WP_Query(
aksrt_homepage_apply_named_sort_args($query_args, $orderby)
);
@@ -630,6 +602,35 @@ if (!function_exists('aksrt_homepage_render_sidebar')) {
}
}
if (!function_exists('aksrt_homepage_get_latest_panel_contract')) {
/**
* Public-safe latest stream contract shared by homepage pagination/AJAX.
*
* @return array{query_context:string,query_vars:string,render_config:string,render_config_array:array<string,mixed>}
*/
function aksrt_homepage_get_latest_panel_contract(): array {
$query = aksrt_homepage_get_latest_query();
$query_vars = $query instanceof WP_Query ? $query->query_vars : [];
if (!is_array($query_vars)) {
$query_vars = [];
}
unset($query_vars['paged'], $query_vars['page']);
$render_config = [
'mode' => 'list',
'context' => 'home',
];
return [
'query_context' => 'homepage_latest',
'query_vars' => (string) wp_json_encode($query_vars),
'render_config' => (string) wp_json_encode($render_config),
'render_config_array' => $render_config,
];
}
}
if (!function_exists('aksrt_homepage_render_pagination')) {
/**
* Render pagination for the fixed homepage latest stream.
@@ -669,7 +670,6 @@ if (!function_exists('aksrt_homepage_render_pagination')) {
}
$links = paginate_links($base_args);
if (!$links || !is_array($links)) {
return;
}
@@ -684,12 +684,18 @@ if (!function_exists('aksrt_homepage_render_pagination')) {
<?php
return;
}
$contract = aksrt_homepage_get_latest_panel_contract();
?>
<div class="ajax-pagination aksrt-pagination-ajax"
data-mode="<?php echo esc_attr($pagination_mode); ?>"
data-next-page="<?php echo esc_attr($current_page + 1); ?>"
data-max-pages="<?php echo esc_attr($max_pages); ?>"
data-query-context="homepage_latest">
data-query-context="<?php echo esc_attr($contract['query_context']); ?>"
data-query-vars="<?php echo esc_attr($contract['query_vars']); ?>"
data-render-config="<?php echo esc_attr($contract['render_config']); ?>"
data-page="<?php echo esc_attr($current_page); ?>"
data-tab="latest">
<a href="javascript:;" class="ajax-next aksrt-load-more-btn">
<?php esc_html_e('加载更多', 'aksrt'); ?>
</a>
@@ -706,9 +712,6 @@ if (!function_exists('aksrt_get_post_gallery_images')) {
/**
* Collect gallery images for homepage mult-thumb cards.
*
* Uses a transient keyed by the post modified timestamp so repeated list
* renders do not keep re-parsing post content.
*
* @return string[]
*/
function aksrt_get_post_gallery_images(int $post_id, int $limit = 4): array {
@@ -745,7 +748,7 @@ if (!function_exists('aksrt_get_post_gallery_images')) {
$content = (string) get_post_field('post_content', $post_id, 'raw');
if ($content !== '') {
if (preg_match_all('/<img[^>]+src=["\x27"]([^"\x27"]+)["\x27"]/i', $content, $html_matches) && !empty($html_matches[1])) {
if (preg_match_all('/<img[^>]+src=["\x27]([^"\x27]+)["\x27]/i', $content, $html_matches) && !empty($html_matches[1])) {
foreach ($html_matches[1] as $raw_url) {
$images[] = esc_url_raw((string) $raw_url);
}
@@ -772,8 +775,6 @@ if (!function_exists('aksrt_get_post_gallery_images')) {
if (!function_exists('aksrt_homepage_render_post_card')) {
/**
* Render a homepage post card inline.
*
* Thin wrapper over the unified shared renderer (aksrt_render_post).
*/
function aksrt_homepage_render_post_card(): void {
if (!function_exists('aksrt_render_post')) {
@@ -791,9 +792,7 @@ if (!function_exists('aksrt_homepage_render_post_card')) {
if (!function_exists('aksrt_homepage_render_posts_grid')) {
/**
* Render a card-grid post block for the fixed homepage.
*
* Delegates to the unified shared renderer via aksrt_render_post_list.
* Render a list block for the fixed homepage.
*/
function aksrt_homepage_render_posts_grid(?WP_Query $query = null, bool $with_pagination = false): void {
$query = $query instanceof WP_Query ? $query : aksrt_homepage_get_latest_query();
@@ -801,7 +800,6 @@ if (!function_exists('aksrt_homepage_render_posts_grid')) {
if (function_exists('aksrt_render_post_list')) {
aksrt_render_post_list($query, ['mode' => 'list', 'context' => 'home'], true);
} else {
// Fallback: simple loop if shared renderer is unavailable
if (!$query->have_posts()) {
echo '<div class="no-results"><p>' . esc_html__('暂无文章', 'aksrt') . '</p></div>';
} else {
@@ -852,9 +850,6 @@ if (!function_exists('aksrt_homepage_get_featured_modules')) {
* Resolve non-core homepage modules that should render alongside the fixed
* hero/banner/main-stream skeleton.
*
* Hero, banner, and tabs are now owned by dedicated settings surfaces, so
* the legacy modules list only contributes featured content modules here.
*
* @return array<int,array{type:string,config:array}>
*/
function aksrt_homepage_get_featured_modules(): array {
@@ -871,6 +866,7 @@ if (!function_exists('aksrt_homepage_get_featured_modules')) {
'tag_cloud',
'friend_links',
'html',
'highlight_cards',
];
$modules = [];
@@ -897,9 +893,6 @@ if (!function_exists('aksrt_homepage_get_featured_modules')) {
if (!function_exists('aksrt_homepage_render_featured_modules')) {
/**
* Render featured homepage modules in configured order.
*
* @param array<int,array{type:string,config:array}> $modules
* @param string $wrapper_class
*/
function aksrt_homepage_render_featured_modules(array $modules, string $wrapper_class = 'home-modules'): void {
if (empty($modules)) {
@@ -923,18 +916,57 @@ if (!function_exists('aksrt_homepage_render_featured_modules')) {
}
}
if (!function_exists('aksrt_homepage_split_featured_modules')) {
/**
* Split legacy featured modules into homepage skeleton slots.
*
* @param array<int,array{type:string,config:array}> $modules
* @return array{top:array<int,array{type:string,config:array}>,mid:array<int,array{type:string,config:array}>,bottom:array<int,array{type:string,config:array}>}
*/
function aksrt_homepage_split_featured_modules(array $modules): array {
$buckets = [
'top' => [],
'mid' => [],
'bottom' => [],
];
$top_types = ['highlight_cards', 'hotspot', 'html'];
$bottom_types = ['ranking', 'tag_cloud', 'friend_links'];
foreach ($modules as $module) {
$type = sanitize_key((string) ($module['type'] ?? ''));
if ($type === '') {
continue;
}
if (in_array($type, $top_types, true)) {
$buckets['top'][] = $module;
continue;
}
if (in_array($type, $bottom_types, true)) {
$buckets['bottom'][] = $module;
continue;
}
$buckets['mid'][] = $module;
}
return $buckets;
}
}
if (!function_exists('aksrt_homepage_render_layout')) {
/**
* Render the fixed homepage layout directly.
*
* Keeping the markup here avoids silent empty homepages when a template
* part file is missing or not synced on the target server.
*/
function aksrt_homepage_render_layout(): void {
$current_page = aksrt_homepage_get_current_page();
$show_tabs = $current_page === 1;
$tab_configs = $show_tabs ? aksrt_homepage_get_tab_configs() : [];
$featured_modules = $show_tabs ? aksrt_homepage_get_featured_modules() : [];
$featured_slots = $show_tabs ? aksrt_homepage_split_featured_modules($featured_modules) : ['top' => [], 'mid' => [], 'bottom' => []];
$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();
@@ -971,16 +1003,25 @@ if (!function_exists('aksrt_homepage_render_layout')) {
aksrt_homepage_render_system_module('banner', 'aksrt-homepage__content-zone aksrt-homepage__content-zone--banner aksrt-homepage__system-modules home-modules');
}
if (!empty($featured_modules)) {
if (!empty($featured_slots['top'])) {
aksrt_homepage_render_featured_modules(
$featured_modules,
'aksrt-homepage__content-zone aksrt-homepage__content-zone--featured home-modules'
$featured_slots['top'],
'aksrt-homepage__content-zone aksrt-homepage__content-zone--operated aksrt-homepage__content-zone--top-modules home-modules'
);
}
?>
<?php if ($main_list_enabled) : ?>
<section class="widget widget-card aksrt-homepage__stream home-tab-content index-tab-main" aria-label="<?php esc_attr_e('Homepage Content', 'aksrt'); ?>">
<div class="aksrt-homepage__stream-header box-body notop nobottom">
<div class="aksrt-homepage__stream-intro">
<div class="aksrt-homepage__stream-kicker"><?php esc_html_e('首页主内容流', 'aksrt'); ?></div>
<h2 class="aksrt-homepage__stream-title"><?php echo esc_html($list_title); ?></h2>
<p class="aksrt-homepage__stream-subtitle"><?php esc_html_e('以内容流为主轴,承接运营入口、分类切换与持续更新。', 'aksrt'); ?></p>
</div>
<?php if (function_exists('aksrt_render_admin_quick_link')) { aksrt_render_admin_quick_link('page-display/homepage', __('首页设置', 'aksrt'), 'aksrt-admin-quicklink aksrt-homepage__admin-link'); } ?>
</div>
<?php if ($show_tabs && !empty($tab_configs)) : ?>
<div class="aksrt-homepage__tabs box-body notop nobottom index-tab home-tab-nav-box" data-sticky-tabs="<?php echo aksrt_homepage_sticky_tabs_enabled() ? 'true' : 'false'; ?>">
<ul class="aksrt-homepage__tab-list scroll-x no-scrollbar" role="tablist" data-aksrt-home-tabs>
@@ -1010,27 +1051,22 @@ if (!function_exists('aksrt_homepage_render_layout')) {
</li>
<?php endforeach; ?>
</ul>
<?php if (function_exists('aksrt_render_admin_quick_link')) { aksrt_render_admin_quick_link('page-display/homepage', __('首页设置', 'aksrt'), 'aksrt-admin-quicklink aksrt-homepage__admin-link'); } ?>
</div>
<?php else : ?>
<?php elseif ($current_page > 1) : ?>
<div class="aksrt-homepage__titlebox box-body notop nobottom">
<div class="title-theme">
<?php echo esc_html($list_title); ?>
<?php if ($current_page > 1) : ?>
<small class="aksrt-homepage__page-indicator">
<?php
echo esc_html(
sprintf(
/* translators: %d is the current pagination page number. */
__('第 %d 页', 'aksrt'),
$current_page
)
);
?>
</small>
<?php endif; ?>
<small class="aksrt-homepage__page-indicator">
<?php
echo esc_html(
sprintf(
__('第 %d 页', 'aksrt'),
$current_page
)
);
?>
</small>
</div>
<?php if (function_exists('aksrt_render_admin_quick_link')) { aksrt_render_admin_quick_link('page-display/homepage', __('首页设置', 'aksrt'), 'aksrt-admin-quicklink aksrt-homepage__admin-link'); } ?>
</div>
<?php endif; ?>
@@ -1038,6 +1074,14 @@ if (!function_exists('aksrt_homepage_render_layout')) {
<div class="aksrt-homepage__panels tab-content home-tab-content">
<div class="aksrt-homepage__panel tab-pane is-active" role="tabpanel" data-home-tab-panel="latest">
<div
class="aksrt-homepage__panel-contract"
data-query-context="<?php echo esc_attr($latest_contract['query_context']); ?>"
data-query-vars="<?php echo esc_attr($latest_contract['query_vars']); ?>"
data-render-config="<?php echo esc_attr($latest_contract['render_config']); ?>"
data-page="1"
data-tab="latest"
></div>
<?php aksrt_homepage_render_posts_grid(aksrt_homepage_get_latest_query(), true); ?>
</div>
@@ -1049,19 +1093,32 @@ if (!function_exists('aksrt_homepage_render_layout')) {
data-home-tab-panel="term-<?php echo (int) $tab_cfg['term_id']; ?>"
data-tab-orderby="<?php echo esc_attr($tab_cfg['orderby']); ?>"
hidden
>
</div>
></div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</section>
<?php endif; // main_list_enabled ?>
<?php endif; ?>
<?php
if (!empty($featured_slots['mid'])) {
aksrt_homepage_render_featured_modules(
$featured_slots['mid'],
'aksrt-homepage__content-zone aksrt-homepage__content-zone--mid home-modules'
);
}
aksrt_homepage_render_widget_zone(
['home_bottom_content'],
'aksrt-homepage__content-zone aksrt-homepage__content-zone--bottom'
);
if (!empty($featured_slots['bottom'])) {
aksrt_homepage_render_featured_modules(
$featured_slots['bottom'],
'aksrt-homepage__content-zone aksrt-homepage__content-zone--supplement home-modules'
);
}
?>
</div>
@@ -1083,8 +1140,6 @@ if (!function_exists('aksrt_homepage_render_layout')) {
if (!function_exists('aksrt_render_fixed_homepage')) {
/**
* Render the new fixed homepage layout.
*
* @return bool True when the current request was handled.
*/
function aksrt_render_fixed_homepage(): bool {
if (!aksrt_is_fixed_homepage_request()) {
+2
View File
@@ -913,6 +913,8 @@ if (!function_exists('aksrt_render_post_list')) {
if ($cfg['context'] === 'home') {
$wrapper_classes[] = 'aksrt-homepage__posts';
$wrapper_classes[] = 'post-grid';
$wrapper_classes[] = 'post-grid--home';
} elseif ($cfg['mode'] !== 'mini') {
$wrapper_classes[] = 'post-grid';
$wrapper_classes[] = 'post-grid--' . $cfg['mode'];
+4 -5
View File
@@ -1,10 +1,9 @@
<?php
/**
* Main posts index template.
* Homepage / posts index template.
*
* v4 起主题统一为 CMS / 资源站形态:
* - 首页第一页固定走 AKSRT_Home_Modules 模块系统
* - 其它情况(分页 / 没有 home modules class 时的兜底)走标准列表
* The homepage shell is handled by the fixed homepage helper so the blog entry
* behaves like a primary product surface instead of a generic archive loop.
*
* @package AKSRT
*/
@@ -17,7 +16,7 @@ if (function_exists('aksrt_render_fixed_homepage') && aksrt_render_fixed_homepag
get_header();
// 兜底:模块系统未就绪 或 已分页 → 标准列表
// Fallback: when homepage shell is unavailable, keep a standard archive loop.
?>
<main id="main-content" class="site-main container" tabindex="-1">