Files
wordpress-theme-aksrt/search.php
T
kate522andClaude Fable 5 cf4554e7c8 fix(ajax): show the reference skeleton on every load-more surface
Clicking 加载更多 in the 多栏目文章 widget showed no skeleton at all — the
list simply stayed still until the response arrived, then the new cards
appeared. The homepage stream, archives and comments already had a working
skeleton; the widget's AJAX load goes through a different client and never
found its loader.

Root cause was DOM placement, not visibility: ContentRenderer emitted
.post_ajax_loader as a *sibling* of .widget-ajaxpager, while the widget REST
client resolves it with container.querySelector('.post_ajax_loader'). The
node existed but could never match, so .is-loading was never added and the
skeleton stayed display:none. Inactive tab panes had the same shape, and the
direct-load branch of ajaxpager() emitted no loader at all.

Changes, all following the reference theme's post_ajax() contract in
zibll/js/main.js (beforeSend anchors the loader to the end of the list;
success only hides it, never removes it):

- ContentRenderer: nest the loader inside .widget-ajaxpager for both the
  direct-load and inactive-tab branches, and drop the sibling append.
- widgets/frontend.js: anchorLoader() moves the loader to the end of the
  list before .ajax-pag on every request; appended cards are inserted before
  it; a replace preserves the node instead of wiping it with innerHTML; a
  fallback loader is created when the DOM has none; loadItems() now returns
  its promise; drop the unreachable is-loading auto-load branch.
- Message centre, user-home panels and the search page switch from spinner /
  opacity feedback to the same .posts-item-shaped skeleton, so all AJAX
  surfaces share one loading contract.
- Remove the second, never-wired skeleton system (.aksrt-skeleton-* in
  core-ui.css) and the dead spinner stylesheets/rules (skeleton.css,
  ajax-spinner.css, .load-more__*, --skeleton-base/--skeleton-shine) plus the
  unregistered assets/js/waterfall.js.
- Extend the widget, message-centre, user-home and asset-ledger contract
  tests to pin the loader inside the container, the class-only visibility
  switch, and the absence of the deleted dead code.

Verified: 470 node tests, 136 PHP widget assertions, admin-contract and
widget-system audits all green; rebuilt public assets after the CSS/JS
removals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-10-03 22:22:15 +08:00

135 lines
6.9 KiB
PHP

