/** * # 脚本 导入产品归档页 Elementor 模板(legacy elementor_library post 1398) * 原站 /shop/ 与产品分类归档共用 archive 模板 post 1398(elementor_location=archive): * - a2ab15c:面包屑 hero(bg #F4F5F8 / padding 0 30 / content 1400) * - 65176b9:两列(20% WPC 筛选 + 80% 标题 + WooCommerce 商品归档) * - 61b1990:移动端归档描述(hide_desktop) * 写入 contents(type=template, slug=shop-archive, meta.elementor),供 * collection 路由以 ElementorRenderer 直出外壳,筛选/商品网格按 widget id 注入。 * 运行:bun scripts/import-shop-template.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"); /** # 函数 从 dump 提取指定 post 的 _elementor_data */ async function extractTemplate(postId: number): Promise[]> { const text = await Bun.file(DUMP).text(); const re = new RegExp("\\(\\d+," + postId + ",'_elementor_data','((?:[^'\\\\]|\\\\.)*)'\\)"); const m = text.match(re); if (!m) throw new Error(`dump 中未找到 post ${postId} 的 _elementor_data`); const json = m[1]!.replace(/\\'/g, "'").replace(/\\"/g, '"').replace(/\\\\/g, "\\"); const data = JSON.parse(json); if (!Array.isArray(data)) throw new Error("_elementor_data 不是数组"); return data as Record[]; } const elements = await extractTemplate(1398); const meta = JSON.stringify({ elementor: elements }); const existing = await db`SELECT id FROM contents WHERE slug='shop-archive' AND type='template'`; if (existing.length) { await db`UPDATE contents SET meta=${meta}::text::jsonb, status='published', updated_at=now() WHERE id=${existing[0]!.id}`; console.log("已更新 shop-archive 模板,contents.id =", existing[0]!.id); } else { const inserted = await db` INSERT INTO contents (type, slug, title, status, meta, legacy_id, published_at) VALUES ('template', 'shop-archive', 'Shop Archive', 'published', ${meta}::text::jsonb, 1398, now()) RETURNING id`; console.log("已插入 shop-archive 模板,contents.id =", inserted[0]!.id); } console.log("顶层节:", elements.map((el) => el.id).join(", ")); await db.end();