feat(shop): category filter bar + sort/load-more 1:1 UX
Port zibll hierarchical cat tabs, multi-metric sort with price toggle, skeleton/empty states, and REST archive payload (header/html/paginate) while reusing product-card template for AJAX HTML.
This commit is contained in:
1 parent
e2587ca3a0
commit
433b7cb3a6
9 files changed
+828
-273
No files matched your search
@@ -733,3 +733,23 @@
|
|||||||
.aksrt-revenue-page__item .is-in{color:#27ae60;font-weight:700}
|
.aksrt-revenue-page__item .is-in{color:#27ae60;font-weight:700}
|
||||||
.aksrt-revenue-page__item .is-out{color:#e74c3c;font-weight:700}
|
.aksrt-revenue-page__item .is-out{color:#e74c3c;font-weight:700}
|
||||||
.aksrt-product-editor__hint{font-size:13px;color:var(--color-ink-4,#8a909c);margin:0 0 10px}
|
.aksrt-product-editor__hint{font-size:13px;color:var(--color-ink-4,#8a909c);margin:0 0 10px}
|
||||||
|
|
||||||
|
/* ===== zibll-parity cat filter / skeleton ===== */
|
||||||
|
.aksrt-shop-cat-filter.shop-cat-filter{margin-top:14px}
|
||||||
|
.shop-cat-filter-tab{display:flex;gap:10px;overflow-x:auto;list-style:none;margin:0 0 10px;padding:0 0 4px;-webkit-overflow-scrolling:touch}
|
||||||
|
.shop-cat-filter-tab li{flex:0 0 auto}
|
||||||
|
.shop-cat-filter-tab a,
|
||||||
|
.shop-cat-filter-tab span,
|
||||||
|
.shop-cat-filter-child a,
|
||||||
|
.shop-cat-filter-child span{display:inline-flex;align-items:center;padding:6px 12px;border-radius:999px;font-size:13px;font-weight:600;text-decoration:none;color:var(--color-ink-2,#5c6370);background:var(--surface-4,#f3f4f6)}
|
||||||
|
.shop-cat-filter-tab .active span,
|
||||||
|
.shop-cat-filter-child .focus-color,
|
||||||
|
.shop-cat-filter-orderby .focus-color{color:var(--color-primary,#f04494);background:color-mix(in srgb,var(--color-primary,#f04494) 12%, #fff)}
|
||||||
|
.shop-cat-filter-child{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:0 0 10px}
|
||||||
|
.shop-cat-filter-orderby{gap:8px}
|
||||||
|
.shop-cat-filter-orderby .opacity5{opacity:.55;margin-right:4px;font-size:13px}
|
||||||
|
.aksrt-product-archive__skeleton{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;padding:8px 0 16px}
|
||||||
|
.aksrt-product-card--placeholder{min-height:220px;border-radius:12px;background:linear-gradient(90deg,#f3f4f6 25%,#e5e7eb 37%,#f3f4f6 63%);background-size:400% 100%;animation:aksrtShopSk 1.2s ease infinite}
|
||||||
|
@keyframes aksrtShopSk{0%{background-position:100% 0}100%{background-position:0 0}}
|
||||||
|
@media (max-width:992px){.aksrt-product-archive__skeleton{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
||||||
|
@media (max-width:560px){.aksrt-product-archive__skeleton{grid-template-columns:1fr}}
|
||||||
+191
-48
@@ -1,5 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Product archive — sort + AJAX load more.
|
* Product archive — cat filter + sort + AJAX load more (zibll ajax-next UX).
|
||||||
|
*
|
||||||
|
* Uses REST /shop/frontend/products/archive and optional AksrtAjaxList events.
|
||||||
*
|
*
|
||||||
* @package AKSRT
|
* @package AKSRT
|
||||||
*/
|
*/
|
||||||
@@ -10,7 +12,7 @@
|
|||||||
if (!root) return;
|
if (!root) return;
|
||||||
|
|
||||||
function restBase() {
|
function restBase() {
|
||||||
var site = (window.aksrtData && aksrtData.siteUrl) ? String(aksrtData.siteUrl).replace(/\/$/, "") : "";
|
var site = window.aksrtData && aksrtData.siteUrl ? String(aksrtData.siteUrl).replace(/\/$/, "") : "";
|
||||||
return site + "/wp-json/aksrt/v1";
|
return site + "/wp-json/aksrt/v1";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,12 +25,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var grid = root.querySelector("[data-aksrt-product-grid], #aksrt-product-grid");
|
var grid = root.querySelector("[data-aksrt-product-grid], #aksrt-product-grid");
|
||||||
|
var pager = root.querySelector("[data-aksrt-ajaxpager], .ajaxpager");
|
||||||
var countEl = root.querySelector("[data-aksrt-archive-count]");
|
var countEl = root.querySelector("[data-aksrt-archive-count]");
|
||||||
|
var headerHost = root.querySelector("[data-aksrt-ajax-header]");
|
||||||
var loadMoreBtn = root.querySelector("[data-aksrt-shop-load-more]");
|
var loadMoreBtn = root.querySelector("[data-aksrt-shop-load-more]");
|
||||||
|
var loader = root.querySelector("[data-aksrt-ajax-loader], .post_ajax_loader");
|
||||||
|
|
||||||
var state = {
|
var state = {
|
||||||
taxonomy: root.getAttribute("data-taxonomy") || "",
|
taxonomy: root.getAttribute("data-taxonomy") || "",
|
||||||
termId: Number(root.getAttribute("data-term-id") || 0),
|
termId: Number(root.getAttribute("data-term-id") || 0),
|
||||||
orderby: root.getAttribute("data-orderby") || "date",
|
orderby: root.getAttribute("data-orderby") || "date",
|
||||||
|
order: (root.getAttribute("data-order") || "DESC").toUpperCase(),
|
||||||
page: Number(root.getAttribute("data-page") || 1),
|
page: Number(root.getAttribute("data-page") || 1),
|
||||||
maxPages: Number(root.getAttribute("data-max-pages") || 1),
|
maxPages: Number(root.getAttribute("data-max-pages") || 1),
|
||||||
paging: root.getAttribute("data-paging") || "number",
|
paging: root.getAttribute("data-paging") || "number",
|
||||||
@@ -38,115 +45,251 @@
|
|||||||
autoLoads: 0,
|
autoLoads: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
function fetchArchive(page, orderby, replace) {
|
function showLoader(on) {
|
||||||
|
if (loader) {
|
||||||
|
loader.hidden = !on;
|
||||||
|
loader.style.display = on ? "" : "none";
|
||||||
|
loader.classList.toggle("is-loading", !!on);
|
||||||
|
}
|
||||||
|
if (pager) pager.classList.toggle("is-ajax-loading", !!on);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLoadMore(hasMore) {
|
||||||
|
var pag = root.querySelector(".ajax-pag");
|
||||||
|
if (loadMoreBtn) {
|
||||||
|
loadMoreBtn.style.display = hasMore ? "" : "none";
|
||||||
|
loadMoreBtn.disabled = false;
|
||||||
|
loadMoreBtn.textContent = hasMore ? "加载更多" : "没有更多了";
|
||||||
|
if (!hasMore) loadMoreBtn.classList.add("ajax-nomore");
|
||||||
|
else loadMoreBtn.classList.remove("ajax-nomore");
|
||||||
|
}
|
||||||
|
if (pag) pag.style.display = hasMore ? "" : "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncOrderbyActive() {
|
||||||
|
root.querySelectorAll("[data-aksrt-shop-orderby]").forEach(function (a) {
|
||||||
|
var key = a.getAttribute("data-aksrt-shop-orderby") || "";
|
||||||
|
var active = key === state.orderby;
|
||||||
|
a.classList.toggle("is-active", active);
|
||||||
|
a.classList.toggle("focus-color", active && key === "price");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchArchive(page, orderby, order, replace, termId) {
|
||||||
if (state.loading) return Promise.resolve();
|
if (state.loading) return Promise.resolve();
|
||||||
state.loading = true;
|
state.loading = true;
|
||||||
|
showLoader(true);
|
||||||
if (loadMoreBtn) {
|
if (loadMoreBtn) {
|
||||||
loadMoreBtn.disabled = true;
|
loadMoreBtn.disabled = true;
|
||||||
loadMoreBtn.textContent = "加载中...";
|
loadMoreBtn.textContent = "加载中…";
|
||||||
}
|
}
|
||||||
|
|
||||||
var qs = new URLSearchParams();
|
var qs = new URLSearchParams();
|
||||||
qs.set("taxonomy", state.taxonomy);
|
qs.set("taxonomy", state.taxonomy);
|
||||||
qs.set("term_id", String(state.termId));
|
qs.set("term_id", String(typeof termId === "number" ? termId : state.termId));
|
||||||
qs.set("page", String(page));
|
qs.set("page", String(page));
|
||||||
qs.set("orderby", orderby || state.orderby);
|
qs.set("orderby", orderby || state.orderby);
|
||||||
|
if ((orderby || state.orderby) === "price") {
|
||||||
|
qs.set("order", order || state.order || "ASC");
|
||||||
|
}
|
||||||
|
|
||||||
|
var container = pager || grid || root;
|
||||||
|
try {
|
||||||
|
container.dispatchEvent(
|
||||||
|
new CustomEvent("post_ajax.before", {
|
||||||
|
bubbles: true,
|
||||||
|
detail: { page: page, orderby: orderby || state.orderby, replace: !!replace },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (e0) {}
|
||||||
|
|
||||||
return fetch(restBase() + "/shop/frontend/products/archive?" + qs.toString(), {
|
return fetch(restBase() + "/shop/frontend/products/archive?" + qs.toString(), {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
headers: {
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
"X-WP-Nonce": (window.aksrtData && aksrtData.restNonce) || "",
|
"X-WP-Nonce": (window.aksrtData && aksrtData.restNonce) || "",
|
||||||
|
"X-AKSRT-Ajax": "list",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(function (r) { return r.json(); })
|
.then(function (r) {
|
||||||
|
return r.json();
|
||||||
|
})
|
||||||
.then(function (result) {
|
.then(function (result) {
|
||||||
state.loading = false;
|
state.loading = false;
|
||||||
|
showLoader(false);
|
||||||
if (!result || !result.success || !result.data) {
|
if (!result || !result.success || !result.data) {
|
||||||
toast((result && result.message) || "加载失败");
|
toast((result && result.message) || "加载失败");
|
||||||
if (loadMoreBtn) {
|
updateLoadMore(state.page < state.maxPages);
|
||||||
loadMoreBtn.disabled = false;
|
|
||||||
loadMoreBtn.textContent = "加载更多";
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var data = result.data;
|
var data = result.data;
|
||||||
state.page = Number(data.page || page);
|
state.page = Number(data.page || page);
|
||||||
state.maxPages = Number(data.max_pages || 1);
|
state.maxPages = Number(data.max_pages || 1);
|
||||||
state.orderby = data.orderby || state.orderby;
|
state.orderby = data.orderby || state.orderby;
|
||||||
|
state.order = String(data.order || state.order || "DESC").toUpperCase();
|
||||||
|
if (typeof termId === "number" && termId > 0) {
|
||||||
|
state.termId = termId;
|
||||||
|
}
|
||||||
|
if (data.term && data.term.id) {
|
||||||
|
state.termId = Number(data.term.id);
|
||||||
|
}
|
||||||
root.setAttribute("data-page", String(state.page));
|
root.setAttribute("data-page", String(state.page));
|
||||||
root.setAttribute("data-max-pages", String(state.maxPages));
|
root.setAttribute("data-max-pages", String(state.maxPages));
|
||||||
root.setAttribute("data-orderby", state.orderby);
|
root.setAttribute("data-orderby", state.orderby);
|
||||||
|
root.setAttribute("data-order", state.order);
|
||||||
|
root.setAttribute("data-term-id", String(state.termId));
|
||||||
|
|
||||||
if (countEl && typeof data.total !== "undefined") {
|
if (countEl && typeof data.total !== "undefined") {
|
||||||
countEl.textContent = "共 " + data.total + " 件商品";
|
countEl.textContent = "共 " + data.total + " 件商品";
|
||||||
}
|
}
|
||||||
|
var titleEl = root.querySelector("[data-aksrt-archive-title]");
|
||||||
|
if (titleEl && data.term && data.term.name) {
|
||||||
|
titleEl.textContent = data.term.name;
|
||||||
|
}
|
||||||
|
var descEl = root.querySelector("[data-aksrt-archive-desc]");
|
||||||
|
if (descEl && data.term) {
|
||||||
|
descEl.textContent = data.term.description || "";
|
||||||
|
descEl.style.display = data.term.description ? "" : "none";
|
||||||
|
}
|
||||||
|
|
||||||
if (grid) {
|
if (headerHost && data.header_html) {
|
||||||
if (replace) {
|
// Keep title/count; replace filter widget if present.
|
||||||
grid.innerHTML = data.html || "";
|
var existingFilter = headerHost.querySelector("[data-aksrt-shop-cat-filter], .shop-cat-filter");
|
||||||
} else if (data.html) {
|
var tmp = document.createElement("div");
|
||||||
grid.insertAdjacentHTML("beforeend", data.html);
|
tmp.innerHTML = data.header_html;
|
||||||
|
var nextFilter = tmp.querySelector("[data-aksrt-shop-cat-filter], .shop-cat-filter") || tmp.firstElementChild;
|
||||||
|
if (existingFilter && nextFilter) {
|
||||||
|
existingFilter.replaceWith(nextFilter);
|
||||||
|
} else if (!existingFilter && nextFilter) {
|
||||||
|
headerHost.appendChild(nextFilter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
root.querySelectorAll("[data-aksrt-shop-orderby]").forEach(function (a) {
|
var html = data.html || data.empty_html || "";
|
||||||
a.classList.toggle("is-active", a.getAttribute("data-aksrt-shop-orderby") === state.orderby);
|
if (grid) {
|
||||||
});
|
if (replace) {
|
||||||
|
grid.innerHTML = html;
|
||||||
if (loadMoreBtn) {
|
} else if (html) {
|
||||||
var hasMore = state.page < state.maxPages;
|
grid.insertAdjacentHTML("beforeend", html);
|
||||||
loadMoreBtn.style.display = hasMore ? "" : "none";
|
}
|
||||||
loadMoreBtn.disabled = false;
|
|
||||||
loadMoreBtn.textContent = "加载更多";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.paginate_html) {
|
||||||
|
var oldPag = root.querySelector(".ajax-pag");
|
||||||
|
var wrap = document.createElement("div");
|
||||||
|
wrap.innerHTML = data.paginate_html;
|
||||||
|
var nextPag = wrap.firstElementChild;
|
||||||
|
if (oldPag && nextPag) oldPag.replaceWith(nextPag);
|
||||||
|
else if (!oldPag && nextPag && pager) pager.appendChild(nextPag);
|
||||||
|
loadMoreBtn = root.querySelector("[data-aksrt-shop-load-more]");
|
||||||
|
}
|
||||||
|
|
||||||
|
syncOrderbyActive();
|
||||||
|
updateLoadMore(!!data.has_more || state.page < state.maxPages);
|
||||||
|
|
||||||
|
try {
|
||||||
|
container.dispatchEvent(
|
||||||
|
new CustomEvent("post_ajax.ed", {
|
||||||
|
bubbles: true,
|
||||||
|
detail: { page: state.page, replace: !!replace, data: data },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent("aksrt:posts:rendered", {
|
||||||
|
bubbles: true,
|
||||||
|
detail: { container: grid, replace: !!replace },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (e1) {}
|
||||||
})
|
})
|
||||||
.catch(function () {
|
.catch(function () {
|
||||||
state.loading = false;
|
state.loading = false;
|
||||||
if (loadMoreBtn) {
|
showLoader(false);
|
||||||
loadMoreBtn.disabled = false;
|
updateLoadMore(state.page < state.maxPages);
|
||||||
loadMoreBtn.textContent = "加载更多";
|
|
||||||
}
|
|
||||||
toast("网络错误");
|
toast("网络错误");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pushUrl(orderby, order, termUrl) {
|
||||||
|
try {
|
||||||
|
var u = termUrl ? new URL(termUrl, window.location.origin) : new URL(window.location.href);
|
||||||
|
if (orderby) u.searchParams.set("orderby", orderby);
|
||||||
|
else u.searchParams.delete("orderby");
|
||||||
|
u.searchParams.delete("shop_orderby");
|
||||||
|
if (orderby === "price" && order) u.searchParams.set("order", order);
|
||||||
|
else u.searchParams.delete("order");
|
||||||
|
u.searchParams.delete("paged");
|
||||||
|
window.history.replaceState({}, "", u.toString());
|
||||||
|
} catch (err) {}
|
||||||
|
}
|
||||||
|
|
||||||
root.addEventListener("click", function (e) {
|
root.addEventListener("click", function (e) {
|
||||||
var sort = e.target.closest("[data-aksrt-shop-orderby]");
|
// Category / sort links with ajax-next — intercept for REST (richer payload).
|
||||||
if (sort && root.contains(sort)) {
|
var termLink = e.target.closest("[data-aksrt-shop-term].ajax-next, a.ajax-next[data-aksrt-shop-term]");
|
||||||
|
if (termLink && root.contains(termLink)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
var tid = Number(termLink.getAttribute("data-aksrt-shop-term") || 0);
|
||||||
|
var href = termLink.getAttribute("href") || "";
|
||||||
|
state.autoLoads = 0;
|
||||||
|
if (tid > 0) state.termId = tid;
|
||||||
|
pushUrl(state.orderby, state.order, href);
|
||||||
|
var rt = termLink.getAttribute("route-title");
|
||||||
|
if (rt) {
|
||||||
|
try {
|
||||||
|
document.title = rt;
|
||||||
|
} catch (e2) {}
|
||||||
|
}
|
||||||
|
fetchArchive(1, state.orderby, state.order, true, tid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sort = e.target.closest("[data-aksrt-shop-orderby]");
|
||||||
|
if (sort && root.contains(sort) && sort.tagName === "A") {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
var orderby = sort.getAttribute("data-aksrt-shop-orderby") || "date";
|
var orderby = sort.getAttribute("data-aksrt-shop-orderby") || "date";
|
||||||
if (orderby === state.orderby && state.paging === "ajax") return;
|
var nextOrder = sort.getAttribute("data-aksrt-shop-order") || "";
|
||||||
|
if (orderby === "price") {
|
||||||
|
if (state.orderby === "price" && nextOrder) {
|
||||||
|
state.order = nextOrder.toUpperCase();
|
||||||
|
} else if (state.orderby !== "price") {
|
||||||
|
state.order = "ASC";
|
||||||
|
} else {
|
||||||
|
state.order = state.order === "ASC" ? "DESC" : "ASC";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (orderby === state.orderby && orderby !== "price" && state.paging === "ajax") return;
|
||||||
state.orderby = orderby;
|
state.orderby = orderby;
|
||||||
state.autoLoads = 0;
|
state.autoLoads = 0;
|
||||||
try {
|
pushUrl(orderby, state.order);
|
||||||
var u = new URL(window.location.href);
|
fetchArchive(1, orderby, state.order, true);
|
||||||
u.searchParams.set("shop_orderby", orderby);
|
|
||||||
u.searchParams.delete("paged");
|
|
||||||
window.history.replaceState({}, "", u.toString());
|
|
||||||
} catch (err) {}
|
|
||||||
fetchArchive(1, orderby, true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var more = e.target.closest("[data-aksrt-shop-load-more]");
|
var more = e.target.closest("[data-aksrt-shop-load-more]");
|
||||||
if (more && root.contains(more)) {
|
if (more && root.contains(more)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
if (state.page >= state.maxPages) return;
|
if (state.page >= state.maxPages) return;
|
||||||
fetchArchive(state.page + 1, state.orderby, false);
|
fetchArchive(state.page + 1, state.orderby, state.order, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (state.paging === "ajax" && state.ias && "IntersectionObserver" in window && loadMoreBtn) {
|
if (state.paging === "ajax" && state.ias && "IntersectionObserver" in window && loadMoreBtn) {
|
||||||
var io = new IntersectionObserver(function (entries) {
|
var io = new IntersectionObserver(
|
||||||
entries.forEach(function (entry) {
|
function (entries) {
|
||||||
if (!entry.isIntersecting) return;
|
entries.forEach(function (entry) {
|
||||||
if (state.loading || state.page >= state.maxPages) return;
|
if (!entry.isIntersecting) return;
|
||||||
if (state.iasMax > 0 && state.autoLoads >= state.iasMax) return;
|
if (state.loading || state.page >= state.maxPages) return;
|
||||||
state.autoLoads += 1;
|
if (state.iasMax > 0 && state.autoLoads >= state.iasMax) return;
|
||||||
fetchArchive(state.page + 1, state.orderby, false);
|
state.autoLoads += 1;
|
||||||
});
|
fetchArchive(state.page + 1, state.orderby, state.order, false);
|
||||||
}, { rootMargin: "240px" });
|
});
|
||||||
|
},
|
||||||
|
{ rootMargin: "240px" }
|
||||||
|
);
|
||||||
io.observe(loadMoreBtn);
|
io.observe(loadMoreBtn);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
@@ -363,75 +363,92 @@ trait ShopControllerFrontendFlowOperations {
|
|||||||
$term_id = (int) ($request->get_param('term_id') ?? 0);
|
$term_id = (int) ($request->get_param('term_id') ?? 0);
|
||||||
$page = max(1, (int) ($request->get_param('page') ?? 1));
|
$page = max(1, (int) ($request->get_param('page') ?? 1));
|
||||||
$orderby = sanitize_key((string) ($request->get_param('orderby') ?? ''));
|
$orderby = sanitize_key((string) ($request->get_param('orderby') ?? ''));
|
||||||
|
$order = sanitize_key((string) ($request->get_param('order') ?? ''));
|
||||||
|
|
||||||
$view = \AKSRT\Shop\Shop::get_instance()->get_product_archive_view([
|
$view = \AKSRT\Shop\Shop::get_instance()->get_product_archive_view([
|
||||||
'taxonomy' => $taxonomy,
|
'taxonomy' => $taxonomy,
|
||||||
'term_id' => $term_id,
|
'term_id' => $term_id,
|
||||||
'paged' => $page,
|
'paged' => $page,
|
||||||
'orderby' => $orderby,
|
'orderby' => $orderby,
|
||||||
|
'order' => $order,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$sales_cfg = is_array($view['sales'] ?? null) ? $view['sales'] : [];
|
||||||
$html = '';
|
$html = '';
|
||||||
if (!empty($view['products']) && is_array($view['products'])) {
|
if (!empty($view['products']) && is_array($view['products'])) {
|
||||||
ob_start();
|
ob_start();
|
||||||
foreach ($view['products'] as $product) {
|
foreach ($view['products'] as $product) {
|
||||||
$this->render_product_card_html($product, $view);
|
if (function_exists('get_template_part')) {
|
||||||
|
get_template_part('templates/parts/shop/product', 'card', [
|
||||||
|
'product' => $product,
|
||||||
|
'sales_cfg' => $sales_cfg,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$html = (string) ob_get_clean();
|
$html = (string) ob_get_clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$empty_html = '';
|
||||||
|
if ($html === '' && function_exists('aksrt_get_ajax_null')) {
|
||||||
|
$empty_html = aksrt_get_ajax_null(__('内容空空如也', 'aksrt'));
|
||||||
|
} elseif ($html === '') {
|
||||||
|
$empty_html = '<div class="aksrt-product-archive__empty ajax-item"><p>' . esc_html__('内容空空如也', 'aksrt') . '</p></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header HTML for cat filter replace (when filter present).
|
||||||
|
$header_html = '';
|
||||||
|
if (!empty($view['filter']) && is_array($view['filter'])) {
|
||||||
|
ob_start();
|
||||||
|
$this->render_product_cat_filter_html($view);
|
||||||
|
$header_html = (string) ob_get_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
$paginate_html = '';
|
||||||
|
$page_n = (int) ($view['page'] ?? 1);
|
||||||
|
$max_pages = (int) ($view['max_pages'] ?? 1);
|
||||||
|
$has_more = $page_n < $max_pages;
|
||||||
|
if ($has_more && (string) ($view['paging'] ?? '') === 'ajax') {
|
||||||
|
$next_url = add_query_arg([
|
||||||
|
'taxonomy' => $taxonomy,
|
||||||
|
'term_id' => $term_id,
|
||||||
|
'page' => $page_n + 1,
|
||||||
|
'orderby' => (string) ($view['orderby'] ?? 'date'),
|
||||||
|
'order' => (string) ($view['order'] ?? ''),
|
||||||
|
], rest_url('aksrt/v1/shop/frontend/products/archive'));
|
||||||
|
if (function_exists('aksrt_get_ajax_next_paginate')) {
|
||||||
|
$paginate_html = aksrt_get_ajax_next_paginate(
|
||||||
|
(int) ($view['total'] ?? 0),
|
||||||
|
$page_n,
|
||||||
|
max(1, (int) ($view['per_page'] ?? 12)),
|
||||||
|
$next_url
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $this->success([
|
return $this->success([
|
||||||
'data' => array_merge($view, [
|
'data' => array_merge($view, [
|
||||||
'html' => $html,
|
'html' => $html !== '' ? $html : $empty_html,
|
||||||
'has_more' => (int) ($view['page'] ?? 1) < (int) ($view['max_pages'] ?? 1),
|
'empty_html' => $empty_html,
|
||||||
|
'header_html' => $header_html,
|
||||||
|
'paginate_html' => $paginate_html,
|
||||||
|
'has_more' => $has_more,
|
||||||
|
'title' => !empty($view['term']['name'])
|
||||||
|
? (string) $view['term']['name'] . ' - ' . wp_strip_all_tags(get_bloginfo('name'))
|
||||||
|
: '',
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function render_product_card_html(array $product, array $view = []): void {
|
/**
|
||||||
$sales_cfg = is_array($view['sales'] ?? null) ? $view['sales'] : [];
|
* Render cat filter bar HTML for AJAX header replace.
|
||||||
$mode = (string) ($sales_cfg['show'] ?? 'show');
|
*/
|
||||||
$min_sales = max(0, (int) ($sales_cfg['show_min'] ?? 0));
|
private function render_product_cat_filter_html(array $view): void {
|
||||||
$sales = (int) ($product['sales'] ?? 0);
|
$filter = is_array($view['filter'] ?? null) ? $view['filter'] : [];
|
||||||
$can_show_sales = false;
|
$orderby = (string) ($view['orderby'] ?? ($filter['orderby'] ?? 'date'));
|
||||||
if ($mode === 'show') {
|
$order = strtoupper((string) ($view['order'] ?? ($filter['order'] ?? 'DESC')));
|
||||||
$can_show_sales = $sales > 0;
|
$term = is_array($view['term'] ?? null) ? $view['term'] : [];
|
||||||
} elseif ($mode === 'threshold') {
|
$current_id = (int) ($filter['current_id'] ?? ($term['id'] ?? 0));
|
||||||
$can_show_sales = $sales >= $min_sales;
|
include get_template_directory() . '/templates/parts/shop/product-cat-filter.php';
|
||||||
}
|
|
||||||
|
|
||||||
$permalink = (string) ($product['permalink'] ?? '#');
|
|
||||||
$title = (string) ($product['title'] ?? '');
|
|
||||||
$image = (string) ($product['image'] ?? '');
|
|
||||||
$price = (float) ($product['price'] ?? 0);
|
|
||||||
$excerpt = (string) ($product['excerpt'] ?? '');
|
|
||||||
?>
|
|
||||||
<article class="aksrt-product-card">
|
|
||||||
<a href="<?php echo esc_url($permalink); ?>" class="aksrt-product-card__link">
|
|
||||||
<?php if ($image !== '') : ?>
|
|
||||||
<div class="aksrt-product-card__image">
|
|
||||||
<img src="<?php echo esc_url($image); ?>" alt="<?php echo esc_attr($title); ?>" loading="lazy">
|
|
||||||
</div>
|
|
||||||
<?php else : ?>
|
|
||||||
<div class="aksrt-product-card__image aksrt-product-card__image--placeholder">
|
|
||||||
<i class="fas fa-image"></i>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="aksrt-product-card__body">
|
|
||||||
<h3 class="aksrt-product-card__title"><?php echo esc_html($title); ?></h3>
|
|
||||||
<?php if ($excerpt !== '') : ?>
|
|
||||||
<p class="aksrt-product-card__excerpt"><?php echo esc_html(wp_trim_words($excerpt, 15)); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="aksrt-product-card__footer">
|
|
||||||
<span class="aksrt-product-card__price">¥<?php echo esc_html(number_format($price, 2)); ?></span>
|
|
||||||
<?php if ($can_show_sales) : ?>
|
|
||||||
<span class="aksrt-product-card__sales"><?php printf(esc_html__('已售 %d', 'aksrt'), $sales); ?></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</article>
|
|
||||||
<?php
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_frontend_revenue(\WP_REST_Request $request): \WP_REST_Response {
|
public function get_frontend_revenue(\WP_REST_Request $request): \WP_REST_Response {
|
||||||
|
|||||||
+163
-10
@@ -57,10 +57,39 @@ trait Part1 {
|
|||||||
$shop_settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_shop_settings() : [];
|
$shop_settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_shop_settings() : [];
|
||||||
$list = is_array($shop_settings['list'] ?? null) ? $shop_settings['list'] : [];
|
$list = is_array($shop_settings['list'] ?? null) ? $shop_settings['list'] : [];
|
||||||
$per_page = max(4, min(100, (int) ($args['per_page'] ?? ($list['count'] ?? 12))));
|
$per_page = max(4, min(100, (int) ($args['per_page'] ?? ($list['count'] ?? 12))));
|
||||||
$orderby = sanitize_key((string) ($args['orderby'] ?? ($list['orderby'] ?? 'date')));
|
|
||||||
if (!in_array($orderby, ['date', 'sales', 'price_asc', 'price_desc', 'comments', 'modified'], true)) {
|
// Normalize orderby aliases (zibll + legacy AKSRT keys).
|
||||||
$orderby = 'date';
|
$orderby_raw = sanitize_key((string) ($args['orderby'] ?? ($list['orderby'] ?? 'date')));
|
||||||
|
$order = strtoupper(sanitize_key((string) ($args['order'] ?? '')));
|
||||||
|
if (!in_array($order, ['ASC', 'DESC'], true)) {
|
||||||
|
$order = '';
|
||||||
}
|
}
|
||||||
|
// Legacy split price keys → price + order.
|
||||||
|
if ($orderby_raw === 'price_asc') {
|
||||||
|
$orderby_raw = 'price';
|
||||||
|
$order = 'ASC';
|
||||||
|
} elseif ($orderby_raw === 'price_desc') {
|
||||||
|
$orderby_raw = 'price';
|
||||||
|
$order = 'DESC';
|
||||||
|
} elseif ($orderby_raw === 'sales_volume') {
|
||||||
|
$orderby_raw = 'sales';
|
||||||
|
} elseif ($orderby_raw === 'zibpay_price') {
|
||||||
|
$orderby_raw = 'price';
|
||||||
|
} elseif ($orderby_raw === 'comments') {
|
||||||
|
$orderby_raw = 'score';
|
||||||
|
}
|
||||||
|
$allowed_orderby = ['date', 'views', 'favorite_count', 'score', 'sales', 'price', 'modified'];
|
||||||
|
if (!in_array($orderby_raw, $allowed_orderby, true)) {
|
||||||
|
$orderby_raw = 'date';
|
||||||
|
}
|
||||||
|
if ($orderby_raw === 'price' && $order === '') {
|
||||||
|
$order = 'ASC';
|
||||||
|
}
|
||||||
|
if ($order === '' && $orderby_raw !== 'price') {
|
||||||
|
$order = 'DESC';
|
||||||
|
}
|
||||||
|
$orderby = $orderby_raw;
|
||||||
|
|
||||||
$paging = sanitize_key((string) ($args['paging'] ?? ($list['paging'] ?? 'number')));
|
$paging = sanitize_key((string) ($args['paging'] ?? ($list['paging'] ?? 'number')));
|
||||||
if (!in_array($paging, ['number', 'ajax'], true)) {
|
if (!in_array($paging, ['number', 'ajax'], true)) {
|
||||||
$paging = 'number';
|
$paging = 'number';
|
||||||
@@ -76,12 +105,14 @@ trait Part1 {
|
|||||||
'max_pages' => 0,
|
'max_pages' => 0,
|
||||||
'page' => $paged,
|
'page' => $paged,
|
||||||
'orderby' => $orderby,
|
'orderby' => $orderby,
|
||||||
|
'order' => $order,
|
||||||
'paging' => $paging,
|
'paging' => $paging,
|
||||||
'ias_s' => $ias_s,
|
'ias_s' => $ias_s,
|
||||||
'ias_max' => $ias_max,
|
'ias_max' => $ias_max,
|
||||||
'per_page' => $per_page,
|
'per_page' => $per_page,
|
||||||
'style' => $style,
|
'style' => $style,
|
||||||
'sales' => is_array($shop_settings['sales'] ?? null) ? $shop_settings['sales'] : [],
|
'sales' => is_array($shop_settings['sales'] ?? null) ? $shop_settings['sales'] : [],
|
||||||
|
'filter' => null,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!in_array($taxonomy, ['aksrt_product_cat', 'aksrt_product_tag'], true) && empty($args['allow_all'])) {
|
if (!in_array($taxonomy, ['aksrt_product_cat', 'aksrt_product_tag'], true) && empty($args['allow_all'])) {
|
||||||
@@ -93,7 +124,7 @@ trait Part1 {
|
|||||||
'posts_per_page' => $per_page,
|
'posts_per_page' => $per_page,
|
||||||
'paged' => $paged,
|
'paged' => $paged,
|
||||||
'post_status' => 'publish',
|
'post_status' => 'publish',
|
||||||
'order' => 'DESC',
|
'order' => $order ?: 'DESC',
|
||||||
'orderby' => 'date',
|
'orderby' => 'date',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -114,16 +145,21 @@ trait Part1 {
|
|||||||
$query_args['meta_key'] = '_aksrt_sales';
|
$query_args['meta_key'] = '_aksrt_sales';
|
||||||
$query_args['orderby'] = 'meta_value_num';
|
$query_args['orderby'] = 'meta_value_num';
|
||||||
$query_args['order'] = 'DESC';
|
$query_args['order'] = 'DESC';
|
||||||
} elseif ($orderby === 'price_asc') {
|
} elseif ($orderby === 'price') {
|
||||||
$query_args['meta_key'] = '_aksrt_price';
|
$query_args['meta_key'] = '_aksrt_price';
|
||||||
$query_args['orderby'] = 'meta_value_num';
|
$query_args['orderby'] = 'meta_value_num';
|
||||||
$query_args['order'] = 'ASC';
|
$query_args['order'] = $order === 'ASC' ? 'ASC' : 'DESC';
|
||||||
} elseif ($orderby === 'price_desc') {
|
} elseif ($orderby === 'favorite_count') {
|
||||||
$query_args['meta_key'] = '_aksrt_price';
|
$query_args['meta_key'] = '_aksrt_favorite_count';
|
||||||
$query_args['orderby'] = 'meta_value_num';
|
$query_args['orderby'] = 'meta_value_num';
|
||||||
$query_args['order'] = 'DESC';
|
$query_args['order'] = 'DESC';
|
||||||
} elseif ($orderby === 'comments') {
|
} elseif ($orderby === 'views') {
|
||||||
$query_args['orderby'] = 'comment_count';
|
$query_args['meta_key'] = '_aksrt_views';
|
||||||
|
$query_args['orderby'] = 'meta_value_num';
|
||||||
|
$query_args['order'] = 'DESC';
|
||||||
|
} elseif ($orderby === 'score') {
|
||||||
|
$query_args['meta_key'] = '_aksrt_score_average';
|
||||||
|
$query_args['orderby'] = 'meta_value_num';
|
||||||
$query_args['order'] = 'DESC';
|
$query_args['order'] = 'DESC';
|
||||||
} elseif ($orderby === 'modified') {
|
} elseif ($orderby === 'modified') {
|
||||||
$query_args['orderby'] = 'modified';
|
$query_args['orderby'] = 'modified';
|
||||||
@@ -138,6 +174,11 @@ trait Part1 {
|
|||||||
}
|
}
|
||||||
wp_reset_postdata();
|
wp_reset_postdata();
|
||||||
|
|
||||||
|
$filter = null;
|
||||||
|
if ($taxonomy === 'aksrt_product_cat' && $term) {
|
||||||
|
$filter = $this->build_product_cat_filter((int) $term->term_id, $orderby, $order);
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'products' => $products,
|
'products' => $products,
|
||||||
'term' => $term ? [
|
'term' => $term ? [
|
||||||
@@ -146,17 +187,129 @@ trait Part1 {
|
|||||||
'description' => (string) $term->description,
|
'description' => (string) $term->description,
|
||||||
'count' => (int) $term->count,
|
'count' => (int) $term->count,
|
||||||
'taxonomy' => $taxonomy,
|
'taxonomy' => $taxonomy,
|
||||||
|
'parent' => (int) $term->parent,
|
||||||
|
'url' => get_term_link($term),
|
||||||
] : null,
|
] : null,
|
||||||
'total' => (int) $query->found_posts,
|
'total' => (int) $query->found_posts,
|
||||||
'max_pages' => (int) $query->max_num_pages,
|
'max_pages' => (int) $query->max_num_pages,
|
||||||
'page' => $paged,
|
'page' => $paged,
|
||||||
'orderby' => $orderby,
|
'orderby' => $orderby,
|
||||||
|
'order' => $order,
|
||||||
'paging' => $paging,
|
'paging' => $paging,
|
||||||
'ias_s' => $ias_s,
|
'ias_s' => $ias_s,
|
||||||
'ias_max' => $ias_max,
|
'ias_max' => $ias_max,
|
||||||
'per_page' => $per_page,
|
'per_page' => $per_page,
|
||||||
'style' => $style,
|
'style' => $style,
|
||||||
'sales' => is_array($shop_settings['sales'] ?? null) ? $shop_settings['sales'] : [],
|
'sales' => is_array($shop_settings['sales'] ?? null) ? $shop_settings['sales'] : [],
|
||||||
|
'filter' => $filter,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hierarchical cat filter data (zibll zib_shop_get_cat_filter).
|
||||||
|
*
|
||||||
|
* @return array{siblings:array<int,array>,children:array<int,array>,parent_id:int,mode:string}
|
||||||
|
*/
|
||||||
|
public function build_product_cat_filter(int $cat_id, string $orderby = 'date', string $order = 'DESC'): array {
|
||||||
|
$taxonomy = 'aksrt_product_cat';
|
||||||
|
$cat = get_term($cat_id, $taxonomy);
|
||||||
|
if (!$cat || is_wp_error($cat)) {
|
||||||
|
return ['siblings' => [], 'children' => [], 'parent_id' => 0, 'mode' => 'flat', 'orderby' => $orderby, 'order' => $order];
|
||||||
|
}
|
||||||
|
|
||||||
|
$map_term = static function ($t) use ($orderby, $order): array {
|
||||||
|
$url = get_term_link($t);
|
||||||
|
if (!is_wp_error($url) && $orderby) {
|
||||||
|
$url = add_query_arg(array_filter([
|
||||||
|
'orderby' => $orderby,
|
||||||
|
'order' => $orderby === 'price' ? $order : null,
|
||||||
|
]), $url);
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'id' => (int) $t->term_id,
|
||||||
|
'name' => (string) $t->name,
|
||||||
|
'url' => is_wp_error($url) ? '' : (string) $url,
|
||||||
|
'count' => (int) $t->count,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
$parent_id = (int) $cat->parent;
|
||||||
|
$children = get_terms([
|
||||||
|
'taxonomy' => $taxonomy,
|
||||||
|
'parent' => $cat_id,
|
||||||
|
'hide_empty' => false,
|
||||||
|
]);
|
||||||
|
if (is_wp_error($children)) {
|
||||||
|
$children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($parent_id > 0) {
|
||||||
|
$siblings = get_terms([
|
||||||
|
'taxonomy' => $taxonomy,
|
||||||
|
'parent' => $parent_id,
|
||||||
|
'hide_empty' => false,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$siblings = get_terms([
|
||||||
|
'taxonomy' => $taxonomy,
|
||||||
|
'parent' => 0,
|
||||||
|
'hide_empty' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (is_wp_error($siblings)) {
|
||||||
|
$siblings = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$mode = 'siblings';
|
||||||
|
$parent_terms = [];
|
||||||
|
if (empty($children) && $parent_id > 0) {
|
||||||
|
$parent_term = get_term($parent_id, $taxonomy);
|
||||||
|
if ($parent_term && !is_wp_error($parent_term) && (int) $parent_term->parent > 0) {
|
||||||
|
$parent_terms = get_terms([
|
||||||
|
'taxonomy' => $taxonomy,
|
||||||
|
'parent' => (int) $parent_term->parent,
|
||||||
|
'hide_empty' => false,
|
||||||
|
]);
|
||||||
|
if (is_wp_error($parent_terms)) {
|
||||||
|
$parent_terms = [];
|
||||||
|
}
|
||||||
|
$mode = 'parent_siblings';
|
||||||
|
} elseif ($parent_id > 0) {
|
||||||
|
$parent_terms = get_terms([
|
||||||
|
'taxonomy' => $taxonomy,
|
||||||
|
'parent' => 0,
|
||||||
|
'hide_empty' => false,
|
||||||
|
]);
|
||||||
|
if (is_wp_error($parent_terms)) {
|
||||||
|
$parent_terms = [];
|
||||||
|
}
|
||||||
|
$mode = 'parent_siblings';
|
||||||
|
}
|
||||||
|
} elseif (!empty($children)) {
|
||||||
|
$mode = 'with_children';
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent_url = '';
|
||||||
|
if ($parent_id > 0) {
|
||||||
|
$plink = get_term_link($parent_id, $taxonomy);
|
||||||
|
if (!is_wp_error($plink)) {
|
||||||
|
$parent_url = add_query_arg(array_filter([
|
||||||
|
'orderby' => $orderby,
|
||||||
|
'order' => $orderby === 'price' ? $order : null,
|
||||||
|
]), $plink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'mode' => $mode,
|
||||||
|
'current_id' => $cat_id,
|
||||||
|
'parent_id' => $parent_id,
|
||||||
|
'parent_url' => $parent_url,
|
||||||
|
'siblings' => array_map($map_term, empty($parent_terms) ? $siblings : $parent_terms),
|
||||||
|
'children' => array_map($map_term, $mode === 'with_children' ? $children : ($mode === 'parent_siblings' ? $siblings : [])),
|
||||||
|
'child_tabs' => array_map($map_term, $children),
|
||||||
|
'orderby' => $orderby,
|
||||||
|
'order' => $order,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ class ProductReview {
|
|||||||
update_comment_meta($comment_id, '_aksrt_review_images', $images);
|
update_comment_meta($comment_id, '_aksrt_review_images', $images);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->refresh_product_scores($product_id);
|
$scores = $this->refresh_product_scores($product_id);
|
||||||
|
update_post_meta($product_id, '_aksrt_score_average', (float) ($scores['average'] ?? $average));
|
||||||
|
|
||||||
if (class_exists('\AKSRT\Payment\OrderRepository')) {
|
if (class_exists('\AKSRT\Payment\OrderRepository')) {
|
||||||
$order = \AKSRT\Payment\OrderRepository::get_instance()->get($order_number);
|
$order = \AKSRT\Payment\OrderRepository::get_instance()->get($order_number);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ $image = (string) ($product['image'] ?? '');
|
|||||||
$excerpt = (string) ($product['excerpt'] ?? '');
|
$excerpt = (string) ($product['excerpt'] ?? '');
|
||||||
$price = (float) ($product['price'] ?? 0);
|
$price = (float) ($product['price'] ?? 0);
|
||||||
?>
|
?>
|
||||||
<article class="aksrt-product-card">
|
<article class="aksrt-product-card product-item posts-item card ajax-item">
|
||||||
<a href="<?php echo esc_url($permalink !== '' ? $permalink : '#'); ?>" class="aksrt-product-card__link">
|
<a href="<?php echo esc_url($permalink !== '' ? $permalink : '#'); ?>" class="aksrt-product-card__link">
|
||||||
<?php if ($image !== '') : ?>
|
<?php if ($image !== '') : ?>
|
||||||
<div class="aksrt-product-card__image">
|
<div class="aksrt-product-card__image">
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Product category hierarchical filter bar (zibll shop-cat-filter parity).
|
||||||
|
*
|
||||||
|
* Expects in scope:
|
||||||
|
* - $filter array from Shop::build_product_cat_filter()
|
||||||
|
* - $orderby string
|
||||||
|
* - $order string ASC|DESC
|
||||||
|
* - $term array|null
|
||||||
|
*
|
||||||
|
* @package AKSRT
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
$filter = is_array($filter ?? null) ? $filter : [];
|
||||||
|
$orderby = sanitize_key((string) ($orderby ?? ($filter['orderby'] ?? 'date')));
|
||||||
|
$order = strtoupper(sanitize_key((string) ($order ?? ($filter['order'] ?? 'DESC'))));
|
||||||
|
if (!in_array($order, ['ASC', 'DESC'], true)) {
|
||||||
|
$order = 'DESC';
|
||||||
|
}
|
||||||
|
$current_id = (int) ($filter['current_id'] ?? 0);
|
||||||
|
$mode = (string) ($filter['mode'] ?? 'siblings');
|
||||||
|
$siblings = is_array($filter['siblings'] ?? null) ? $filter['siblings'] : [];
|
||||||
|
$children = is_array($filter['children'] ?? null) ? $filter['children'] : [];
|
||||||
|
$child_tabs = is_array($filter['child_tabs'] ?? null) ? $filter['child_tabs'] : [];
|
||||||
|
$parent_url = (string) ($filter['parent_url'] ?? '');
|
||||||
|
$parent_id = (int) ($filter['parent_id'] ?? 0);
|
||||||
|
$term_name = is_array($term ?? null) ? (string) ($term['name'] ?? '') : '';
|
||||||
|
|
||||||
|
$order_labels = [
|
||||||
|
'date' => __('最新', 'aksrt'),
|
||||||
|
'views' => __('最热', 'aksrt'),
|
||||||
|
'favorite_count' => __('收藏', 'aksrt'),
|
||||||
|
'score' => __('评分', 'aksrt'),
|
||||||
|
'sales' => __('销量', 'aksrt'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$base_term_url = !empty($term['url']) ? (string) $term['url'] : '';
|
||||||
|
if ($base_term_url === '' && $current_id > 0) {
|
||||||
|
$link = get_term_link($current_id, 'aksrt_product_cat');
|
||||||
|
$base_term_url = is_wp_error($link) ? '' : (string) $link;
|
||||||
|
}
|
||||||
|
|
||||||
|
$blog = wp_strip_all_tags(get_bloginfo('name'));
|
||||||
|
?>
|
||||||
|
<div class="shop-cat-filter aksrt-shop-cat-filter zib-widget relative" data-aksrt-shop-cat-filter win-ajax-replace="shop-cat-filter">
|
||||||
|
<?php if (!empty($siblings)) : ?>
|
||||||
|
<div class="shop-cat-filter-tab list-inline scroll-x mini-scrollbar tab-nav-theme" data-aksrt-cat-tabs>
|
||||||
|
<?php foreach ($siblings as $sib) :
|
||||||
|
$sid = (int) ($sib['id'] ?? 0);
|
||||||
|
$is_active = ($mode === 'with_children' && $sid === $current_id)
|
||||||
|
|| ($mode === 'parent_siblings' && $sid === $parent_id)
|
||||||
|
|| ($mode === 'siblings' && $sid === $current_id);
|
||||||
|
?>
|
||||||
|
<?php if ($is_active) : ?>
|
||||||
|
<li class="active"><span class="focus-color"><?php echo esc_html((string) ($sib['name'] ?? '')); ?></span></li>
|
||||||
|
<?php else : ?>
|
||||||
|
<li>
|
||||||
|
<a class="ajax-next"
|
||||||
|
ajax-replace="true"
|
||||||
|
route="1"
|
||||||
|
route-title="<?php echo esc_attr((string) ($sib['name'] ?? '') . ' - ' . __('商城', 'aksrt') . ($blog ? ' · ' . $blog : '')); ?>"
|
||||||
|
href="<?php echo esc_url((string) ($sib['url'] ?? '#')); ?>"
|
||||||
|
data-aksrt-shop-term="<?php echo esc_attr((string) $sid); ?>">
|
||||||
|
<?php echo esc_html((string) ($sib['name'] ?? '')); ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($mode === 'with_children' && !empty($child_tabs)) : ?>
|
||||||
|
<div class="shop-cat-filter-child" data-aksrt-cat-children>
|
||||||
|
<span class="focus-color"><?php esc_html_e('全部', 'aksrt'); ?></span>
|
||||||
|
<?php foreach ($child_tabs as $child) : ?>
|
||||||
|
<a class="ajax-next"
|
||||||
|
ajax-replace="true"
|
||||||
|
route="1"
|
||||||
|
route-title="<?php echo esc_attr((string) ($child['name'] ?? '') . ' - ' . __('商城', 'aksrt')); ?>"
|
||||||
|
href="<?php echo esc_url((string) ($child['url'] ?? '#')); ?>"
|
||||||
|
data-aksrt-shop-term="<?php echo esc_attr((string) ((int) ($child['id'] ?? 0))); ?>">
|
||||||
|
<?php echo esc_html((string) ($child['name'] ?? '')); ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php elseif ($mode === 'parent_siblings' && !empty($children)) : ?>
|
||||||
|
<div class="shop-cat-filter-child" data-aksrt-cat-children>
|
||||||
|
<?php if ($parent_url !== '') : ?>
|
||||||
|
<a class="ajax-next" ajax-replace="true" route="1" href="<?php echo esc_url($parent_url); ?>" data-aksrt-shop-term="<?php echo esc_attr((string) $parent_id); ?>">
|
||||||
|
<?php esc_html_e('全部', 'aksrt'); ?>
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php foreach ($children as $child) :
|
||||||
|
$cid = (int) ($child['id'] ?? 0);
|
||||||
|
?>
|
||||||
|
<?php if ($cid === $current_id) : ?>
|
||||||
|
<span class="focus-color"><?php echo esc_html((string) ($child['name'] ?? '')); ?></span>
|
||||||
|
<?php else : ?>
|
||||||
|
<a class="ajax-next"
|
||||||
|
ajax-replace="true"
|
||||||
|
route="1"
|
||||||
|
route-title="<?php echo esc_attr((string) ($child['name'] ?? '') . ' - ' . __('商城', 'aksrt')); ?>"
|
||||||
|
href="<?php echo esc_url((string) ($child['url'] ?? '#')); ?>"
|
||||||
|
data-aksrt-shop-term="<?php echo esc_attr((string) $cid); ?>">
|
||||||
|
<?php echo esc_html((string) ($child['name'] ?? '')); ?>
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="shop-cat-filter-orderby shop-cat-filter-child" win-ajax-replace="orderby" data-aksrt-shop-orderby-bar>
|
||||||
|
<span class="opacity5"><?php esc_html_e('排序', 'aksrt'); ?></span>
|
||||||
|
<?php foreach ($order_labels as $key => $label) :
|
||||||
|
if ($orderby === $key) : ?>
|
||||||
|
<span class="focus-color"><?php echo esc_html($label); ?></span>
|
||||||
|
<?php else :
|
||||||
|
$href = $base_term_url !== '' ? add_query_arg(['orderby' => $key], $base_term_url) : add_query_arg(['orderby' => $key]);
|
||||||
|
?>
|
||||||
|
<a rel="nofollow" ajax-replace="true" class="ajax-next" href="<?php echo esc_url($href); ?>" data-aksrt-shop-orderby="<?php echo esc_attr($key); ?>">
|
||||||
|
<?php echo esc_html($label); ?>
|
||||||
|
</a>
|
||||||
|
<?php endif;
|
||||||
|
endforeach;
|
||||||
|
|
||||||
|
// Price toggle (single 售价 control).
|
||||||
|
if ($orderby === 'price') {
|
||||||
|
$next_order = $order === 'DESC' ? 'ASC' : 'DESC';
|
||||||
|
$icon = $next_order === 'DESC' ? 'up' : 'down';
|
||||||
|
$href = $base_term_url !== ''
|
||||||
|
? add_query_arg(['orderby' => 'price', 'order' => $next_order], $base_term_url)
|
||||||
|
: add_query_arg(['orderby' => 'price', 'order' => $next_order]);
|
||||||
|
?>
|
||||||
|
<a rel="nofollow" ajax-replace="true" class="ajax-next focus-color" href="<?php echo esc_url($href); ?>" data-aksrt-shop-orderby="price" data-aksrt-shop-order="<?php echo esc_attr($next_order); ?>">
|
||||||
|
<?php esc_html_e('售价', 'aksrt'); ?><i class="opacity5 ml3 fa fa-long-arrow-<?php echo esc_attr($icon); ?>"></i>
|
||||||
|
</a>
|
||||||
|
<?php } else {
|
||||||
|
$href = $base_term_url !== ''
|
||||||
|
? add_query_arg(['orderby' => 'price'], $base_term_url)
|
||||||
|
: add_query_arg(['orderby' => 'price']);
|
||||||
|
?>
|
||||||
|
<a rel="nofollow" ajax-replace="true" class="ajax-next" href="<?php echo esc_url($href); ?>" data-aksrt-shop-orderby="price">
|
||||||
|
<?php esc_html_e('售价', 'aksrt'); ?>
|
||||||
|
</a>
|
||||||
|
<?php } ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
+108
-84
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* 商品分类归档模板
|
* 商品分类归档模板 — zibll shop cat filter + ajax list 1:1 UX
|
||||||
*
|
*
|
||||||
* @package AKSRT
|
* @package AKSRT
|
||||||
*/
|
*/
|
||||||
@@ -11,14 +11,25 @@ get_header();
|
|||||||
|
|
||||||
$term = get_queried_object();
|
$term = get_queried_object();
|
||||||
$paged = max(1, (int) get_query_var('paged'));
|
$paged = max(1, (int) get_query_var('paged'));
|
||||||
$orderby = isset($_GET['shop_orderby']) ? sanitize_key(wp_unslash((string) $_GET['shop_orderby'])) : '';
|
$orderby = '';
|
||||||
$shop = class_exists('\AKSRT\Shop\Shop') ? \AKSRT\Shop\Shop::get_instance() : null;
|
$order = '';
|
||||||
$view = $shop ? $shop->get_product_archive_view([
|
if (isset($_GET['orderby'])) {
|
||||||
'taxonomy' => 'aksrt_product_cat',
|
$orderby = sanitize_key(wp_unslash((string) $_GET['orderby']));
|
||||||
'term_id' => $term ? (int) $term->term_id : 0,
|
} elseif (isset($_GET['shop_orderby'])) {
|
||||||
'paged' => $paged,
|
$orderby = sanitize_key(wp_unslash((string) $_GET['shop_orderby']));
|
||||||
'orderby' => $orderby,
|
}
|
||||||
]) : ['products' => [], 'term' => null, 'total' => 0, 'max_pages' => 0, 'orderby' => 'date', 'paging' => 'number'];
|
if (isset($_GET['order'])) {
|
||||||
|
$order = sanitize_key(wp_unslash((string) $_GET['order']));
|
||||||
|
}
|
||||||
|
|
||||||
|
$shop = class_exists('\AKSRT\Shop\Shop') ? \AKSRT\Shop\Shop::get_instance() : null;
|
||||||
|
$view = $shop ? $shop->get_product_archive_view([
|
||||||
|
'taxonomy' => 'aksrt_product_cat',
|
||||||
|
'term_id' => $term ? (int) $term->term_id : 0,
|
||||||
|
'paged' => $paged,
|
||||||
|
'orderby' => $orderby,
|
||||||
|
'order' => $order,
|
||||||
|
]) : ['products' => [], 'term' => null, 'total' => 0, 'max_pages' => 0, 'orderby' => 'date', 'order' => 'DESC', 'paging' => 'number'];
|
||||||
|
|
||||||
$products = $view['products'] ?? [];
|
$products = $view['products'] ?? [];
|
||||||
$total = (int) ($view['total'] ?? 0);
|
$total = (int) ($view['total'] ?? 0);
|
||||||
@@ -26,95 +37,108 @@ $max_pages = (int) ($view['max_pages'] ?? 0);
|
|||||||
$term_name = $term->name ?? '';
|
$term_name = $term->name ?? '';
|
||||||
$term_desc = $term->description ?? '';
|
$term_desc = $term->description ?? '';
|
||||||
$active_orderby = (string) ($view['orderby'] ?? 'date');
|
$active_orderby = (string) ($view['orderby'] ?? 'date');
|
||||||
|
$active_order = strtoupper((string) ($view['order'] ?? 'DESC'));
|
||||||
$paging = (string) ($view['paging'] ?? 'number');
|
$paging = (string) ($view['paging'] ?? 'number');
|
||||||
$ias_s = !empty($view['ias_s']);
|
$ias_s = !empty($view['ias_s']);
|
||||||
$ias_max = (int) ($view['ias_max'] ?? 5);
|
$ias_max = (int) ($view['ias_max'] ?? 5);
|
||||||
$style = (string) ($view['style'] ?? 'default');
|
$style = (string) ($view['style'] ?? 'default');
|
||||||
$sales_cfg = is_array($view['sales'] ?? null) ? $view['sales'] : [];
|
$sales_cfg = is_array($view['sales'] ?? null) ? $view['sales'] : [];
|
||||||
|
$filter = is_array($view['filter'] ?? null) ? $view['filter'] : null;
|
||||||
$order_options = [
|
|
||||||
'date' => __('最新', 'aksrt'),
|
|
||||||
'sales' => __('销量', 'aksrt'),
|
|
||||||
'price_asc' => __('价格升序', 'aksrt'),
|
|
||||||
'price_desc' => __('价格降序', 'aksrt'),
|
|
||||||
'comments' => __('评价', 'aksrt'),
|
|
||||||
];
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content" class="site-main content-shell" tabindex="-1">
|
<main id="main-content" class="site-main content-shell" tabindex="-1">
|
||||||
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
|
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
|
||||||
|
|
||||||
<div class="aksrt-product-archive container"
|
<div class="aksrt-product-archive container"
|
||||||
data-aksrt-product-archive
|
data-aksrt-product-archive
|
||||||
data-taxonomy="aksrt_product_cat"
|
data-taxonomy="aksrt_product_cat"
|
||||||
data-term-id="<?php echo esc_attr((string) ($term->term_id ?? 0)); ?>"
|
data-term-id="<?php echo esc_attr((string) ($term->term_id ?? 0)); ?>"
|
||||||
data-orderby="<?php echo esc_attr($active_orderby); ?>"
|
data-orderby="<?php echo esc_attr($active_orderby); ?>"
|
||||||
data-page="<?php echo esc_attr((string) $paged); ?>"
|
data-order="<?php echo esc_attr($active_order); ?>"
|
||||||
data-max-pages="<?php echo esc_attr((string) $max_pages); ?>"
|
data-page="<?php echo esc_attr((string) $paged); ?>"
|
||||||
data-paging="<?php echo esc_attr($paging); ?>"
|
data-max-pages="<?php echo esc_attr((string) $max_pages); ?>"
|
||||||
data-ias="<?php echo $ias_s ? '1' : '0'; ?>"
|
data-paging="<?php echo esc_attr($paging); ?>"
|
||||||
data-ias-max="<?php echo esc_attr((string) $ias_max); ?>"
|
data-ias="<?php echo $ias_s ? '1' : '0'; ?>"
|
||||||
data-style="<?php echo esc_attr($style); ?>">
|
data-ias-max="<?php echo esc_attr((string) $ias_max); ?>"
|
||||||
|
data-style="<?php echo esc_attr($style); ?>">
|
||||||
|
|
||||||
<header class="aksrt-product-archive__header">
|
<header class="aksrt-product-archive__header shop-term-header ajax-item-header" data-aksrt-ajax-header>
|
||||||
<div class="aksrt-product-archive__eyebrow"><?php esc_html_e('商城商品', 'aksrt'); ?></div>
|
<div class="aksrt-product-archive__eyebrow"><?php esc_html_e('商城商品', 'aksrt'); ?></div>
|
||||||
<h1 class="aksrt-product-archive__title"><?php echo esc_html($term_name); ?></h1>
|
<h1 class="aksrt-product-archive__title" data-aksrt-archive-title><?php echo esc_html($term_name); ?></h1>
|
||||||
<?php if ($term_desc) : ?>
|
<?php if ($term_desc) : ?>
|
||||||
<p class="aksrt-product-archive__desc"><?php echo esc_html($term_desc); ?></p>
|
<p class="aksrt-product-archive__desc" data-aksrt-archive-desc><?php echo esc_html($term_desc); ?></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<p class="aksrt-product-archive__count" data-aksrt-archive-count><?php printf(esc_html__('共 %d 件商品', 'aksrt'), $total); ?></p>
|
<p class="aksrt-product-archive__count" data-aksrt-archive-count><?php printf(esc_html__('共 %d 件商品', 'aksrt'), $total); ?></p>
|
||||||
</header>
|
|
||||||
|
|
||||||
<nav class="aksrt-product-archive__toolbar" aria-label="<?php esc_attr_e('商品排序', 'aksrt'); ?>">
|
<?php
|
||||||
<?php foreach ($order_options as $key => $label) :
|
if ($filter) {
|
||||||
$url = add_query_arg(['shop_orderby' => $key]);
|
$orderby = $active_orderby;
|
||||||
?>
|
$order = $active_order;
|
||||||
<a class="aksrt-product-archive__sort<?php echo $active_orderby === $key ? ' is-active' : ''; ?>"
|
$term = $view['term'] ?? null;
|
||||||
href="<?php echo esc_url($url); ?>"
|
include get_template_directory() . '/templates/parts/shop/product-cat-filter.php';
|
||||||
data-aksrt-shop-orderby="<?php echo esc_attr($key); ?>">
|
}
|
||||||
<?php echo esc_html($label); ?>
|
?>
|
||||||
</a>
|
</header>
|
||||||
<?php endforeach; ?>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<?php if (!empty($products)) : ?>
|
<div class="ajaxpager product-lists-row aksrt-product-archive__ajaxpager"
|
||||||
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--<?php echo esc_attr($style); ?>" id="aksrt-product-grid" data-aksrt-product-grid>
|
data-aksrt-ajaxpager
|
||||||
<?php foreach ($products as $product) :
|
data-aksrt-ajax-clear="1">
|
||||||
get_template_part('templates/parts/shop/product', 'card', [
|
<div class="post_ajax_loader" data-aksrt-ajax-loader data-aksrt-ajax-loader-hide hidden>
|
||||||
'product' => $product,
|
<div class="aksrt-product-archive__skeleton">
|
||||||
'sales_cfg' => $sales_cfg,
|
<?php for ($i = 0; $i < 4; $i++) : ?>
|
||||||
]);
|
<div class="aksrt-product-card aksrt-product-card--placeholder placeholder"></div>
|
||||||
endforeach; ?>
|
<?php endfor; ?>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php if ($max_pages > 1) : ?>
|
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--<?php echo esc_attr($style); ?>" id="aksrt-product-grid" data-aksrt-product-grid>
|
||||||
<?php if ($paging === 'ajax') : ?>
|
<?php if (!empty($products)) : ?>
|
||||||
<div class="aksrt-product-archive__load-more">
|
<?php foreach ($products as $product) :
|
||||||
<button type="button" class="aksrt-load-more-btn" data-aksrt-shop-load-more><?php esc_html_e('加载更多', 'aksrt'); ?></button>
|
get_template_part('templates/parts/shop/product', 'card', [
|
||||||
</div>
|
'product' => $product,
|
||||||
<?php else : ?>
|
'sales_cfg' => $sales_cfg,
|
||||||
<nav class="aksrt-product-archive__pagination" aria-label="<?php esc_attr_e('商品分页', 'aksrt'); ?>">
|
]);
|
||||||
<?php
|
endforeach; ?>
|
||||||
echo paginate_links([
|
<?php else : ?>
|
||||||
'total' => $max_pages,
|
<?php echo function_exists('aksrt_get_ajax_null') ? aksrt_get_ajax_null(__('内容空空如也', 'aksrt')) : '<div class="aksrt-product-archive__empty ajax-item"><p>' . esc_html__('内容空空如也', 'aksrt') . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
'current' => $paged,
|
<?php endif; ?>
|
||||||
'prev_text' => '<i class="fas fa-chevron-left"></i>',
|
</div>
|
||||||
'next_text' => '<i class="fas fa-chevron-right"></i>',
|
|
||||||
'add_args' => $active_orderby ? ['shop_orderby' => $active_orderby] : [],
|
<?php if ($max_pages > 1 && $paging === 'ajax') : ?>
|
||||||
]);
|
<div class="ajax-pag text-center theme-pagination">
|
||||||
?>
|
<div class="next-page ajax-next">
|
||||||
</nav>
|
<a href="#"
|
||||||
<?php endif; ?>
|
class="ajax-next aksrt-load-more-btn"
|
||||||
<?php endif; ?>
|
data-aksrt-shop-load-more
|
||||||
<?php else : ?>
|
data-aksrt-ajax-next><?php esc_html_e('加载更多', 'aksrt'); ?></a>
|
||||||
<div class="aksrt-product-archive__empty">
|
</div>
|
||||||
<i class="fas fa-box-open"></i>
|
</div>
|
||||||
<p><?php esc_html_e('内容空空如也', 'aksrt'); ?></p>
|
<?php elseif ($max_pages > 1) : ?>
|
||||||
</div>
|
<nav class="aksrt-product-archive__pagination" aria-label="<?php esc_attr_e('商品分页', 'aksrt'); ?>">
|
||||||
<?php endif; ?>
|
<?php
|
||||||
</div>
|
echo paginate_links([
|
||||||
|
'total' => $max_pages,
|
||||||
|
'current' => $paged,
|
||||||
|
'prev_text' => '<i class="fas fa-chevron-left"></i>',
|
||||||
|
'next_text' => '<i class="fas fa-chevron-right"></i>',
|
||||||
|
'add_args' => array_filter([
|
||||||
|
'orderby' => $active_orderby,
|
||||||
|
'order' => $active_orderby === 'price' ? $active_order : null,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
?>
|
||||||
|
</nav>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
wp_enqueue_script('aksrt-product-archive', get_template_directory_uri() . '/assets/js/product-archive.js', ['aksrt-script'], AKSRT_VERSION, true);
|
wp_enqueue_script(
|
||||||
|
'aksrt-product-archive',
|
||||||
|
get_template_directory_uri() . '/assets/js/product-archive.js',
|
||||||
|
['aksrt-script', 'aksrt-core-ajax-list'],
|
||||||
|
AKSRT_VERSION,
|
||||||
|
true
|
||||||
|
);
|
||||||
get_footer();
|
get_footer();
|
||||||
+130
-82
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* 商品标签归档模板
|
* 商品标签归档模板 — sort + ajax load-more (zibll tag parity)
|
||||||
*
|
*
|
||||||
* @package AKSRT
|
* @package AKSRT
|
||||||
*/
|
*/
|
||||||
@@ -11,14 +11,25 @@ get_header();
|
|||||||
|
|
||||||
$term = get_queried_object();
|
$term = get_queried_object();
|
||||||
$paged = max(1, (int) get_query_var('paged'));
|
$paged = max(1, (int) get_query_var('paged'));
|
||||||
$orderby = isset($_GET['shop_orderby']) ? sanitize_key(wp_unslash((string) $_GET['shop_orderby'])) : '';
|
$orderby = '';
|
||||||
$shop = class_exists('\AKSRT\Shop\Shop') ? \AKSRT\Shop\Shop::get_instance() : null;
|
$order = '';
|
||||||
$view = $shop ? $shop->get_product_archive_view([
|
if (isset($_GET['orderby'])) {
|
||||||
'taxonomy' => 'aksrt_product_tag',
|
$orderby = sanitize_key(wp_unslash((string) $_GET['orderby']));
|
||||||
'term_id' => $term ? (int) $term->term_id : 0,
|
} elseif (isset($_GET['shop_orderby'])) {
|
||||||
'paged' => $paged,
|
$orderby = sanitize_key(wp_unslash((string) $_GET['shop_orderby']));
|
||||||
'orderby' => $orderby,
|
}
|
||||||
]) : ['products' => [], 'term' => null, 'total' => 0, 'max_pages' => 0, 'orderby' => 'date', 'paging' => 'number'];
|
if (isset($_GET['order'])) {
|
||||||
|
$order = sanitize_key(wp_unslash((string) $_GET['order']));
|
||||||
|
}
|
||||||
|
|
||||||
|
$shop = class_exists('\AKSRT\Shop\Shop') ? \AKSRT\Shop\Shop::get_instance() : null;
|
||||||
|
$view = $shop ? $shop->get_product_archive_view([
|
||||||
|
'taxonomy' => 'aksrt_product_tag',
|
||||||
|
'term_id' => $term ? (int) $term->term_id : 0,
|
||||||
|
'paged' => $paged,
|
||||||
|
'orderby' => $orderby,
|
||||||
|
'order' => $order,
|
||||||
|
]) : ['products' => [], 'term' => null, 'total' => 0, 'max_pages' => 0, 'orderby' => 'date', 'order' => 'DESC', 'paging' => 'number'];
|
||||||
|
|
||||||
$products = $view['products'] ?? [];
|
$products = $view['products'] ?? [];
|
||||||
$total = (int) ($view['total'] ?? 0);
|
$total = (int) ($view['total'] ?? 0);
|
||||||
@@ -26,95 +37,132 @@ $max_pages = (int) ($view['max_pages'] ?? 0);
|
|||||||
$term_name = $term->name ?? '';
|
$term_name = $term->name ?? '';
|
||||||
$term_desc = $term->description ?? '';
|
$term_desc = $term->description ?? '';
|
||||||
$active_orderby = (string) ($view['orderby'] ?? 'date');
|
$active_orderby = (string) ($view['orderby'] ?? 'date');
|
||||||
|
$active_order = strtoupper((string) ($view['order'] ?? 'DESC'));
|
||||||
$paging = (string) ($view['paging'] ?? 'number');
|
$paging = (string) ($view['paging'] ?? 'number');
|
||||||
$ias_s = !empty($view['ias_s']);
|
$ias_s = !empty($view['ias_s']);
|
||||||
$ias_max = (int) ($view['ias_max'] ?? 5);
|
$ias_max = (int) ($view['ias_max'] ?? 5);
|
||||||
$style = (string) ($view['style'] ?? 'default');
|
$style = (string) ($view['style'] ?? 'default');
|
||||||
$sales_cfg = is_array($view['sales'] ?? null) ? $view['sales'] : [];
|
$sales_cfg = is_array($view['sales'] ?? null) ? $view['sales'] : [];
|
||||||
|
|
||||||
$order_options = [
|
$order_labels = [
|
||||||
'date' => __('最新', 'aksrt'),
|
'date' => __('最新', 'aksrt'),
|
||||||
'sales' => __('销量', 'aksrt'),
|
'views' => __('最热', 'aksrt'),
|
||||||
'price_asc' => __('价格升序', 'aksrt'),
|
'favorite_count' => __('收藏', 'aksrt'),
|
||||||
'price_desc' => __('价格降序', 'aksrt'),
|
'score' => __('评分', 'aksrt'),
|
||||||
'comments' => __('评价', 'aksrt'),
|
'sales' => __('销量', 'aksrt'),
|
||||||
];
|
];
|
||||||
|
$base_url = $term && !is_wp_error(get_term_link($term)) ? get_term_link($term) : '';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content" class="site-main content-shell" tabindex="-1">
|
<main id="main-content" class="site-main content-shell" tabindex="-1">
|
||||||
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
|
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
|
||||||
|
|
||||||
<div class="aksrt-product-archive container"
|
<div class="aksrt-product-archive container"
|
||||||
data-aksrt-product-archive
|
data-aksrt-product-archive
|
||||||
data-taxonomy="aksrt_product_tag"
|
data-taxonomy="aksrt_product_tag"
|
||||||
data-term-id="<?php echo esc_attr((string) ($term->term_id ?? 0)); ?>"
|
data-term-id="<?php echo esc_attr((string) ($term->term_id ?? 0)); ?>"
|
||||||
data-orderby="<?php echo esc_attr($active_orderby); ?>"
|
data-orderby="<?php echo esc_attr($active_orderby); ?>"
|
||||||
data-page="<?php echo esc_attr((string) $paged); ?>"
|
data-order="<?php echo esc_attr($active_order); ?>"
|
||||||
data-max-pages="<?php echo esc_attr((string) $max_pages); ?>"
|
data-page="<?php echo esc_attr((string) $paged); ?>"
|
||||||
data-paging="<?php echo esc_attr($paging); ?>"
|
data-max-pages="<?php echo esc_attr((string) $max_pages); ?>"
|
||||||
data-ias="<?php echo $ias_s ? '1' : '0'; ?>"
|
data-paging="<?php echo esc_attr($paging); ?>"
|
||||||
data-ias-max="<?php echo esc_attr((string) $ias_max); ?>"
|
data-ias="<?php echo $ias_s ? '1' : '0'; ?>"
|
||||||
data-style="<?php echo esc_attr($style); ?>">
|
data-ias-max="<?php echo esc_attr((string) $ias_max); ?>"
|
||||||
|
data-style="<?php echo esc_attr($style); ?>">
|
||||||
|
|
||||||
<header class="aksrt-product-archive__header">
|
<header class="aksrt-product-archive__header shop-term-header" data-aksrt-ajax-header>
|
||||||
<div class="aksrt-product-archive__eyebrow"><?php esc_html_e('商品标签', 'aksrt'); ?></div>
|
<div class="aksrt-product-archive__eyebrow"><?php esc_html_e('商城标签', 'aksrt'); ?></div>
|
||||||
<h1 class="aksrt-product-archive__title"><?php echo esc_html($term_name); ?></h1>
|
<h1 class="aksrt-product-archive__title"><?php echo esc_html($term_name); ?></h1>
|
||||||
<?php if ($term_desc) : ?>
|
<?php if ($term_desc) : ?>
|
||||||
<p class="aksrt-product-archive__desc"><?php echo esc_html($term_desc); ?></p>
|
<p class="aksrt-product-archive__desc"><?php echo esc_html($term_desc); ?></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<p class="aksrt-product-archive__count" data-aksrt-archive-count><?php printf(esc_html__('共 %d 件商品', 'aksrt'), $total); ?></p>
|
<p class="aksrt-product-archive__count" data-aksrt-archive-count><?php printf(esc_html__('共 %d 件商品', 'aksrt'), $total); ?></p>
|
||||||
</header>
|
|
||||||
|
|
||||||
<nav class="aksrt-product-archive__toolbar" aria-label="<?php esc_attr_e('商品排序', 'aksrt'); ?>">
|
<div class="shop-cat-filter-orderby shop-cat-filter-child" win-ajax-replace="orderby" data-aksrt-shop-orderby-bar>
|
||||||
<?php foreach ($order_options as $key => $label) :
|
<span class="opacity5"><?php esc_html_e('排序', 'aksrt'); ?></span>
|
||||||
$url = add_query_arg(['shop_orderby' => $key]);
|
<?php foreach ($order_labels as $key => $label) :
|
||||||
?>
|
if ($active_orderby === $key) : ?>
|
||||||
<a class="aksrt-product-archive__sort<?php echo $active_orderby === $key ? ' is-active' : ''; ?>"
|
<span class="focus-color"><?php echo esc_html($label); ?></span>
|
||||||
href="<?php echo esc_url($url); ?>"
|
<?php else :
|
||||||
data-aksrt-shop-orderby="<?php echo esc_attr($key); ?>">
|
$href = $base_url ? add_query_arg(['orderby' => $key], $base_url) : add_query_arg(['orderby' => $key]);
|
||||||
<?php echo esc_html($label); ?>
|
?>
|
||||||
</a>
|
<a rel="nofollow" ajax-replace="true" class="ajax-next" href="<?php echo esc_url($href); ?>" data-aksrt-shop-orderby="<?php echo esc_attr($key); ?>">
|
||||||
<?php endforeach; ?>
|
<?php echo esc_html($label); ?>
|
||||||
</nav>
|
</a>
|
||||||
|
<?php endif;
|
||||||
|
endforeach;
|
||||||
|
if ($active_orderby === 'price') {
|
||||||
|
$next_order = $active_order === 'DESC' ? 'ASC' : 'DESC';
|
||||||
|
$icon = $next_order === 'DESC' ? 'up' : 'down';
|
||||||
|
$href = $base_url ? add_query_arg(['orderby' => 'price', 'order' => $next_order], $base_url) : add_query_arg(['orderby' => 'price', 'order' => $next_order]);
|
||||||
|
?>
|
||||||
|
<a rel="nofollow" ajax-replace="true" class="ajax-next focus-color" href="<?php echo esc_url($href); ?>" data-aksrt-shop-orderby="price" data-aksrt-shop-order="<?php echo esc_attr($next_order); ?>">
|
||||||
|
<?php esc_html_e('售价', 'aksrt'); ?><i class="opacity5 ml3 fa fa-long-arrow-<?php echo esc_attr($icon); ?>"></i>
|
||||||
|
</a>
|
||||||
|
<?php } else {
|
||||||
|
$href = $base_url ? add_query_arg(['orderby' => 'price'], $base_url) : add_query_arg(['orderby' => 'price']);
|
||||||
|
?>
|
||||||
|
<a rel="nofollow" ajax-replace="true" class="ajax-next" href="<?php echo esc_url($href); ?>" data-aksrt-shop-orderby="price">
|
||||||
|
<?php esc_html_e('售价', 'aksrt'); ?>
|
||||||
|
</a>
|
||||||
|
<?php } ?>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
<?php if (!empty($products)) : ?>
|
<div class="ajaxpager product-lists-row aksrt-product-archive__ajaxpager" data-aksrt-ajaxpager data-aksrt-ajax-clear="1">
|
||||||
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--<?php echo esc_attr($style); ?>" id="aksrt-product-grid" data-aksrt-product-grid>
|
<div class="post_ajax_loader" data-aksrt-ajax-loader data-aksrt-ajax-loader-hide hidden>
|
||||||
<?php foreach ($products as $product) :
|
<div class="aksrt-product-archive__skeleton">
|
||||||
get_template_part('templates/parts/shop/product', 'card', [
|
<?php for ($i = 0; $i < 4; $i++) : ?>
|
||||||
'product' => $product,
|
<div class="aksrt-product-card aksrt-product-card--placeholder placeholder"></div>
|
||||||
'sales_cfg' => $sales_cfg,
|
<?php endfor; ?>
|
||||||
]);
|
</div>
|
||||||
endforeach; ?>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if ($max_pages > 1) : ?>
|
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--<?php echo esc_attr($style); ?>" id="aksrt-product-grid" data-aksrt-product-grid>
|
||||||
<?php if ($paging === 'ajax') : ?>
|
<?php if (!empty($products)) : ?>
|
||||||
<div class="aksrt-product-archive__load-more">
|
<?php foreach ($products as $product) :
|
||||||
<button type="button" class="aksrt-load-more-btn" data-aksrt-shop-load-more><?php esc_html_e('加载更多', 'aksrt'); ?></button>
|
get_template_part('templates/parts/shop/product', 'card', [
|
||||||
</div>
|
'product' => $product,
|
||||||
<?php else : ?>
|
'sales_cfg' => $sales_cfg,
|
||||||
<nav class="aksrt-product-archive__pagination" aria-label="<?php esc_attr_e('商品分页', 'aksrt'); ?>">
|
]);
|
||||||
<?php
|
endforeach; ?>
|
||||||
echo paginate_links([
|
<?php else : ?>
|
||||||
'total' => $max_pages,
|
<?php echo function_exists('aksrt_get_ajax_null') ? aksrt_get_ajax_null(__('内容空空如也', 'aksrt')) : '<div class="aksrt-product-archive__empty ajax-item"><p>' . esc_html__('内容空空如也', 'aksrt') . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
'current' => $paged,
|
<?php endif; ?>
|
||||||
'prev_text' => '<i class="fas fa-chevron-left"></i>',
|
</div>
|
||||||
'next_text' => '<i class="fas fa-chevron-right"></i>',
|
|
||||||
'add_args' => $active_orderby ? ['shop_orderby' => $active_orderby] : [],
|
<?php if ($max_pages > 1 && $paging === 'ajax') : ?>
|
||||||
]);
|
<div class="ajax-pag text-center theme-pagination">
|
||||||
?>
|
<div class="next-page ajax-next">
|
||||||
</nav>
|
<a href="#" class="ajax-next aksrt-load-more-btn" data-aksrt-shop-load-more data-aksrt-ajax-next><?php esc_html_e('加载更多', 'aksrt'); ?></a>
|
||||||
<?php endif; ?>
|
</div>
|
||||||
<?php endif; ?>
|
</div>
|
||||||
<?php else : ?>
|
<?php elseif ($max_pages > 1) : ?>
|
||||||
<div class="aksrt-product-archive__empty">
|
<nav class="aksrt-product-archive__pagination" aria-label="<?php esc_attr_e('商品分页', 'aksrt'); ?>">
|
||||||
<i class="fas fa-box-open"></i>
|
<?php
|
||||||
<p><?php esc_html_e('内容空空如也', 'aksrt'); ?></p>
|
echo paginate_links([
|
||||||
</div>
|
'total' => $max_pages,
|
||||||
<?php endif; ?>
|
'current' => $paged,
|
||||||
</div>
|
'prev_text' => '<i class="fas fa-chevron-left"></i>',
|
||||||
|
'next_text' => '<i class="fas fa-chevron-right"></i>',
|
||||||
|
'add_args' => array_filter([
|
||||||
|
'orderby' => $active_orderby,
|
||||||
|
'order' => $active_orderby === 'price' ? $active_order : null,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
?>
|
||||||
|
</nav>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
wp_enqueue_script('aksrt-product-archive', get_template_directory_uri() . '/assets/js/product-archive.js', ['aksrt-script'], AKSRT_VERSION, true);
|
wp_enqueue_script(
|
||||||
|
'aksrt-product-archive',
|
||||||
|
get_template_directory_uri() . '/assets/js/product-archive.js',
|
||||||
|
['aksrt-script', 'aksrt-core-ajax-list'],
|
||||||
|
AKSRT_VERSION,
|
||||||
|
true
|
||||||
|
);
|
||||||
get_footer();
|
get_footer();
|
||||||
Reference in new issue
Block a user