feat(widgets): Stats count-up + product oneline swiper-nav

Wire data-aksrt-countup for numeric stats; oneline products use
swiper-scroll slides with prev/next; batch12 CSS for video/links/oneline.
This commit is contained in:
2026-07-21 08:36:00 +08:00
parent af8f97ad3c
commit 0cf3d440e2
3 changed files with 188 additions and 24 deletions
+43 -23
View File
@@ -93,6 +93,7 @@ class WidgetProductList extends \WP_Widget {
if (!$products->have_posts()) {
return '';
}
$oneline = $style === 'oneline';
ob_start();
while ($products->have_posts()) {
$products->the_post();
@@ -100,30 +101,36 @@ class WidgetProductList extends \WP_Widget {
$card = class_exists('\AKSRT\Shop\Shop')
? \AKSRT\Shop\Shop::get_instance()->build_product_card_view($pid)
: [];
if ($oneline) {
echo '<div class="swiper-slide ajax-item">';
}
if (function_exists('get_template_part') && !empty($card['id'])) {
get_template_part('templates/parts/shop/product', 'card', [
'product' => $card,
'show_sales' => true,
]);
continue;
} else {
// Fallback mini card.
$price = (float) ($card['price'] ?? 0);
$image = (string) ($card['image'] ?? '');
echo '<div class="aksrt-product-widget__item ajax-item">';
if ($image !== '') {
echo '<a href="' . esc_url(get_permalink($pid)) . '" class="aksrt-product-widget__thumb">';
echo '<img src="' . esc_url($image) . '" alt="' . esc_attr(get_the_title($pid)) . '" loading="lazy">';
echo '</a>';
}
echo '<div class="aksrt-product-widget__info">';
echo '<a href="' . esc_url(get_permalink($pid)) . '" class="aksrt-product-widget__title">' . esc_html(get_the_title($pid)) . '</a>';
echo '<div class="aksrt-product-widget__meta">';
echo '<span class="aksrt-product-widget__price">&yen;' . esc_html(number_format_i18n($price, 2)) . '</span>';
if (!empty($card['sales'])) {
echo '<span class="aksrt-product-widget__sales">' . esc_html((string) $card['sales']) . esc_html__(' 已售', 'aksrt') . '</span>';
}
echo '</div></div></div>';
}
// Fallback mini card.
$price = (float) ($card['price'] ?? 0);
$image = (string) ($card['image'] ?? '');
echo '<div class="aksrt-product-widget__item ajax-item">';
if ($image !== '') {
echo '<a href="' . esc_url(get_permalink($pid)) . '" class="aksrt-product-widget__thumb">';
echo '<img src="' . esc_url($image) . '" alt="' . esc_attr(get_the_title($pid)) . '" loading="lazy">';
echo '</a>';
if ($oneline) {
echo '</div>';
}
echo '<div class="aksrt-product-widget__info">';
echo '<a href="' . esc_url(get_permalink($pid)) . '" class="aksrt-product-widget__title">' . esc_html(get_the_title($pid)) . '</a>';
echo '<div class="aksrt-product-widget__meta">';
echo '<span class="aksrt-product-widget__price">&yen;' . esc_html(number_format_i18n($price, 2)) . '</span>';
if (!empty($card['sales'])) {
echo '<span class="aksrt-product-widget__sales">' . esc_html((string) $card['sales']) . esc_html__(' 已售', 'aksrt') . '</span>';
}
echo '</div></div></div>';
}
wp_reset_postdata();
return (string) ob_get_clean();
@@ -231,12 +238,25 @@ class WidgetProductList extends \WP_Widget {
$style_class = 'aksrt-product-widget--' . $style;
echo '<div class="aksrt-product-widget ' . esc_attr($style_class) . '" data-aksrt-product-widget data-aksrt-product-config="' . esc_attr(wp_json_encode($cfg)) . '">';
// Items sit directly under .ajaxpager so ajax-list inject/append works (zibll product-lists-row).
echo '<div class="ajaxpager aksrt-product-widget__grid product-lists-row" data-aksrt-ajaxpager data-aksrt-ajax-url="' . esc_url($ajax_url) . '">';
echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped — cards escaped upstream
echo $payload['paginate_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<div class="post_ajax_loader" data-aksrt-ajax-loader data-aksrt-ajax-loader-hide hidden></div>';
echo '</div></div>';
if ($style === 'oneline') {
// zibll-style horizontal swiper-scroll (shared slider.js Type A).
echo '<div class="swiper-container swiper-scroll aksrt-product-oneline-swiper">';
echo '<div class="swiper-wrapper product-lists-row">';
echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '</div>';
echo '<div class="swiper-button-prev" aria-label="' . esc_attr__('上一页', 'aksrt') . '"></div>';
echo '<div class="swiper-button-next" aria-label="' . esc_attr__('下一页', 'aksrt') . '"></div>';
echo '</div>';
} else {
// Items sit directly under .ajaxpager so ajax-list inject/append works (zibll product-lists-row).
echo '<div class="ajaxpager aksrt-product-widget__grid product-lists-row" data-aksrt-ajaxpager data-aksrt-ajax-url="' . esc_url($ajax_url) . '">';
echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped — cards escaped upstream
echo $payload['paginate_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<div class="post_ajax_loader" data-aksrt-ajax-loader data-aksrt-ajax-loader-hide hidden></div>';
echo '</div>';
}
echo '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
+16 -1
View File
@@ -67,7 +67,22 @@ class WidgetStats extends \WP_Widget {
if ($s['prefix'] !== '') {
echo '<span class="aksrt-stats__prefix">' . esc_html($s['prefix']) . '</span>';
}
echo '<span class="aksrt-stats__number" data-target="' . esc_attr($s['number']) . '">' . esc_html($s['number']) . '</span>';
// Wire effects.js count-up when number is numeric.
$raw_num = preg_replace('/[^\d.]/', '', (string) $s['number']);
$is_numeric = $raw_num !== '' && is_numeric($raw_num);
if ($is_numeric) {
$dec = 0;
if (str_contains((string) $raw_num, '.')) {
$dec = strlen(substr(strrchr((string) $raw_num, '.'), 1));
}
printf(
'<span class="aksrt-stats__number" data-aksrt-countup data-target="%s" data-duration="1600" data-decimals="%d">0</span>',
esc_attr((string) $raw_num),
(int) $dec
);
} else {
echo '<span class="aksrt-stats__number" data-target="' . esc_attr($s['number']) . '">' . esc_html($s['number']) . '</span>';
}
if ($s['unit'] !== '') {
echo '<span class="aksrt-stats__unit">' . esc_html($s['unit']) . '</span>';
}