Align homepage and category discovery, modern widgets, admin controls, quotes, and comments with the reference theme. Remove superseded paths and add rendering and behavior coverage. Update stale asset and finance contracts; all 760 Node tests and 139 widget assertions pass.
299 lines
9.8 KiB
PHP
299 lines
9.8 KiB
PHP
<?php
|
|
/**
|
|
* Shared archive / category / tag / search stream helpers.
|
|
*
|
|
* Keeps list pages on one content-stream contract instead of four hand-rolled shells.
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
if (!function_exists('aksrt_resolve_post_list_render_config')) :
|
|
/**
|
|
* Build the legacy-shaped arguments used by every list surface.
|
|
*
|
|
* @param array<string,mixed> $args {
|
|
* @type string $context home|category|tag|author|search|archive
|
|
* @type int $term_id Optional term id for list_card_cat
|
|
* @type array<string,mixed> $overrides Optional renderer overrides (mode, style, …)
|
|
* }
|
|
* @return array<string,mixed>
|
|
*/
|
|
function aksrt_resolve_post_list_render_config(array $args = []): array {
|
|
$has_top_level_term_id = array_key_exists('term_id', $args);
|
|
$args = wp_parse_args($args, [
|
|
'context' => '',
|
|
'term_id' => 0,
|
|
'overrides' => [],
|
|
]);
|
|
$overrides = is_array($args['overrides']) ? $args['overrides'] : [];
|
|
$has_override_term_id = array_key_exists('term_id', $overrides);
|
|
$context = sanitize_key((string) ($args['context'] ?: ($overrides['context'] ?? '')));
|
|
if ($context === '') {
|
|
if (function_exists('is_front_page') && (is_front_page() || is_home())) {
|
|
$context = 'home';
|
|
} elseif (is_category()) {
|
|
$context = 'category';
|
|
} elseif (is_tag()) {
|
|
$context = 'tag';
|
|
} elseif (is_author()) {
|
|
$context = 'author';
|
|
} elseif (is_search()) {
|
|
$context = 'search';
|
|
} else {
|
|
$context = 'archive';
|
|
}
|
|
}
|
|
$term_id = $has_override_term_id ? absint($overrides['term_id']) : absint($args['term_id']);
|
|
if ($context === 'category' && !$has_top_level_term_id && !$has_override_term_id) {
|
|
$term_id = absint(get_queried_object_id());
|
|
}
|
|
$config = [
|
|
'context' => $context,
|
|
'term_id' => $term_id,
|
|
'is_home' => $context === 'home',
|
|
'is_category' => $context === 'category',
|
|
'is_tag' => $context === 'tag',
|
|
'is_author' => $context === 'author',
|
|
'is_search' => $context === 'search',
|
|
];
|
|
foreach (['type', 'term_id', 'no_author', 'no_margin', 'is_mult_thumb', 'is_no_thumb', 'is_card', 'highlight_query', 'wrapper_class', 'skip_wrapper'] as $key) {
|
|
if (array_key_exists($key, $overrides)) {
|
|
$config[$key] = $key === 'term_id' ? absint($overrides[$key]) : $overrides[$key];
|
|
}
|
|
}
|
|
return aksrt_renderer_config($config);
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('aksrt_archive_get_render_config')) :
|
|
/**
|
|
* Build render config for archive-like pages.
|
|
*
|
|
* @param array<string,mixed> $overrides Context/mode overrides.
|
|
* @return array<string,mixed>
|
|
*/
|
|
function aksrt_archive_get_render_config(array $overrides = []): array {
|
|
$context = sanitize_key((string) ($overrides['context'] ?? ''));
|
|
return aksrt_resolve_post_list_render_config([
|
|
'context' => $context,
|
|
'overrides' => $overrides,
|
|
]);
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('aksrt_archive_get_sort_state')) :
|
|
/**
|
|
* Build the canonical legacy orderby state for term archives.
|
|
*
|
|
* @param array<string,mixed> $option Page-display orderby fieldset.
|
|
* @return array{current:string,links:array<string,string>}
|
|
*/
|
|
function aksrt_archive_get_sort_state(array $option = []): array {
|
|
$all = class_exists('\AKSRT\Settings\Settings')
|
|
? \AKSRT\Settings\Settings::homepage_allowed_sorts()
|
|
: ['modified', 'date', 'views', 'like', 'comment_count', 'favorite', 'rand'];
|
|
$lists = is_array($option['lists'] ?? null) ? $option['lists'] : [];
|
|
$lists = array_values(array_intersect(array_map('sanitize_key', $lists), $all));
|
|
if (!empty($option['dropdown'])) {
|
|
$lists = array_values(array_unique(array_merge($lists, $all)));
|
|
}
|
|
|
|
$current = isset($_GET['orderby']) ? sanitize_key(wp_unslash((string) $_GET['orderby'])) : '';
|
|
if ($current !== '' && !in_array($current, $all, true)) {
|
|
$current = 'date';
|
|
}
|
|
|
|
$base_url = remove_query_arg(['orderby', 'order'], aksrt_homepage_url_del_paged(aksrt_homepage_get_current_url()));
|
|
$links = [];
|
|
foreach ($lists as $orderby) {
|
|
$links[$orderby] = add_query_arg('orderby', $orderby, $base_url);
|
|
}
|
|
|
|
return [
|
|
'current' => $current,
|
|
'links' => $links,
|
|
];
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('aksrt_archive_has_sidebar')) :
|
|
/**
|
|
* Resolve whether a stream page should show an aside.
|
|
*
|
|
* @param bool $enabled Page-level sidebar toggle.
|
|
*/
|
|
function aksrt_archive_has_sidebar(bool $enabled = true): bool {
|
|
if (!$enabled) {
|
|
return false;
|
|
}
|
|
return function_exists('aksrt_is_show_sidebar') ? aksrt_is_show_sidebar() : false;
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('aksrt_archive_render_widget_zone')) :
|
|
/**
|
|
* Render stacked sidebars when active.
|
|
*
|
|
* @param string[] $sidebar_ids Sidebar ids.
|
|
* @param string $wrapper_class Wrapper class.
|
|
*/
|
|
function aksrt_archive_render_widget_zone(array $sidebar_ids, string $wrapper_class = ''): void {
|
|
$active = [];
|
|
foreach ($sidebar_ids as $sidebar_id) {
|
|
if (is_active_sidebar($sidebar_id)) {
|
|
$active[] = $sidebar_id;
|
|
}
|
|
}
|
|
if (empty($active)) {
|
|
return;
|
|
}
|
|
|
|
if ($wrapper_class !== '') {
|
|
echo '<div class="' . esc_attr($wrapper_class) . '">';
|
|
}
|
|
foreach ($active as $sidebar_id) {
|
|
dynamic_sidebar($sidebar_id);
|
|
}
|
|
if ($wrapper_class !== '') {
|
|
echo '</div>';
|
|
}
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('aksrt_archive_render_stream')) :
|
|
/**
|
|
* Shared list + pagination + empty state for archive surfaces.
|
|
*
|
|
* @param WP_Query|null $query Query or null for main loop.
|
|
* @param array<string,mixed> $render_config Renderer config.
|
|
* @param array<string,mixed> $args Stream args.
|
|
*/
|
|
function aksrt_archive_render_stream(?WP_Query $query, array $render_config, array $args = []): void {
|
|
$args = wp_parse_args($args, [
|
|
'page_kind' => 'archive',
|
|
'query_context' => 'archive',
|
|
'empty_text' => __('暂无文章', 'aksrt'),
|
|
'stream_class' => '',
|
|
'ajax_attrs' => '',
|
|
'filter_html' => '',
|
|
]);
|
|
|
|
$classes = [
|
|
'content-stream', 'posts-row', 'ajaxpager',
|
|
'content-stream--' . sanitize_html_class((string) $args['page_kind']),
|
|
];
|
|
if (!empty($args['stream_class'])) {
|
|
foreach (preg_split('/\s+/', trim((string) $args['stream_class'])) ?: [] as $class) {
|
|
$class = sanitize_html_class($class);
|
|
if ($class !== '') {
|
|
$classes[] = $class;
|
|
}
|
|
}
|
|
}
|
|
|
|
$mode = (string) ($render_config['mode'] ?? 'list');
|
|
$has_posts = $query instanceof WP_Query ? $query->have_posts() : have_posts();
|
|
?>
|
|
<div
|
|
class="<?php echo esc_attr(implode(' ', array_unique($classes))); ?>"
|
|
data-page-kind="<?php echo esc_attr((string) $args['page_kind']); ?>"
|
|
data-render-mode="<?php echo esc_attr($mode); ?>"
|
|
data-list-type="<?php echo esc_attr((string) ($render_config['list_type'] ?? 'thumb')); ?>"
|
|
<?php echo $args['ajax_attrs']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
|
>
|
|
<?php echo $args['filter_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
|
<?php if ($has_posts) : ?>
|
|
<?php
|
|
// legacy 契约:分页渲染在 .ajaxpager 内部(zib_paging 位置),
|
|
// 首页更多栏目 tab 的 runtime post_ajax 依赖它提取下一页。
|
|
ob_start();
|
|
aksrt_render_pagination($query, [
|
|
'query_context' => (string) $args['query_context'],
|
|
'render_config' => $render_config,
|
|
]);
|
|
$pagination_html = (string) ob_get_clean();
|
|
|
|
// 归档面与首页共用同一套骨架契约:.post_ajax_loader + .is-loading。
|
|
// 挂在分页之后(列表末尾),通用列表运行时在 pager 内定位加载态。
|
|
$loader_html = '<div class="post_ajax_loader" role="status" aria-label="'
|
|
. esc_attr__('正在加载', 'aksrt') . '">'
|
|
. aksrt_render_placeholder(
|
|
(string) $render_config['mode'] === 'card' ? 'card' : 'list',
|
|
4
|
|
)
|
|
. '</div>';
|
|
|
|
aksrt_render_post_list(array_merge($render_config, [
|
|
'skip_wrapper' => true,
|
|
'append_inner_html' => $pagination_html . $loader_html,
|
|
]), $query);
|
|
?>
|
|
<?php else : ?>
|
|
<div class="ajax-item"><?php echo aksrt_get_null((string) $args['empty_text'], 100, 'null-post.svg'); ?></div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('aksrt_archive_open_shell')) :
|
|
/**
|
|
* Open a shared archive shell.
|
|
*
|
|
* @param array<string,mixed> $args Shell args.
|
|
*/
|
|
function aksrt_archive_open_shell(array $args = []): void {
|
|
$args = wp_parse_args($args, [
|
|
'main_class' => 'site-main container',
|
|
'has_sidebar' => false,
|
|
'top_fluid' => [],
|
|
'page_kind' => 'archive',
|
|
]);
|
|
|
|
// Force container; strip content-shell* so float dual-column is not padded/max-width nested.
|
|
$main_class = trim((string) $args['main_class']);
|
|
if ($main_class === '') {
|
|
$main_class = 'site-main container';
|
|
} elseif (strpos($main_class, 'container') === false) {
|
|
$main_class .= ' container';
|
|
}
|
|
$main_class = trim((string) preg_replace('/\bcontent-shell(?:--[a-z0-9-]+)?\b/i', '', $main_class));
|
|
if (!empty($args['top_fluid']) && is_array($args['top_fluid'])) {
|
|
aksrt_archive_render_widget_zone($args['top_fluid'], 'fluid-widget-wrap');
|
|
}
|
|
?>
|
|
<main id="main-content" class="<?php echo esc_attr($main_class); ?>" tabindex="-1">
|
|
<div class="content-wrap">
|
|
<div class="content-layout">
|
|
<?php
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('aksrt_archive_close_shell')) :
|
|
/**
|
|
* Close a shared archive shell.
|
|
* Sidebar is a sibling of .content-wrap (legacy float dual-column).
|
|
*
|
|
* @param array<string,mixed> $args Shell args.
|
|
*/
|
|
function aksrt_archive_close_shell(array $args = []): void {
|
|
$args = wp_parse_args($args, [
|
|
'has_sidebar' => false,
|
|
'bottom_fluid' => [],
|
|
]);
|
|
?>
|
|
</div>
|
|
</div>
|
|
<?php if (!empty($args['has_sidebar'])) : ?>
|
|
<?php get_sidebar(); ?>
|
|
<?php endif; ?>
|
|
</main>
|
|
<?php
|
|
if (!empty($args['bottom_fluid']) && is_array($args['bottom_fluid'])) {
|
|
aksrt_archive_render_widget_zone($args['bottom_fluid'], 'fluid-widget-wrap');
|
|
}
|
|
}
|
|
endif;
|