v0.10.19: G2 页脚 Footer 一比一复刻(原站 elementor_library post 58)
- 导入脚本 scripts/import-footer-template.ts:从 legacy dump 提取 post 58 的 _elementor_data 写入 contents(type=template, slug=footer),并按线上 post-58.css/DOM 补齐快照后改动 (f95e22e Google Preferred Source、405d251 width:auto、2481635 桌面外距) - Layout/getLayoutData 下发 footerDoc,Footer 改用 ElementorRenderer 直出原模板, 短代码按 widget id 注入:menu-2 移动端折叠菜单、gtranslate 语言下拉(原生 select.gt_selector) - Renderer 增强:section html_tag/边框/content_position、column 响应式宽度与 populated padding/margin(tablet/mobile)、widget 响应式盒模型、icon widget(fixed 返回顶部)、 icon-list 图标/间距/文字排版与 CSS 变量悬停、image 宽度、divider Elementor DOM、 text-editor 对齐与 current-date-time 动态年份、shortcode 预渲染上下文 - slim 白名单补齐响应式/图标/动态标签字段;app.css 新增 FA Solid/Regular 字体、 页脚 scoped 规则、elementor-hidden-* 响应式可见性 - 实测 1436:页脚总高 590.4 与原站全等(列宽/内层列/logo/社交/下拉逐项一致); 390:56/15/347/337/97/46.4/61 逐项全等;语言切换写 ui_lang cookie;返回顶部回滚 0 - bun test 11 pass;版本 0.10.19
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* # 脚本 导入页脚 Elementor 模板(legacy elementor_library post 58)
|
||||
* 背景:WordPress 导入管线未迁移 elementor_library 类型(仅 page/post/landing),
|
||||
* 页脚模板(post 58,含 46d7afa / d834160 两节及其内嵌 28c7f0b8 / a428bb4)因此缺失。
|
||||
* 数据源:legacy/dusuniot-db-20261029.sql 中 `(meta_id,58,'_elementor_data','…')` 行。
|
||||
* 补丁:线上页脚另有 f95e22e(Google Preferred Source 图,dump 快照之后新增),
|
||||
* 依线上 DOM(/tmp/orig-footer.html 取证:class elementor-widget__width-inherit、
|
||||
* img 528×64、链接 google.com/preferences/source?q=dusuniot.com)补入 2ccb47d 列末位。
|
||||
* 结果写入 contents(type=template, slug=footer, meta.elementor),供 Layout 渲染。
|
||||
* 运行:bun scripts/import-footer-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 58 的 _elementor_data 并反转义为 JSON
|
||||
* 返回值 Elementor 元素数组
|
||||
*/
|
||||
async function extractTemplate(): Promise<Record<string, unknown>[]> {
|
||||
const text = await Bun.file(DUMP).text();
|
||||
const m = text.match(/\(\d+,58,'_elementor_data','((?:[^'\\]|\\.)*)'\)/);
|
||||
if (!m) throw new Error("dump 中未找到 post 58 的 _elementor_data");
|
||||
const raw = m[1]!;
|
||||
// SQL dump 反斜杠转义:\" → "、\' → '、\\ → \
|
||||
const json = raw.replace(/\\'/g, "'").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
||||
const data = JSON.parse(json);
|
||||
if (!Array.isArray(data)) throw new Error("_elementor_data 不是数组");
|
||||
return data as Record<string, unknown>[];
|
||||
}
|
||||
|
||||
/** # 函数 深度查找指定 id 的元素节点 */
|
||||
function findElement(els: Record<string, unknown>[], id: string): Record<string, unknown> | null {
|
||||
for (const el of els) {
|
||||
if (el.id === id) return el;
|
||||
const children = el.elements as Record<string, unknown>[] | undefined;
|
||||
if (children?.length) {
|
||||
const hit = findElement(children, id);
|
||||
if (hit) return hit;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** # 函数 线上快照新增的 f95e22e(Google Preferred Source 图)
|
||||
* 线上 post-58.css 取证:.elementor-element-f95e22e img{width:300px}、
|
||||
* > .elementor-widget-container{margin:10px 0 0};dump 快照之后新增,故在此补全。
|
||||
*/
|
||||
function preferredSourceWidget(): Record<string, unknown> {
|
||||
return {
|
||||
id: "f95e22e",
|
||||
elType: "widget",
|
||||
settings: {
|
||||
image: {
|
||||
url: "http://www.dusuniot.com/wp-content/uploads/2022/06/google-preffered-source.png",
|
||||
id: 161805,
|
||||
alt: "google prefferd source",
|
||||
source: "library",
|
||||
size: "",
|
||||
},
|
||||
image_size: "full",
|
||||
width: { unit: "px", size: 300, sizes: [] },
|
||||
align: "left",
|
||||
_element_width: "inherit",
|
||||
_margin: { unit: "px", top: "10", right: "0", bottom: "0", left: "0", isLinked: false },
|
||||
link: {
|
||||
url: "https://www.google.com/preferences/source?q=dusuniot.com",
|
||||
is_external: "on",
|
||||
nofollow: "on",
|
||||
custom_attributes: "",
|
||||
},
|
||||
},
|
||||
elements: [],
|
||||
widgetType: "image",
|
||||
};
|
||||
}
|
||||
|
||||
const elements = await extractTemplate();
|
||||
|
||||
// 补丁:2ccb47d 列末尾追加 f95e22e(幂等:已存在则跳过)
|
||||
const col = findElement(elements, "2ccb47d");
|
||||
if (!col) throw new Error("模板缺少 2ccb47d 列");
|
||||
const colChildren = (col.elements as Record<string, unknown>[]) || [];
|
||||
const psIdx = colChildren.findIndex((el) => el.id === "f95e22e");
|
||||
if (psIdx >= 0) colChildren[psIdx] = preferredSourceWidget();
|
||||
else colChildren.push(preferredSourceWidget());
|
||||
col.elements = colChildren;
|
||||
|
||||
// 补丁:社交图标行 405d251 宽度模式(线上 class=elementor-widget__width-auto、
|
||||
// 生成 CSS width:auto;dump 快照为 inherit,实测线上为 auto → 与 gtranslate 同排)
|
||||
const social = findElement(elements, "405d251");
|
||||
if (social) {
|
||||
const st = (social.settings as Record<string, unknown>) || {};
|
||||
st._element_width = "auto";
|
||||
social.settings = st;
|
||||
}
|
||||
// 补丁:gtranslate 短代码控件 2481635 桌面外距(线上 post-58.css:margin -10px 0 0 20px;
|
||||
// dump 只有 _margin_mobile,桌面值来自快照之后的编辑)
|
||||
const gt = findElement(elements, "2481635");
|
||||
if (gt) {
|
||||
const st = (gt.settings as Record<string, unknown>) || {};
|
||||
st._margin = { unit: "px", top: "-10", right: "0", bottom: "0", left: "20", isLinked: false };
|
||||
gt.settings = st;
|
||||
}
|
||||
|
||||
const meta = JSON.stringify({ elementor: elements });
|
||||
|
||||
// 写入 contents:type=template / slug=footer;已存在则更新
|
||||
const existing = await db`SELECT id FROM contents WHERE slug='footer' AND type='template'`;
|
||||
if (existing.length) {
|
||||
await db`UPDATE contents SET meta=${meta}::jsonb, status='published', updated_at=now() WHERE id=${existing[0]!.id}`;
|
||||
console.log("已更新 footer 模板,contents.id =", existing[0]!.id);
|
||||
} else {
|
||||
const inserted = await db`
|
||||
INSERT INTO contents (type, slug, title, status, meta, legacy_id, published_at)
|
||||
VALUES ('template', 'footer', 'Footer', 'published', ${meta}::jsonb, 58, now())
|
||||
RETURNING id`;
|
||||
console.log("已插入 footer 模板,contents.id =", inserted[0]!.id);
|
||||
}
|
||||
|
||||
// 验证:节数量与顶层 id
|
||||
const top = elements.map((el) => el.id).join(", ");
|
||||
console.log("顶层节:", top);
|
||||
await db.end();
|
||||
Reference in New Issue
Block a user