Repository navigation
Conversation
|
Flagging the red checks so they don't get misread as fallout from this change: they are pre-existing and unrelated to the diff. Every failing job dies in
Composer blocks advisory-affected packages by default now, and the pinned PHPUnit range is entirely within that advisory, so dependency resolution fails outright.
The failing job names line up too ( Meanwhile everything that did manage to install and run on this PR passed: all three E2E shards, plus Happy to open a separate PR unblocking CI if that would help. The options are roughly: allow the advisory through |
It looks like 582b8a3 / #264 fixed this within the workflow file, so merging/rebasing should fix those failures. However, it was not fixed within the TIL about the shift from
I'm not that familiar with the Also outside of the scope for this PR, but it would be really nice for the toolkit to be pinned as a dependency. It would make updating and managing that much easier. |
A reference like `#section` points within the document that contains it. It has no host and no path, so there is no origin to migrate. wp_rewrite_urls() resolved it against the base URL first, which made it look like a child of the site being imported from, and it was then rewritten against the new home: #section becomes /#section #add-to-calendar becomes /#add-to-calendar # becomes / (fragment dropped entirely) An in-page anchor therefore turns into a link to a different page, and blocks whose saved markup contains such an href fail validation after an import because the serialized attribute no longer matches what the block expects. Sites have been working around this by disabling URL rewriting altogether via the wp_import_options filter, which is a heavy price for one class of URL. Skips those references before the mapping is consulted. The guard reads the raw URL rather than the parsed one, because parsing is what loses the distinction: by the time a fragment has been resolved against the base it is indistinguishable from a same-site link. Scoped deliberately to references that are *only* a fragment. A URL that carries a fragment alongside a host or path is still rewritten, and still keeps its fragment. Adds regression tests covering fragment-only hrefs in markup and in block attributes, plus the two cases that must keep working. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
05967e1 to
8877cb1
Compare
|
Rebased on master to pick up #264, so the checks are running against the workflow fix now. The toolkit half is up at WordPress/php-toolkit#320. Once that lands I'll refresh this PR from it so the vendored copy matches. I'll open the |
The importer only offers URL rewriting on 6.7 and later, where WP_HTML_Tag_Processor::set_modifiable_text() exists, and switches the option off below that. The tests called the rewriter directly, so on older WordPress they errored inside the tag processor instead of skipping where the importer itself would not rewrite. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
The |
The vendored URL parser calls mb_str_split(), which PHP added in 7.4, and its parse() swallows the resulting Error, so on 7.2 and 7.3 wp_rewrite_urls() returns its input untouched. The two control tests that expect an absolute URL to be rewritten caught that; the fragment cases only passed there because nothing was rewritten at all. Skip the whole set where the parser cannot run rather than assert on a no-op. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
zaerl
left a comment
There was a problem hiding this comment.
The PR is ok, thanks for it. Just just change the domain names.
| const FROM = 'https://legacy-blog.com'; | ||
| const TO = 'https://modern-webstore.org'; |
There was a problem hiding this comment.
Please don't use real domain names in tests. example.com and similar is ok.
There was a problem hiding this comment.
Switched to old.example.com and new.example.org.
akirk
left a comment
There was a problem hiding this comment.
Thanks for your contribution! I agree this is a bug that should be fixed but in my opinion the logic that detects the fragment-only URL belongs in PHP toolkit.
| $raw_url = $p->get_raw_url(); | ||
| if ( is_string( $raw_url ) && 0 === strpos( $raw_url, '#' ) ) { |
There was a problem hiding this comment.
I think we should not analyze the raw URL here. What about this (after adding it to WordPress/php-toolkit#320):
| $raw_url = $p->get_raw_url(); | |
| if ( is_string( $raw_url ) && 0 === strpos( $raw_url, '#' ) ) { | |
| if ( $p->is_fragment_only_reference() ) { |
There was a problem hiding this comment.
Done. It uses $p->is_fragment_only_reference() from WordPress/php-toolkit#320, mirrored into the vendored copy.
Mirrors BlockMarkupUrlProcessor::is_fragment_only_reference() from WordPress/php-toolkit#320 into the vendored copy and calls it from wp_rewrite_urls(). The tests use example.com domains and cover a fragment with leading whitespace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

The problem
A reference like
#sectionpoints within the document that contains it. It has no host and no path, so there is no origin to migrate.wp_rewrite_urls()resolves every URL against the base URL before consulting the mapping. For a fragment-only reference that resolution produceshttps://old-site.com/current-page#section, which then matchesis_child_url_of()and gets rewritten against the new home:<a href="#section"><a href="/#section"><a href="#add-to-calendar"><a href="/#add-to-calendar"><a href="#"><a href="/">The last one is the worst: the fragment is dropped entirely, so an in-page anchor becomes a link to the site root.
Why it matters
Beyond the broken links, this breaks block validation. Any block whose saved markup contains a fragment-only
href(accordions, tab and anchor navigation, "jump to" links, and blocks that use#as a JavaScript-handled placeholder) no longer matches itssave()output after an import, and the editor shows "This block contains unexpected or invalid content."The workaround people land on is disabling URL rewriting altogether:
That is a heavy price for one class of URL, and it gives up the migration for every genuine link in the content.
The fix
Skip fragment-only references before the mapping is consulted.
The guard deliberately reads
get_raw_url()rather than the parsed URL, because parsing is what destroys the distinction: once#sectionhas been resolved against the base it is indistinguishable from an ordinary same-site link, which is exactly why the current code rewrites it.Scoped to references that are only a fragment. A URL carrying a fragment alongside a host or path still rewrites, and still keeps its fragment:
Tests
phpunit/tests/rewrite-urls.phpcovers fragment-only hrefs in both markup and block attributes, plus the two cases that must keep working (absolute URL, absolute URL carrying a fragment).Verified they fail before the change and pass after:
The two controls passing in both columns is the part that matters: the guard does not over-correct.
Notes
components/DataLiberation/URL/functions.php), vendored here undersrc/php-toolkit/. Happy to open the matching PR there so the two do not diverge, just say the word.<a href="?filter=all">currently becomes<a href="/?filter=all">, which likewise moves the link from the current page to the site root. I left it alone to keep this change to the reported behavior, but it may be worth the same treatment.phpcs --standard=phpcs.xml.distis clean on both files. I could not run the PHPUnit suite locally (the pinned PHPUnit predates my PHP version, as CONTRIBUTING.md notes), so those run on CI.