fix(android): include restBase and restNamespace in GBKit post payload#432
Merged
fix(android): include restBase and restNamespace in GBKit post payload#432
Conversation
The api-fetch filterEndpointsMiddleware blocks server fetches for the
post being edited (preventing them from overwriting local edits with
stale or context-mismatched data). The middleware bails out early when
either restBase or restNamespace is missing from window.GBKit.post:
if ( id === undefined || ! restNamespace || ! restBase ) {
return next( options ); // lets the request through
}
iOS already populates these from EditorConfiguration.postType
(PostTypeDetails struct), but Android's GBKitGlobal.Post only had
{ id, type, status, title, content }. As a result, when the editor
mounted with an existing post ID, WordPress core data fetched the
post via GET /wp/v2/posts/{id} unfiltered, and the response (without
context=edit) overwrote the title and content set from the native
host with empty values — causing the editor to briefly show the
loaded post before clearing it.
Adds restBase and restNamespace fields to GBKitGlobal.Post and derives
them from the postType slug ("post" → "posts", "page" → "pages",
custom types pluralized).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds coverage for the restBase/restNamespace fields recently added to GBKitGlobal.Post, including the heuristic pluralization for custom post types.
The middleware previously bailed out when window.GBKit.post was missing
restBase or restNamespace, letting the editor's GET /wp/v2/posts/{id}
request through unfiltered. The response (without context=edit) then
clobbered the host-provided title and content.
Apply the same fallback contract that getPost() already uses
('posts' / 'wp/v2'), centralized in a new POST_FALLBACKS export so
both consumers stay in sync. Hosts that omit those fields now get the
filter applied with sensible defaults instead of silently slipping past.
dcalhoun
commented
Apr 8, 2026
Comment on lines
+136
to
+146
| /** | ||
| * Maps a post type slug to its WordPress REST API base path. | ||
| * | ||
| * Defaults to pluralizing the slug for unknown types (e.g., `product` → `products`), | ||
| * which matches the WordPress convention for most post types. | ||
| */ | ||
| private fun restBaseFor(postType: String): String = when (postType) { | ||
| "post" -> "posts" | ||
| "page" -> "pages" | ||
| else -> if (postType.endsWith("s")) postType else "${postType}s" | ||
| } |
Member
Author
There was a problem hiding this comment.
This will be removed and replaced with fetching of PostTypeDetails in a future PR focused on editing existing posts (and align with iOS). In the interim, this ensures Android correctly sets the restBase value for posts and pages.
Captures a @todo explaining that this middleware could likely be removed in favor of properly seeding entity content into the store on initialization, and links to the historical commit that added it.
8bc5ea4 to
944fbfc
Compare
dcalhoun
commented
Apr 8, 2026
Comment on lines
+115
to
+125
| * @todo Properly seed the post entity and remove this middleware. | ||
| * | ||
| * This was added to prevent re-fetching entity content provided by the native | ||
| * host app, which can lead to content loss. However, we can likely avoid the | ||
| * need for this middleware by ensuring we properly seed the entity content into | ||
| * the store on initialization. | ||
| * | ||
| * This requires hoisting the relevant logic from `useEditorSetup` to occur | ||
| * before we render the editor, and invoking `finishResolution`. | ||
| * | ||
| * See: https://github.com/wordpress-mobile/GutenbergKit/commit/c9b4fc9978a3760ba97f3f5d4359c2bc2155bb80 |
Member
Author
There was a problem hiding this comment.
In the future, we can improve entity seeding and negate the need this middleware that manually disables the entity fetch requests. See c9b4fc9 as a proof-of-concept.
This was referenced Apr 8, 2026
jkmassel
approved these changes
Apr 8, 2026
Contributor
jkmassel
left a comment
There was a problem hiding this comment.
This fixes the immediate problem and we'll revisit the further improvements
This was referenced Apr 8, 2026
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?
restBaseandrestNamespaceto the AndroidGBKitGlobal.Postpayload, populated from the configured post type via a small heuristic (post→posts,page→pages, custom types pluralized).filterEndpointsMiddlewareso it falls back towp/v2/postswhen those fields are missing fromwindow.GBKit.post, matching the contractgetPost()already provides.Why?
filterEndpointsMiddleware(insrc/utils/api-fetch.js) failed blocking server fetches for the post being edited. This resulted in the WordPress core data fetched viaGET /wp/v2/posts/{id}clearing the title and content set from the native host.iOS already populates these fields from
EditorConfiguration.postType(PostTypeDetails). This PR brings Android in line and adds a defensive fallback in the JS middleware so any host that omits the fields still gets the filter applied.How?
android/Gutenberg/src/main/java/org/wordpress/gutenberg/model/GBKitGlobal.kt— adds the two new fields toPost, populates them infromConfiguration, and introduces a privaterestBaseFor(postType)helper with the pluralization heuristic.src/utils/bridge.js— extracts a new exportedPOST_FALLBACKSconstant sogetPost()and the middleware share one source of truth for default values.src/utils/api-fetch.js—filterEndpointsMiddlewarenow bails out only when there is no post or no post id, and falls back toPOST_FALLBACKSforrestBase/restNamespace.src/utils/api-fetch.test.js— switches the bridge mock to a partial mock soPOST_FALLBACKSsurvives, and adds four new cases covering the filter with/without explicit fields and the bail-out paths.android/Gutenberg/src/test/java/org/wordpress/gutenberg/model/GBKitGlobalTest.kt— assertsrestBase/restNamespaceforpost,page, and a custom post type.Testing Instructions
Since the Android demo app cannot yet edit existing posts, a manual patch is required to verify the fix end-to-end.
0000with a valid post ID for your test site.Accessibility Testing Instructions
No UI changes; not applicable.
Screenshots or screencast
N/A — bug fix with no visible UI changes.