From 43bad058c20d0ace2a1555c70e330fb1808185e0 Mon Sep 17 00:00:00 2001 From: Mike Auteri Date: Fri, 11 Sep 2026 23:45:21 -0400 Subject: [PATCH] Leave fragment-only references alone when rewriting URLs A reference like `#section` points within the document that contains it, so there is no origin to migrate. Resolving it against the base URL made it look like a child of the source site, and rewriting it turned an in-page anchor into `/#section` and a bare `#` into `/`. Blocks whose saved markup carries such an href then fail validation after an import. Mirrors WordPress/wordpress-importer#263. Co-Authored-By: Claude Fable 5.1 --- .../DataLiberation/Tests/RewriteUrlsTest.php | 24 +++++++++++++++++++ components/DataLiberation/URL/functions.php | 15 +++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/components/DataLiberation/Tests/RewriteUrlsTest.php b/components/DataLiberation/Tests/RewriteUrlsTest.php index 17aca6d57..3b947432a 100644 --- a/components/DataLiberation/Tests/RewriteUrlsTest.php +++ b/components/DataLiberation/Tests/RewriteUrlsTest.php @@ -213,6 +213,30 @@ public static function provider_test_wp_rewrite_urls() { 'https://🚀-science.com/science', 'https://science.wordpress.org', ), + 'Fragment-only reference in an HTML attribute is left alone' => array( + 'Jump', + 'Jump', + 'https://legacy-blog.com', + 'https://modern-webstore.org', + ), + 'Bare hash in an HTML attribute is left alone' => array( + 'Placeholder', + 'Placeholder', + 'https://legacy-blog.com', + 'https://modern-webstore.org', + ), + 'Fragment-only reference in a block attribute is left alone' => array( + '', + '', + 'https://legacy-blog.com', + 'https://modern-webstore.org', + ), + 'Absolute URL carrying a fragment is still rewritten and keeps its fragment' => array( + 'Deep link', + 'Deep link', + 'https://legacy-blog.com', + 'https://modern-webstore.org', + ), ); } diff --git a/components/DataLiberation/URL/functions.php b/components/DataLiberation/URL/functions.php index fe931ce3d..daecc82d2 100644 --- a/components/DataLiberation/URL/functions.php +++ b/components/DataLiberation/URL/functions.php @@ -70,7 +70,20 @@ function wp_rewrite_urls( $options ) { while ( $p->next_url() ) { $token_type = $p->get_token_type(); $raw_url = $p->get_raw_url(); - $cache_key = $mapping_cache_key . "\0" . $token_type . "\0" . $raw_url; + + /* + * Leave fragment-only references alone. A URL like `#section` points + * within the document that contains it, so there is no origin to + * migrate. Resolving it against the base URL makes it look like a + * child of the site being imported from, and rewriting it then turns + * an in-page anchor into a link somewhere else entirely: + * `#section` becomes `/#section`, and a bare `#` becomes `/`. + */ + if ( is_string( $raw_url ) && 0 === strpos( $raw_url, '#' ) ) { + continue; + } + + $cache_key = $mapping_cache_key . "\0" . $token_type . "\0" . $raw_url; $cached = $rewrite_cache->get( $cache_key ); if ( null !== $cached ) {