feat(widgets): shared tab JS + main posts ajax load_mode

Move category/forum/product tab lazy load into widget-set.js with
skeletons; MainPosts gains load_mode=ajax first-paint placeholders.
This commit is contained in:
2026-07-21 12:42:58 +08:00
parent 6a78b553d6
commit aed056152c
5 changed files with 344 additions and 154 deletions
+275 -8
View File
@@ -9,8 +9,16 @@
(function () {
'use strict';
function restHeaders() {
var headers = { Accept: 'application/json' };
if (window.aksrtData && aksrtData.restNonce) {
headers['X-WP-Nonce'] = aksrtData.restNonce;
}
return headers;
}
function initWidgetTabs() {
document.querySelectorAll('.widget-tab-posts').forEach(function (widget) {
document.querySelectorAll('.widget-tab-posts[data-aksrt-tab-posts]').forEach(function (widget) {
if (widget.dataset.aksrtWidgetTabsBound === '1') return;
widget.dataset.aksrtWidgetTabsBound = '1';
@@ -37,11 +45,7 @@
});
var url = rest + (rest.indexOf('?') > -1 ? '&' : '?') + qs.toString();
panel.classList.add('is-ajax-loading');
var headers = { Accept: 'application/json' };
if (window.aksrtData && aksrtData.restNonce) {
headers['X-WP-Nonce'] = aksrtData.restNonce;
}
fetch(url, { credentials: 'same-origin', headers: headers })
fetch(url, { credentials: 'same-origin', headers: restHeaders() })
.then(function (r) { return r.json(); })
.then(function (j) {
var d = (j && j.data) || j || {};
@@ -59,16 +63,16 @@
tabs.forEach(function (tab) {
tab.addEventListener('click', function () {
var target = tab.getAttribute('data-tab');
tabs.forEach(function (item) {
var active = item === tab;
item.classList.toggle('active', active);
item.classList.toggle('is-active', active);
item.setAttribute('aria-selected', active ? 'true' : 'false');
});
panels.forEach(function (panel) {
var active = panel.getAttribute('data-tab-panel') === target;
panel.classList.toggle('active', active);
panel.classList.toggle('is-active', active);
if (active) {
panel.removeAttribute('hidden');
loadPanel(panel, tab);
@@ -81,6 +85,265 @@
});
}
// Homepage category tabs (was inline in CategoryTabsWidget).
function initCategoryTabs() {
document.querySelectorAll('[data-aksrt-home-cat-tabs]').forEach(function (section) {
if (section.dataset.aksrtCatTabsBound === '1') return;
section.dataset.aksrtCatTabsBound = '1';
var rest = section.getAttribute('data-rest') || '';
var count = section.getAttribute('data-count') || '6';
var layout = section.getAttribute('data-layout') || 'card';
var columns = section.getAttribute('data-columns') || '3';
var context = section.getAttribute('data-context') || 'homepage';
var showMore = section.getAttribute('data-show-more') === '1';
var tabs = [].slice.call(section.querySelectorAll('.widget-tab-posts__tab'));
var panels = [].slice.call(section.querySelectorAll('.widget-tab-posts__panel'));
if (!tabs.length || !panels.length || !rest) return;
function load(panel) {
if (!panel || panel.getAttribute('data-loaded') === '1') return;
var cat = panel.getAttribute('data-cat') || '0';
var more = panel.getAttribute('data-more') || '';
var qs = new URLSearchParams({
cat: cat,
count: String(count),
layout: layout,
columns: String(columns),
context: context,
});
var url = rest + (rest.indexOf('?') > -1 ? '&' : '?') + qs.toString();
panel.classList.add('is-ajax-loading');
fetch(url, { credentials: 'same-origin', headers: restHeaders() })
.then(function (r) { return r.json(); })
.then(function (j) {
var d = (j && j.data) || j || {};
var html = d.html || '';
if (showMore && more) {
html += '<div class="aksrt-home-widget__footer"><a class="aksrt-home-widget__more" href="' + more + '">查看更多</a></div>';
}
panel.innerHTML = html || '<div class="ajax-item widget-empty muted-2-color">暂无文章</div>';
panel.setAttribute('data-loaded', '1');
panel.classList.remove('is-ajax-loading');
})
.catch(function () {
panel.classList.remove('is-ajax-loading');
});
}
tabs.forEach(function (tab) {
tab.addEventListener('click', function () {
var target = tab.getAttribute('data-tab');
tabs.forEach(function (item) {
var active = item === tab;
item.classList.toggle('active', active);
item.setAttribute('aria-selected', active ? 'true' : 'false');
});
panels.forEach(function (panel) {
var active = panel.getAttribute('data-tab-panel') === target;
panel.classList.toggle('active', active);
if (active) {
panel.removeAttribute('hidden');
load(panel);
} else {
panel.setAttribute('hidden', '');
}
});
});
});
});
}
// Forum multi-tab topics.
function initForumTabTopics() {
document.querySelectorAll('.aksrt-ftab[data-aksrt-ftab]').forEach(function (root) {
if (root.dataset.aksrtFtabBound === '1') return;
root.dataset.aksrtFtabBound = '1';
var rest = root.getAttribute('data-rest') || '';
var count = root.getAttribute('data-count') || '6';
var style = root.getAttribute('data-style') || 'mini';
var plate = root.getAttribute('data-plate') || '0';
var btns = [].slice.call(root.querySelectorAll('.aksrt-ftab__btn'));
var panels = [].slice.call(root.querySelectorAll('.aksrt-ftab__panel'));
function load(panel, orderby) {
if (!panel || panel.getAttribute('data-loaded') === '1' || !rest) return;
var qs = new URLSearchParams({
page: '1',
count: count,
orderby: orderby || 'date',
style: style,
plate: plate,
period: 'all',
paginate: 'none',
});
var url = rest + (rest.indexOf('?') > -1 ? '&' : '?') + qs.toString();
panel.classList.add('is-ajax-loading');
fetch(url, { credentials: 'same-origin', headers: restHeaders() })
.then(function (r) { return r.json(); })
.then(function (j) {
var d = (j && j.data) || j || {};
var html = d.html || '';
panel.innerHTML = html || '<div class="ajax-item aksrt-ftab__empty muted-2-color">暂无内容</div>';
panel.setAttribute('data-loaded', '1');
panel.classList.remove('is-ajax-loading');
})
.catch(function () {
panel.classList.remove('is-ajax-loading');
});
}
function go(i) {
btns.forEach(function (b, idx) {
var on = idx === i;
b.classList.toggle('is-active', on);
b.setAttribute('aria-selected', on ? 'true' : 'false');
});
panels.forEach(function (p, idx) {
var on = idx === i;
p.classList.toggle('is-active', on);
if (on) {
p.removeAttribute('hidden');
} else {
p.setAttribute('hidden', '');
}
});
var btn = btns[i];
var panel = panels[i];
if (btn && panel) load(panel, btn.getAttribute('data-orderby') || 'date');
}
btns.forEach(function (b) {
b.addEventListener('click', function () {
go(parseInt(b.getAttribute('data-index') || '0', 10));
});
});
});
}
// Product multi-tab.
function initProductTabs() {
document.querySelectorAll('[data-aksrt-product-tab]').forEach(function (root) {
if (root.dataset.aksrtProductTabBound === '1') return;
root.dataset.aksrtProductTabBound = '1';
var rest = root.getAttribute('data-rest') || '';
var per = root.getAttribute('data-per-page') || '8';
var style = root.getAttribute('data-style') || 'default';
var paginate = root.getAttribute('data-paginate') || 'ajax';
function skeleton(n) {
n = Math.max(1, Math.min(12, parseInt(n, 10) || 4));
var html = '<div class="aksrt-product-tab__skeleton">';
for (var i = 0; i < n; i++) {
html += '<div class="placeholder-row product-card-placeholder"><div class="placeholder thumb"></div><div class="placeholder k1"></div><div class="placeholder s1"></div></div>';
}
return html + '</div>';
}
function loadPanel(panel, btn) {
if (!panel || panel.getAttribute('data-loaded') === '1' || !rest) return;
var grid = panel.querySelector('[data-aksrt-ajaxpager]');
if (!grid) return;
var qs = new URLSearchParams({
page: '1',
per_page: per,
style: style,
paginate: paginate,
orderby: btn.getAttribute('data-orderby') || 'date',
order: 'DESC',
cat_ids: btn.getAttribute('data-cat-ids') || '',
tag_ids: btn.getAttribute('data-tag-ids') || '',
discount_ids: btn.getAttribute('data-discount-ids') || '',
});
var url = rest + (rest.indexOf('?') > -1 ? '&' : '?') + qs.toString();
grid.classList.add('is-ajax-loading');
if (!grid.querySelector('.aksrt-product-tab__skeleton') && !grid.querySelector('.ajax-item')) {
grid.insertAdjacentHTML('afterbegin', skeleton(per));
}
fetch(url, { credentials: 'same-origin', headers: restHeaders() })
.then(function (r) { return r.json(); })
.then(function (j) {
var d = (j && j.data && (j.data.data || j.data)) || j || {};
var html = d.html || '';
var pag = d.paginate_html || d.paginateHtml || '';
var loader = grid.querySelector('[data-aksrt-ajax-loader]');
grid.innerHTML = '';
if (html) grid.insertAdjacentHTML('beforeend', html);
else grid.insertAdjacentHTML('beforeend', '<p class="widget-empty ajax-item">暂无商品</p>');
if (pag) grid.insertAdjacentHTML('beforeend', pag);
if (loader) grid.appendChild(loader);
panel.setAttribute('data-loaded', '1');
grid.classList.remove('is-ajax-loading');
})
.catch(function () {
grid.classList.remove('is-ajax-loading');
});
}
root.querySelectorAll('.aksrt-product-tab__header').forEach(function (btn) {
btn.addEventListener('click', function () {
root.querySelectorAll('.aksrt-product-tab__header').forEach(function (b) {
b.classList.remove('is-active');
});
root.querySelectorAll('.aksrt-product-tab__panel').forEach(function (p) {
p.style.display = 'none';
p.classList.remove('is-active');
});
btn.classList.add('is-active');
var idx = btn.getAttribute('data-tab-index');
var panel = root.querySelector('.aksrt-product-tab__panel[data-tab-index="' + idx + '"]');
if (panel) {
panel.style.display = '';
panel.classList.add('is-active');
loadPanel(panel, btn);
}
});
});
});
}
// Main posts load_mode=ajax first paint.
function initMainPostsLazy() {
document.querySelectorAll('.aksrt-main-posts[data-load-mode="ajax"]').forEach(function (root) {
if (root.dataset.aksrtMainLazyBound === '1') return;
root.dataset.aksrtMainLazyBound = '1';
if (root.getAttribute('data-loaded') === '1') return;
var rest = root.getAttribute('data-aksrt-ajax-url') || root.getAttribute('data-rest') || '';
if (!rest) return;
var qs = root.getAttribute('data-query') || '';
var url = rest + (rest.indexOf('?') > -1 ? '&' : '?') + (qs || 'page=1');
root.classList.add('is-ajax-loading');
fetch(url, { credentials: 'same-origin', headers: restHeaders() })
.then(function (r) { return r.json(); })
.then(function (j) {
var d = (j && j.data) || j || {};
var html = d.html || '';
var pag = d.paginate_html || d.paginateHtml || '';
var loader = root.querySelector('[data-aksrt-ajax-loader]');
// Remove skeleton rows.
root.querySelectorAll('.aksrt-main-posts__skeleton, .posts-mini.placeholder-row, .placeholder-row').forEach(function (n) {
n.remove();
});
if (html) {
root.insertAdjacentHTML('afterbegin', html);
} else {
root.insertAdjacentHTML('afterbegin', '<p class="widget-empty ajax-item">暂无文章</p>');
}
// Replace/append paginate.
var oldPag = root.querySelector('.ajax-pag, .pagenav.ajax-pag');
if (oldPag) oldPag.remove();
if (pag) {
if (loader) loader.insertAdjacentHTML('beforebegin', pag);
else root.insertAdjacentHTML('beforeend', pag);
}
root.setAttribute('data-loaded', '1');
root.classList.remove('is-ajax-loading');
})
.catch(function () {
root.classList.remove('is-ajax-loading');
});
});
}
function initFloatingQRCodes() {
var wrap = document.querySelector('.float-right');
if (!wrap) return;
@@ -121,6 +384,10 @@
function init() {
initWidgetTabs();
initCategoryTabs();
initForumTabTopics();
initProductTabs();
initMainPostsLazy();
initFloatingQRCodes();
}
+6 -55
View File
@@ -38,7 +38,7 @@ class CategoryTabsWidget extends \WP_Widget {
$tabs = $this->resolve_tabs($instance);
echo $args['before_widget'];
echo '<section class="aksrt-home-widget aksrt-home-widget--tabs widget-tab-posts" data-aksrt-home-cat-tabs data-aksrt-tabs="1">';
echo '<section class="aksrt-home-widget aksrt-home-widget--tabs widget-tab-posts" data-aksrt-home-cat-tabs data-aksrt-tabs="1" data-rest="' . esc_url(rest_url('aksrt/v1/widgets/category-tabs')) . '" data-count="' . esc_attr((string) $count) . '" data-layout="' . esc_attr($layout) . '" data-columns="' . esc_attr((string) $columns) . '" data-context="' . esc_attr($context) . '" data-show-more="' . (!empty($show_more) ? '1' : '0') . '">';
if (empty($tabs)) {
echo function_exists('aksrt_get_widget_null') ? aksrt_get_widget_null(__('暂无可用分类', 'aksrt')) : '<p class="widget-empty">' . esc_html__('暂无可用分类', 'aksrt') . '</p>';
@@ -95,65 +95,16 @@ class CategoryTabsWidget extends \WP_Widget {
</div>
<?php endif;
else : ?>
<div class="post_ajax_loader" data-aksrt-ajax-loader></div>
<div class="post_ajax_loader" data-aksrt-ajax-loader>
<?php for ($si = 0; $si < $count; $si++) : ?>
<div class="posts-mini placeholder-row"><div class="placeholder radius thumb-placeholder"></div><div class="flex1"><div class="placeholder k1"></div><div class="placeholder s1 mt6"></div></div></div>
<?php endfor; ?>
</div>
<?php endif; ?>
</div>
<?php
}
$rest = rest_url('aksrt/v1/widgets/category-tabs');
?>
<script>
(function(){
var section=document.currentScript?document.currentScript.parentElement:null;
if(!section||section._aksrtCatTabs)return; section._aksrtCatTabs=1;
var rest=<?php echo wp_json_encode($rest); ?>;
var count=<?php echo (int) $count; ?>;
var layout=<?php echo wp_json_encode($layout); ?>;
var columns=<?php echo (int) $columns; ?>;
var context=<?php echo wp_json_encode($context); ?>;
var showMore=<?php echo $show_more ? 'true' : 'false'; ?>;
var tabs=[].slice.call(section.querySelectorAll('.widget-tab-posts__tab'));
var panels=[].slice.call(section.querySelectorAll('.widget-tab-posts__panel'));
function load(panel){
if(!panel||panel.getAttribute('data-loaded')==='1')return;
var cat=panel.getAttribute('data-cat')||'0';
var more=panel.getAttribute('data-more')||'';
var qs=new URLSearchParams({cat:cat,count:String(count),layout:layout,columns:String(columns),context:context});
var url=rest+(rest.indexOf('?')>-1?'&':'?')+qs.toString();
panel.classList.add('is-ajax-loading');
var headers={Accept:'application/json'};
if(window.aksrtData&&aksrtData.restNonce)headers['X-WP-Nonce']=aksrtData.restNonce;
fetch(url,{credentials:'same-origin',headers:headers}).then(function(r){return r.json()}).then(function(j){
var d=(j&&j.data)||j||{};
var html=d.html||'';
if(showMore&&more){
html+='<div class="aksrt-home-widget__footer"><a class="aksrt-home-widget__more" href="'+more+'">查看更多</a></div>';
}
panel.innerHTML=html||'<div class="ajax-item widget-empty muted-2-color">暂无文章</div>';
panel.setAttribute('data-loaded','1');
panel.classList.remove('is-ajax-loading');
}).catch(function(){panel.classList.remove('is-ajax-loading');});
}
tabs.forEach(function(tab){
tab.addEventListener('click',function(){
var target=tab.getAttribute('data-tab');
tabs.forEach(function(item){
var active=item===tab;
item.classList.toggle('active',active);
item.setAttribute('aria-selected',active?'true':'false');
});
panels.forEach(function(panel){
var active=panel.getAttribute('data-tab-panel')===target;
panel.classList.toggle('active',active);
if(active){panel.removeAttribute('hidden');load(panel);} else {panel.setAttribute('hidden','');}
});
});
});
})();
</script>
<?php
echo '</section>';
echo $args['after_widget'];
}
+1 -45
View File
@@ -50,7 +50,7 @@ class WidgetForumTabTopics extends \WP_Widget {
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
echo '<div class="aksrt-ftab widget-tab-posts" id="' . $uid . '" data-aksrt-tabs="1" data-rest="' . esc_url($rest) . '" data-count="' . esc_attr((string) $count) . '" data-style="' . esc_attr($style) . '" data-plate="' . esc_attr((string) $plate) . '">';
echo '<div class="aksrt-ftab widget-tab-posts" id="' . $uid . '" data-aksrt-tabs="1" data-aksrt-ftab="1" data-rest="' . esc_url($rest) . '" data-count="' . esc_attr((string) $count) . '" data-style="' . esc_attr($style) . '" data-plate="' . esc_attr((string) $plate) . '">';
echo '<ul class="aksrt-ftab__nav widget-tab-posts__nav" role="tablist">';
foreach ($tabs as $i => $tab) {
$cls = $i === 0 ? ' is-active' : '';
@@ -78,50 +78,6 @@ class WidgetForumTabTopics extends \WP_Widget {
echo '</div>';
}
echo '</div>';
?>
<script>
(function(){
var root=document.getElementById(<?php echo wp_json_encode($uid); ?>);
if(!root||root._aksrtFtab)return; root._aksrtFtab=1;
var rest=root.getAttribute('data-rest')||'';
var count=root.getAttribute('data-count')||'6';
var style=root.getAttribute('data-style')||'mini';
var plate=root.getAttribute('data-plate')||'0';
var btns=[].slice.call(root.querySelectorAll('.aksrt-ftab__btn'));
var panels=[].slice.call(root.querySelectorAll('.aksrt-ftab__panel'));
function load(panel, orderby){
if(!panel||panel.getAttribute('data-loaded')==='1'||!rest)return;
var qs=new URLSearchParams({page:'1',count:count,orderby:orderby||'date',style:style,plate:plate,period:'all',paginate:'none'});
var url=rest+(rest.indexOf('?')>-1?'&':'?')+qs.toString();
panel.classList.add('is-ajax-loading');
fetch(url,{credentials:'same-origin',headers:{Accept:'application/json','X-WP-Nonce':(window.aksrtData&&aksrtData.restNonce)||''}})
.then(function(r){return r.json()}).then(function(j){
var d=(j&&j.data)||j||{};
var html=d.html||'';
panel.innerHTML=html||'<div class="ajax-item aksrt-ftab__empty muted-2-color">暂无内容</div>';
panel.setAttribute('data-loaded','1');
panel.classList.remove('is-ajax-loading');
}).catch(function(){panel.classList.remove('is-ajax-loading');});
}
function go(i){
btns.forEach(function(b,idx){
var on=idx===i;
b.classList.toggle('is-active',on);
b.setAttribute('aria-selected',on?'true':'false');
});
panels.forEach(function(p,idx){
var on=idx===i;
p.classList.toggle('is-active',on);
if(on){p.removeAttribute('hidden');}else{p.setAttribute('hidden','');}
});
var btn=btns[i], panel=panels[i];
if(btn&&panel) load(panel, btn.getAttribute('data-orderby')||'date');
}
btns.forEach(function(b){ b.addEventListener('click', function(){ go(parseInt(b.getAttribute('data-index')||'0',10)); }); });
})();
</script>
<?php
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
+56 -11
View File
@@ -255,6 +255,7 @@ class WidgetMainPosts extends \WP_Widget {
'show_meta' => !isset($instance['show_meta']) || !empty($instance['show_meta']) ? 1 : 0,
'show_number' => !empty($instance['show_number']) ? 1 : 0,
'paginate' => $paginate,
'load_mode' => sanitize_key((string) ($new_instance['load_mode'] ?? 'detail')) === 'ajax' ? 'ajax' : 'detail',
], static function ($v) {
return $v !== '' && $v !== null;
});
@@ -288,28 +289,63 @@ class WidgetMainPosts extends \WP_Widget {
$style = 'list';
}
$paginate = sanitize_key((string) ($instance['paginate'] ?? 'none'));
if (!in_array($paginate, ['none', 'ajax', 'number'], true)) {
$paginate = 'none';
}
$load_mode = sanitize_key((string) ($instance['load_mode'] ?? 'detail'));
if (!in_array($load_mode, ['detail', 'ajax'], true)) {
$load_mode = 'detail';
}
$instance['style'] = $style;
$instance['paginate'] = $paginate;
$payload = self::query_payload($instance, 1);
if ($payload['html'] === '' && empty($payload['total'])) {
return;
}
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
if ($title !== '') {
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
$count = max(1, min(30, (int) ($instance['count'] ?? 6)));
$rest = rest_url('aksrt/v1/widgets/posts');
$qs = http_build_query(array_filter([
'page' => 1,
'count' => $count,
'orderby' => sanitize_key((string) ($instance['orderby'] ?? 'date')),
'cat' => (int) ($instance['cat'] ?? 0),
'limit_day' => (int) ($instance['limit_day'] ?? 0),
'topics' => (string) ($instance['topics'] ?? ''),
'pay_type' => sanitize_key((string) ($instance['pay_type'] ?? '')),
'style' => $style,
'show_thumb' => !isset($instance['show_thumb']) || !empty($instance['show_thumb']) ? 1 : 0,
'show_meta' => !isset($instance['show_meta']) || !empty($instance['show_meta']) ? 1 : 0,
'show_number' => !empty($instance['show_number']) ? 1 : 0,
'paginate' => $paginate,
'load_mode' => sanitize_key((string) ($new_instance['load_mode'] ?? 'detail')) === 'ajax' ? 'ajax' : 'detail',
], static function ($v) {
return $v !== '' && $v !== null;
}));
$wrap_cls = 'aksrt-main-posts style-' . $style . ' ajaxpager';
if ($style === 'mini') {
$wrap_cls .= ' zib-widget posts-mini-lists';
}
echo '<div class="' . esc_attr($wrap_cls) . '" data-aksrt-ajaxpager data-aksrt-ajax-url="' . esc_url($rest) . '">';
echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $payload['paginate_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<div class="' . esc_attr($wrap_cls) . '" data-aksrt-ajaxpager data-aksrt-ajax-url="' . esc_url($rest) . '" data-load-mode="' . esc_attr($load_mode) . '" data-query="' . esc_attr($qs) . '"' . ($load_mode === 'ajax' ? ' data-loaded="0"' : ' data-loaded="1"') . '>';
if ($load_mode === 'ajax') {
// Skeleton first paint (zibll load_mode=ajax).
echo '<div class="aksrt-main-posts__skeleton">';
for ($si = 0; $si < $count; $si++) {
if ($style === 'card') {
echo '<div class="placeholder-row card"><div class="placeholder thumb"></div><div class="placeholder k1"></div></div>';
} else {
echo '<div class="posts-mini placeholder-row"><div class="placeholder radius thumb-placeholder"></div><div class="flex1"><div class="placeholder t1 k1"></div><div class="placeholder s1"></div></div></div>';
}
}
echo '</div>';
} else {
$payload = self::query_payload($instance, 1);
echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
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>';
@@ -345,8 +381,8 @@ class WidgetMainPosts extends \WP_Widget {
<option value="views" <?php selected(($instance['orderby'] ?? ''), 'views'); ?>><?php esc_html_e('浏览', 'aksrt'); ?></option>
<option value="comments" <?php selected(($instance['orderby'] ?? ''), 'comments'); ?>><?php esc_html_e('评论', 'aksrt'); ?></option>
<option value="likes" <?php selected(($instance['orderby'] ?? ''), 'likes'); ?>><?php esc_html_e('点赞', 'aksrt'); ?></option>
<option value=\"favorites\" <?php selected(($instance['orderby'] ?? ''), 'favorites'); ?>><?php esc_html_e('收藏', 'aksrt'); ?></option>
<option value=\"downloads\" <?php selected(($instance['orderby'] ?? ''), 'downloads'); ?>><?php esc_html_e('下载', 'aksrt'); ?></option>
<option value="favorites" <?php selected(($instance['orderby'] ?? ''), 'favorites'); ?>><?php esc_html_e('收藏', 'aksrt'); ?></option>
<option value="downloads" <?php selected(($instance['orderby'] ?? ''), 'downloads'); ?>><?php esc_html_e('下载', 'aksrt'); ?></option>
<option value="rand" <?php selected(($instance['orderby'] ?? ''), 'rand'); ?>><?php esc_html_e('随机', 'aksrt'); ?></option>
</select>
</label>
@@ -361,7 +397,15 @@ class WidgetMainPosts extends \WP_Widget {
<input class="tiny-text" type="number" min="0" name="<?php echo esc_attr($this->get_field_name('limit_day')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['limit_day'] ?? 0))); ?>">
</label>
</p>
<p>
<p>
<label><?php esc_html_e('模块加载', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('load_mode')); ?>">
<option value="detail" <?php selected(($instance['load_mode'] ?? 'detail'), 'detail'); ?>><?php esc_html_e('直接加载', 'aksrt'); ?></option>
<option value="ajax" <?php selected(($instance['load_mode'] ?? ''), 'ajax'); ?>><?php esc_html_e('AJAX 懒加载', 'aksrt'); ?></option>
</select>
</label>
</p>
<p>
<label><?php esc_html_e('分页', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('paginate')); ?>">
<option value="none" <?php selected(($instance['paginate'] ?? 'none'), 'none'); ?>><?php esc_html_e('无', 'aksrt'); ?></option>
@@ -419,6 +463,7 @@ class WidgetMainPosts extends \WP_Widget {
'topics' => sanitize_text_field((string) ($new_instance['topics'] ?? '')),
'pay_type' => sanitize_key((string) ($new_instance['pay_type'] ?? '')),
'paginate' => $paginate,
'load_mode' => sanitize_key((string) ($new_instance['load_mode'] ?? 'detail')) === 'ajax' ? 'ajax' : 'detail',
'show_thumb' => !empty($new_instance['show_thumb']) ? 1 : 0,
'show_meta' => !empty($new_instance['show_meta']) ? 1 : 0,
'show_number' => !empty($new_instance['show_number']) ? 1 : 0,
+6 -35
View File
@@ -105,47 +105,18 @@ class WidgetProductTab extends \WP_Widget {
echo '</div>';
} else {
echo '<div class="ajaxpager aksrt-product-widget__grid product-lists-row aksrt-product-widget--' . esc_attr($style) . ' is-lazy" data-aksrt-ajaxpager>';
echo '<div class="post_ajax_loader" data-aksrt-ajax-loader></div>';
echo '<div class="post_ajax_loader" data-aksrt-ajax-loader>';
echo '<div class="aksrt-product-tab__skeleton">';
for ($si = 0; $si < min(4, $per_page); $si++) {
echo '<div class="placeholder-row product-card-placeholder"><div class="placeholder thumb"></div><div class="placeholder k1"></div><div class="placeholder s1"></div></div>';
}
echo '</div></div>';
echo '<div class="ajax-pag hide"><div class="next-page ajax-next"><a href="#"></a></div></div>';
echo '</div>';
}
echo '</div>';
}
// Lightweight tab switch + lazy REST load (no inline product HTML duplication).
echo '<script>(function(){';
echo 'var root=document.currentScript&&document.currentScript.parentElement;if(!root)return;';
echo 'var rest=root.getAttribute("data-rest")||"";';
echo 'var per=root.getAttribute("data-per-page")||"8";';
echo 'var style=root.getAttribute("data-style")||"default";';
echo 'var paginate=root.getAttribute("data-paginate")||"ajax";';
echo 'function loadPanel(panel,btn){if(!panel||panel.getAttribute("data-loaded")==="1")return;';
echo 'var grid=panel.querySelector("[data-aksrt-ajaxpager]");if(!grid||!rest)return;';
echo 'var qs=new URLSearchParams({page:"1",per_page:per,style:style,paginate:paginate,';
echo 'orderby:btn.getAttribute("data-orderby")||"date",order:"DESC",';
echo 'cat_ids:btn.getAttribute("data-cat-ids")||"",tag_ids:btn.getAttribute("data-tag-ids")||"",';
echo 'discount_ids:btn.getAttribute("data-discount-ids")||""});';
echo 'var url=rest+(rest.indexOf("?")>-1?"&":"?")+qs.toString();';
echo 'grid.classList.add("is-ajax-loading");';
echo 'fetch(url,{credentials:"same-origin",headers:{Accept:"application/json","X-WP-Nonce":(window.aksrtData&&aksrtData.restNonce)||""}})';
echo '.then(function(r){return r.json()}).then(function(j){';
echo 'var d=(j&&j.data&&(j.data.data||j.data))||j||{};';
echo 'var html=d.html||""; var pag=d.paginate_html||d.paginateHtml||"";';
echo 'var loader=grid.querySelector("[data-aksrt-ajax-loader]");';
echo 'grid.innerHTML=""; if(html)grid.insertAdjacentHTML("beforeend",html); if(pag)grid.insertAdjacentHTML("beforeend",pag);';
echo 'if(loader)grid.appendChild(loader); panel.setAttribute("data-loaded","1"); grid.classList.remove("is-ajax-loading");';
echo '}).catch(function(){grid.classList.remove("is-ajax-loading");});}';
echo 'root.querySelectorAll(".aksrt-product-tab__header").forEach(function(btn){';
echo 'btn.addEventListener("click",function(){';
echo 'root.querySelectorAll(".aksrt-product-tab__header").forEach(function(b){b.classList.remove("is-active")});';
echo 'root.querySelectorAll(".aksrt-product-tab__panel").forEach(function(p){p.style.display="none"});';
echo 'btn.classList.add("is-active");';
echo 'var idx=btn.getAttribute("data-tab-index");';
echo 'var panel=root.querySelector(\'.aksrt-product-tab__panel[data-tab-index="\'+idx+\'"]\');';
echo 'if(panel){panel.style.display="";loadPanel(panel,btn);}';
echo '});});';
echo '})();</script>';
echo '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}