Rewrite WordPress cross-page links to site-relative paths
Content linked between pages using absolute WordPress URLs -- 100 occurrences across 39 files, many against wp.vicidial.com, the old WordPress backend host that won't outlive this migration, the rest against www.vicidial.com in ?page_id=N form. The export now resolves those IDs against the published page/post set and emits /slug (or /blog/slug) instead. All 100 resolved; links to vicihost.com are a separate site and deliberately untouched. Verified every internal href in the built output corresponds to a page that actually exists -- no broken links. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+37
-3
@@ -82,6 +82,32 @@ function rewriteImageUrls(html, fromDir) {
|
||||
);
|
||||
}
|
||||
|
||||
// Content links between pages are stored as absolute WordPress URLs, many of them against
|
||||
// wp.vicidial.com -- the old WordPress backend host, which won't outlive this migration.
|
||||
// Turn them into site-relative paths. IDs with no published page/post behind them (deleted
|
||||
// pages, a stray revision) are left alone: they are already broken on the live site.
|
||||
function rewriteInternalLinks(html, linkMap, unresolved) {
|
||||
return html.replace(
|
||||
/https?:\/\/(?:www\.|wp\.)?vicidial\.(?:com|net)\/\?(?:page_id|p)=(\d+)/gi,
|
||||
(match, id) => {
|
||||
const target = linkMap.get(Number(id));
|
||||
if (!target) {
|
||||
unresolved.add(id);
|
||||
return match;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function buildLinkMap(conn) {
|
||||
const [rows] = await conn.execute(
|
||||
`SELECT ID, post_type, post_name FROM ${TABLE_PREFIX}posts
|
||||
WHERE post_status = 'publish' AND post_type IN ('page', 'post')`
|
||||
);
|
||||
return new Map(rows.map((r) => [r.ID, r.post_type === 'post' ? `/blog/${r.post_name}` : `/${r.post_name}`]));
|
||||
}
|
||||
|
||||
async function copyAttachments() {
|
||||
// Copy the whole uploads tree rather than just the 82 attachment rows: WordPress generates
|
||||
// multiple resized variants per image (e.g. "-1008x1024.png") that content <img> tags/srcsets
|
||||
@@ -91,7 +117,7 @@ async function copyAttachments() {
|
||||
console.log(`Copied uploads tree to ${UPLOADS_DEST}`);
|
||||
}
|
||||
|
||||
async function exportPostType(conn, postType, destDir, { attachmentPaths, thumbnails }) {
|
||||
async function exportPostType(conn, postType, destDir, { attachmentPaths, thumbnails, linkMap, unresolved }) {
|
||||
const [rows] = await conn.execute(
|
||||
`SELECT ID, post_title, post_name, post_date, post_content, post_excerpt
|
||||
FROM ${TABLE_PREFIX}posts WHERE post_type = ? AND post_status = 'publish' ORDER BY post_date DESC`,
|
||||
@@ -107,6 +133,7 @@ async function exportPostType(conn, postType, destDir, { attachmentPaths, thumbn
|
||||
html = wpautop(html);
|
||||
}
|
||||
html = rewriteImageUrls(html, destDir);
|
||||
html = rewriteInternalLinks(html, linkMap, unresolved);
|
||||
const markdown = turndown.turndown(html);
|
||||
|
||||
let excerpt = fixLiteralNewlines(row.post_excerpt || '');
|
||||
@@ -174,8 +201,15 @@ async function main() {
|
||||
const thumbnails = new Map(thumbRows.map((r) => [r.post_id, r.meta_value]));
|
||||
|
||||
await copyAttachments();
|
||||
await exportPostType(conn, 'page', PAGES_DEST, { attachmentPaths, thumbnails });
|
||||
await exportPostType(conn, 'post', POSTS_DEST, { attachmentPaths, thumbnails });
|
||||
const linkMap = await buildLinkMap(conn);
|
||||
const unresolved = new Set();
|
||||
|
||||
await exportPostType(conn, 'page', PAGES_DEST, { attachmentPaths, thumbnails, linkMap, unresolved });
|
||||
await exportPostType(conn, 'post', POSTS_DEST, { attachmentPaths, thumbnails, linkMap, unresolved });
|
||||
|
||||
if (unresolved.size) {
|
||||
console.warn(`Left ${unresolved.size} link(s) pointing at WordPress IDs with no published page: ${[...unresolved].join(', ')}`);
|
||||
}
|
||||
await exportNav(conn);
|
||||
|
||||
await conn.end();
|
||||
|
||||
Reference in New Issue
Block a user