<?php
/**
* legacy-contract search results template.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
global $wp_query;
$search_query = trim(wp_strip_all_tags(get_search_query()));
$search_type = function_exists('aksrt_get_search_form_type') ? aksrt_get_search_form_type() : 'post';
$search_types = function_exists('aksrt_get_search_type_options') ? aksrt_get_search_type_options() : ['post' => __('文章', 'aksrt')];
$search_category = isset($_REQUEST['trem']) ? absint(wp_unslash($_REQUEST['trem'])) : 0;
$search_user = isset($_REQUEST['user']) ? absint(wp_unslash($_REQUEST['user'])) : 0;
$paged = max(1, (int) get_query_var('paged'));
$history_value = $search_query . ($search_type !== '' ? '&type=' . $search_type : '');
if ($search_query !== '' && function_exists('aksrt_save_history_search')) {
aksrt_save_history_search($history_value);
}
$user_query = null;
if ($search_type === 'user' && $search_query !== '') {
$user_page = max(1, isset($_REQUEST['user_paged']) ? absint(wp_unslash($_REQUEST['user_paged'])) : 1);
$orderby = isset($_REQUEST['orderby']) ? sanitize_key(wp_unslash($_REQUEST['orderby'])) : 'name';
$orderby = in_array($orderby, ['name', 'registered'], true) ? $orderby : 'name';
$user_query = new WP_User_Query([
'search' => '*' . $search_query . '*',
'search_columns' => ['user_email', 'user_nicename', 'display_name', 'user_login'],
'count_total' => true,
'number' => 12,
'paged' => $user_page,
'orderby' => $orderby === 'registered' ? 'user_registered' : 'display_name',
'order' => 'DESC',
]);
}
$search_total = $user_query instanceof WP_User_Query ? (int) $user_query->get_total() : (int) $wp_query->found_posts;
if ($search_query !== '' && $search_total > 0 && $paged <= 1 && function_exists('aksrt_update_search_keywords')) {
aksrt_update_search_keywords($history_value);
}
get_header();
if (is_active_sidebar('search_top_fluid')) {
echo '<div class="fluid-widget-wrap">';
dynamic_sidebar('search_top_fluid');
echo '</div>';
}
?>
<main class="container">
<div class="content-wrap">
<div class="content-layout">
<?php if (is_active_sidebar('search_top_content')) dynamic_sidebar('search_top_content'); ?>
<?php
$search_args = [
'class' => 'main-search page-search-box',
'show_posts' => false,
'in_cat' => $search_category,
'in_type' => $search_type,
'in_user' => $search_user,
's' => $search_query,
];
echo '<div class="aksrt-panel"' . ($paged < 2 ? ' win-ajax-replace="search"' : '') . '>';
if (function_exists('aksrt_get_main_search')) aksrt_get_main_search($search_args, true);
echo '</div>';
$base_url = add_query_arg(['s' => $search_query, 'user' => $search_user], home_url('/'));
$tab_nav = '';
foreach ($search_types as $key => $label) {
if ($search_type === $key) {
$tab_nav .= '<li class="active"><a class="focus-color" href="javascript:;">' . esc_html($label) . '</a></li>';
} else {
$tab_nav .= '<li><a ajax-replace="true" route="1" class="ajax-next" href="' . esc_url(add_query_arg('type', $key, $base_url)) . '">' . esc_html($label) . '</a></li>';
}
}
$tab_nav = '<div class="list-inline scroll-x mini-scrollbar tab-nav-theme">' . $tab_nav . '</div>';
$description = sprintf(
__('搜索 %1$s ,共找到 %2$s 个%3$s', 'aksrt'),
'<b class="search-key focus-color">' . esc_html($search_query) . '</b>',
'<b class="focus-color">' . esc_html(number_format_i18n($search_total)) . '</b>',
esc_html($search_types[$search_type] ?? __('内容', 'aksrt'))
);
?>
<div class="ajaxpager search-page-ajaxpager">
<div class="ajax-item-header type-<?php echo esc_attr($search_type); ?>">
<div class="search-desc-text mb10 mt10 muted-2-color"><?php echo wp_kses_post($description); ?></div>
<div class="search-tab-header aksrt-panel relative padding-h10"><div><?php echo $tab_nav; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div><div class="search-tab-filter"><?php echo function_exists('aksrt_get_search_tab_nav_filter') ? aksrt_get_search_tab_nav_filter($search_type) : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div></div>
</div>
<?php if ($search_query === '') : ?>
<div class="aksrt-panel search-content"><div class="text-center muted-2-color padding-20"><?php esc_html_e('请输入搜索关键词', 'aksrt'); ?></div></div>
<?php elseif ($user_query instanceof WP_User_Query && $user_query->get_results()) : ?>
<div class="aksrt-panel">
<?php foreach ($user_query->get_results() as $result_user) :
$user_id = (int) $result_user->ID;
$user_url = function_exists('aksrt_get_user_home_url') ? aksrt_get_user_home_url($user_id) : get_author_posts_url($user_id);
?>
<a class="author-minicard radius8 flex ac ajax-item" href="<?php echo esc_url($user_url); ?>">
<span class="avatar-img mr10"><?php echo function_exists('aksrt_get_avatar_html') ? aksrt_get_avatar_html($user_id, 48) : get_avatar($user_id, 48); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
<span class="flex1"><b><?php echo esc_html($result_user->display_name); ?></b><span class="muted-2-color em09 block text-ellipsis"><?php echo esc_html(wp_trim_words((string) $result_user->description, 16)); ?></span></span>
</a>
<?php endforeach; ?>
</div>
<?php
$user_pages = (int) ceil($search_total / 12);
if ($user_pages > 1) {
echo '<div class="text-center theme-pagination ajax-pag">' . paginate_links(['base' => esc_url_raw(add_query_arg('user_paged', '%#%')), 'current' => $user_page, 'total' => $user_pages, 'prev_text' => '<i class="fa fas fa-angle-left"></i>', 'next_text' => '<i class="fa fas fa-angle-right"></i>']) . '</div>';
}
?>
<?php elseif ($search_type === 'post' && $wp_query->have_posts()) : ?>
<?php
$config = function_exists('aksrt_archive_get_render_config') ? aksrt_archive_get_render_config(['context' => 'search', 'highlight_query' => $search_query]) : ['context' => 'search', 'mode' => 'list'];
aksrt_render_post_list(array_merge($config, ['wrapper_class' => 'mtn6']), $wp_query);
?>
<?php aksrt_render_pagination($wp_query, ['query_context' => 'search', 'render_config' => $config]); ?>
<?php else : ?>
<div class="aksrt-panel search-content"><div class="text-center muted-2-color padding-20"><?php esc_html_e('未找到相关内容', 'aksrt'); ?></div></div>
<?php endif; ?>
<div class="post_ajax_loader search-loader"><?php echo function_exists('aksrt_render_placeholder') ? aksrt_render_placeholder('list', 6) : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- 固定骨架结构。 ?></div>
</div>
<?php if (is_active_sidebar('search_bottom_content')) dynamic_sidebar('search_bottom_content'); ?>
</div>
</div>
<?php get_sidebar(); ?>
</main>
<?php
if (is_active_sidebar('search_bottom_fluid')) {
echo '<div class="fluid-widget-wrap">';
dynamic_sidebar('search_bottom_fluid');
echo '</div>';
}
get_footer();