- 导入 archive 模板 post 1398(slug=shop-archive),/collection/ 用 ElementorRenderer 直出 hero/两列外壳,按 widget id 注入 ShopFilters/ShopProducts;新增 server function 解决客户端导航时 loader 打不开 db 的问题 - C1 hero:面包屑 Home / Shop(BreadcrumbWidget + vars.breadcrumb 上下文) - C2 筛选:12 组属性(term taxonomy 顺序,scripts/import-attribute-term-order.ts); 长期列表 5 项 + See more,Battery/Operating/Install 默认折叠;URL query 驱动, SoM 筛选实测 22 条;顶部 Filters 标题/已选 chips/Clear all - C3 网格:WooCommerce 归档 DOM(结果计数、orderby、24 卡 4 列、卡片 1:1 图/标题/ Read more);默认排序导入 products.meta.menu_order(scripts/import-product-menu-order.ts), 前三个商品与原站一致(DSOM-040R/110R/130N) - C4 分页:页码/箭头、当前页样式、page2 25–48 条验证 - 修复 Tailwind .columns-4 与 WooCommerce 网格类冲突;app.css 新增 shop 归档 scoped 样式 - 1436 实测:hero 52.8、shop 节 2906.7、筛选区 2798.7、网格 2523.3、卡 257.7×409、 分页 y2855,与原站逐项一致(±6px 内);bun test 11 pass;版本 0.10.21
113 lines
3.6 KiB
TypeScript
113 lines
3.6 KiB
TypeScript
/**
|
||
* # 脚本 导入产品属性术语顺序(对齐原站 /shop/ 筛选列表顺序)
|
||
* 原站 WPC 筛选按 wp_term_taxonomy 中的术语顺序展示(取证:pa_product-type 顺序
|
||
* SoM → IoT Gateway → Wi-Fi Repeater → Router → Beacon,对应 term_id 756/764/845/846/862;
|
||
* pa_cpu 顺序 PX30 → RK3328 → RK3588 → PX30K …)。本项目导入时按字母序写入,需要修复。
|
||
* 做法:解析 dump 的 wp_terms(term_id→name)与 wp_term_taxonomy(插入顺序),
|
||
* 对每个 pa_<属性 slug>,按顺序把 product_attribute_values.sort 设为序号。
|
||
* 运行:bun scripts/import-attribute-term-order.ts
|
||
*/
|
||
import { SQL } from "bun";
|
||
|
||
const DUMP = "/home/bigcode/data/dev/sites/dusuniot/legacy/dusuniot-db-20261029.sql";
|
||
const db = new SQL("postgres://dusuniot:dusuniot@127.0.0.1:25432/dusuniot");
|
||
|
||
/** # 函数 提取某张表的 INSERT 段文本(支持多段 INSERT) */
|
||
function tableInserts(lines: string[], table: string): string[] {
|
||
const out: string[] = [];
|
||
let buf = "";
|
||
let on = false;
|
||
for (const l of lines) {
|
||
if (l.startsWith(`INSERT INTO \`${table}\` VALUES`)) {
|
||
on = true;
|
||
buf = l;
|
||
} else if (on) {
|
||
buf += l;
|
||
}
|
||
if (on && l.trimEnd().endsWith(";")) {
|
||
out.push(buf);
|
||
buf = "";
|
||
on = false;
|
||
}
|
||
}
|
||
return out;
|
||
}
|
||
|
||
/** # 函数 解析 SQL 值元组 */
|
||
function parseTuples(s: string): string[][] {
|
||
const out: string[][] = [];
|
||
let p = s.indexOf("(");
|
||
while (p >= 0 && p < s.length) {
|
||
const values: string[] = [];
|
||
let cur = "";
|
||
let inQ = false;
|
||
let esc = false;
|
||
let depth = 0;
|
||
p++;
|
||
for (; p < s.length; p++) {
|
||
const ch = s[p]!;
|
||
if (esc) { cur += ch; esc = false; continue; }
|
||
if (inQ) {
|
||
if (ch === "\\") { esc = true; continue; }
|
||
if (ch === "'") { inQ = false; continue; }
|
||
cur += ch;
|
||
continue;
|
||
}
|
||
if (ch === "'") { inQ = true; continue; }
|
||
if (ch === "(") { depth++; cur += ch; continue; }
|
||
if (ch === ")") {
|
||
if (depth === 0) { values.push(cur); cur = ""; p++; break; }
|
||
depth--;
|
||
cur += ch;
|
||
continue;
|
||
}
|
||
if (ch === "," && depth === 0) { values.push(cur); cur = ""; continue; }
|
||
cur += ch;
|
||
}
|
||
out.push(values);
|
||
p = s.indexOf("(", p);
|
||
}
|
||
return out;
|
||
}
|
||
|
||
const lines = (await Bun.file(DUMP).text()).split("\n");
|
||
|
||
// term_id → name
|
||
const nameById = new Map<number, string>();
|
||
for (const seg of tableInserts(lines, "wp_terms")) {
|
||
for (const v of parseTuples(seg)) {
|
||
if (v[0]) nameById.set(Number(v[0]), v[1] ?? "");
|
||
}
|
||
}
|
||
console.log("terms:", nameById.size);
|
||
|
||
// taxonomy → [term names](按 dump 插入顺序)
|
||
const byTax = new Map<string, string[]>();
|
||
for (const seg of tableInserts(lines, "wp_term_taxonomy")) {
|
||
for (const v of parseTuples(seg)) {
|
||
const taxonomy = v[2] ?? "";
|
||
const termId = Number(v[1]);
|
||
if (!taxonomy.startsWith("pa_")) continue;
|
||
const name = nameById.get(termId);
|
||
if (!name) continue;
|
||
const list = byTax.get(taxonomy) ?? [];
|
||
list.push(name);
|
||
byTax.set(taxonomy, list);
|
||
}
|
||
}
|
||
|
||
let updated = 0;
|
||
for (const [taxonomy, names] of byTax) {
|
||
const attrSlug = taxonomy.slice(3);
|
||
for (let i = 0; i < names.length; i++) {
|
||
const res = await db`
|
||
UPDATE product_attribute_values v SET sort = ${i}
|
||
FROM product_attributes a
|
||
WHERE v.attribute_id = a.id AND a.slug = ${attrSlug} AND lower(trim(v.value)) = lower(trim(${names[i]!}))`;
|
||
updated += res.count;
|
||
}
|
||
console.log(taxonomy, "→", names.length, "terms");
|
||
}
|
||
console.log("updated rows:", updated);
|
||
await db.end();
|