From 677f5699ba004146b254af4a29376f292893c8ef Mon Sep 17 00:00:00 2001 From: Filip Ilic Date: Thu, 11 Jun 2026 20:52:59 +0200 Subject: [PATCH] Fix: repoint sitemap XSL stylesheet to local copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yoast emits the sitemap's as a protocol-relative absolute URL (///.../main-sitemap.xsl). When the clone is served from any host other than the original domain, the browser fetches the XSL cross-origin from the live site, the XSLT transform is blocked, and the sitemap renders blank (raw XML is fine in view-source — only the styled render breaks). The existing passes miss it: rewrite-paths.py processes *.html only, and its abs-URL rule matches https?:// not the protocol-relative // form. Add a Phase 1 recipe (AGENTS.md) that repoints each sitemap's stylesheet at the local copy, handling both // and https:// forms, and expand gotcha #5 (SKILL.md) to document the blank-render trap. Docs/recipe only — no script changes. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Filip Ilic --- wp-static-clone/AGENTS.md | 11 +++++++++++ wp-static-clone/SKILL.md | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/wp-static-clone/AGENTS.md b/wp-static-clone/AGENTS.md index c2c8138..38d9806 100644 --- a/wp-static-clone/AGENTS.md +++ b/wp-static-clone/AGENTS.md @@ -29,6 +29,17 @@ mkdir -p output/wp-content/plugins/wordpress-seo/css curl -s -A "Mozilla/5.0" \ "$ROOT/wp-content/plugins/wordpress-seo/css/main-sitemap.xsl" \ -o output/wp-content/plugins/wordpress-seo/css/main-sitemap.xsl + +# Repoint the sitemaps' at the LOCAL copy. Yoast emits it as a +# protocol-relative absolute URL (`href="///wp-content/.../main-sitemap.xsl"`). +# Left alone, the browser fetches the XSL cross-origin from the live site, the XSLT +# transform is blocked, and the sitemap renders as a BLANK page (raw XML is fine in +# view-source — only the styled render breaks). rewrite-paths.py won't fix this: it +# only touches *.html, and its abs-URL rule matches `https?://`, not `//`. +SRC=${ROOT#http*://} # bare domain, e.g. example.com +for f in output/*.xml; do + perl -0pi -e "s{href=\"(?:https?:)?//\Q$SRC\E(/wp-content/plugins/wordpress-seo/css/main-sitemap\.xsl)\"}{href=\"\$1\"}g" "$f" +done ``` ## Phase 2 — One-shot wget diff --git a/wp-static-clone/SKILL.md b/wp-static-clone/SKILL.md index 7432c02..1dff28c 100644 --- a/wp-static-clone/SKILL.md +++ b/wp-static-clone/SKILL.md @@ -133,7 +133,7 @@ These are the things that bit us. Don't repeat them. 4. **WordPress Offload Media plugins** route `/wp-content/uploads/` to R2 / S3 buckets. wget may successfully fetch an image even when later direct access 404s (intermittent or partial bucket sync). Trust your local copy — that's why we scrape and self-host. -5. **Sitemaps and the Yoast XSL aren't linked from HTML.** wget `-p` won't find them. Fetch explicitly in Phase 1. +5. **Sitemaps and the Yoast XSL aren't linked from HTML.** wget `-p` won't find them. Fetch explicitly in Phase 1. And after fetching, **repoint each sitemap's `` at the local copy** — Yoast emits it as a protocol-relative absolute URL (`href="///wp-content/.../main-sitemap.xsl"`). Left alone, the browser fetches it cross-origin from the live site, the XSLT transform is blocked, and the sitemap renders **blank** (view-source shows the XML fine — only the styled render breaks). `rewrite-paths.py` won't catch it: it processes `*.html` only, and its abs-URL rule matches `https?://`, not `//`. Recipe in Phase 1 of `AGENTS.md`. 6. **Filenames with `?ver=...` query strings.** wget keeps these as literal filenames; HTML uses `%3F` encoding. Standard servers (Pages, Netlify, Vercel, `python -m http.server`) URL-decode and serve correctly. Don't try to "clean these up" unless something actually breaks.