fix: build REST URLs for sites using plain permalinks - #573
Draft
dcalhoun wants to merge 2 commits into
Draft
Conversation
Sites with plain permalinks have no path-based REST root, so WordPress advertises the query form `https://site/?rest_route=/` instead. Appending an endpoint to that root landed the path before the query, malforming every native REST URL. Teach `URL.appending(rawPath:)` to append the endpoint to the query value when the root carries one, merging the path's own query string with `&`. This mirrors `@wordpress/api-fetch`'s root URL middleware, which the web layer already uses, so native and web requests resolve identically. Also route `editorAssetsUrl` through the same primitive instead of `URL.appending(path:)`, which had the same defect. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sites with plain permalinks have no path-based REST root, so WordPress
advertises the query form `https://site/?rest_route=/` instead. The root
was normalized with `trimEnd('/')` and concatenated with the endpoint,
which mangled the route value and emitted a second `?` for endpoints that
carry their own query string.
Add `String.appendingRestPath`, which appends the endpoint to the query
value when the root carries one and merges the path's query string with
`&`. This mirrors `@wordpress/api-fetch`'s root URL middleware, which the
web layer already uses, so native and web requests resolve identically.
Route the repository and both asset library URL builders through it, and
align namespace insertion with iOS, which also namespaces two-segment
paths.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Teaches the native REST URL builders to address sites that use plain permalinks, where the only REST root is the query form
https://site/?rest_route=/.Stacks on #572 (the wordpress-rs 0.6.0 bump), so it targets
build/bump-wordpress-rs-0.6.0rather thantrunk.Fixes #563.
Why?
A site with plain permalinks has no path-based REST root —
/wp-json/depends on the rewrite rules that plain permalinks disable, so WordPress advertises?rest_route=/instead. Both hosts hand that root straight to GutenbergKit (EditorConfiguration+Blog.swifton iOS,GutenbergKitSettingsBuilder.kton Android) after discovering it from the site'shttps://api.w.org/Link header, so it reaches every native URL builder verbatim.Those builders appended the endpoint to the path, which produced malformed URLs for every native endpoint — editor settings, active theme, site settings, post types, the post itself, and editor assets.
Worth noting the iOS failure was silent, not a 404. Verified against a live plain-permalink site:
The trailing
?rest_route=/routes to the API root and the path is ignored, so the editor received the wrong resource and failed later at decode time with no indication the URL was wrong. On Android the two query-carrying endpoints did 404 outright.WP.com sites are unaffected — they use the path-based
public-api.wordpress.com/proxy.How?
Both platforms mirror the algorithm in
@wordpress/api-fetch's root URL middleware, which the web layer already uses (and which is why JS requests work today on these sites): when the root carries a query, append the endpoint to it and merge the path's own query string with&.URL.appending(rawPath:)(Foundation+Extensions.swift), the primitive every iOS REST URL bottoms out in.EditorAssetLibraryused stockURL.appending(path:), which had the same defect, so it now routes through the same primitive.String.appendingRestPath(StringExtensions.kt), replacing thetrimEnd('/')-plus-concat inRESTAPIRepositoryand both asset libraries. Namespace insertion is split intonamespacedPath()so the path transform and the root join are separate concerns.The fix lives in the join primitive rather than in namespace insertion deliberately: two of the three Android call sites (and the iOS asset library) build their URLs without going through namespacing, so they would otherwise stay broken.
Also aligns a pre-existing platform divergence in namespace insertion — iOS namespaced two-segment paths (
components.count >= 2) where Android bailed (parts.size < 3); Android now matches iOS.Note for #357 / #561
#357 introduces
WordPressRESTURL.namespaced(iOS) andRestUrlBuilder.namespaced(Android). This branch and that one merge without textual conflict, but two things need coordinating — details in a comment on #357:WordPressRESTURL.namespacedalready callsappending(rawPath:)on every path), but Android'sRestUrlBuilder.namespacedneeds to delegate its join toappendingRestPath, or a clean merge silently reverts the Android fix.mediaEndpointURLneeds&merging on both platforms before it works on a query root.Testing Instructions
Requires a self-hosted site set to Settings ▸ Permalinks ▸ Plain. Confirm it advertises the query-form root first:
The
rel="https://api.w.org/"value should contain?rest_route=/rather than/wp-json/.?rest_route=form.Check that:
/wp/v2/posts/{id})./wp-block-editor/v1/settingsand/wp/v2/themes). This is the highest-value check: the themes endpoint is the only one carrying its own query string, so it's what exercises the?→&merge./wp/v2/types).Enable Network Logging in the site-preparation screen to inspect the request URLs directly — they should read
?rest_route=/wp/v2/…, not/wp/v2/…?rest_route=/.Also confirm no regression on a pretty-permalink site and a WP.com site.
Accessibility Testing Instructions
N/A — no user interface changes.