Skip to content

fix(android): include restBase and restNamespace in GBKit post payload#432

Merged
dcalhoun merged 4 commits intotrunkfrom
fix/android-rest-base-namespace-payload
Apr 8, 2026
Merged

fix(android): include restBase and restNamespace in GBKit post payload#432
dcalhoun merged 4 commits intotrunkfrom
fix/android-rest-base-namespace-payload

Conversation

@dcalhoun
Copy link
Copy Markdown
Member

@dcalhoun dcalhoun commented Apr 7, 2026

What?

  • Adds restBase and restNamespace to the Android GBKitGlobal.Post payload, populated from the configured post type via a small heuristic (postposts, pagepages, custom types pluralized).
  • Hardens filterEndpointsMiddleware so it falls back to wp/v2/posts when those fields are missing from window.GBKit.post, matching the contract getPost() already provides.

Why?

filterEndpointsMiddleware (in src/utils/api-fetch.js) failed blocking server fetches for the post being edited. This resulted in the WordPress core data fetched via GET /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 to Post, populates them in fromConfiguration, and introduces a private restBaseFor(postType) helper with the pluralization heuristic.
  • src/utils/bridge.js — extracts a new exported POST_FALLBACKS constant so getPost() and the middleware share one source of truth for default values.
  • src/utils/api-fetch.jsfilterEndpointsMiddleware now bails out only when there is no post or no post id, and falls back to POST_FALLBACKS for restBase/restNamespace.
  • src/utils/api-fetch.test.js — switches the bridge mock to a partial mock so POST_FALLBACKS survives, 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 — asserts restBase/restNamespace for post, 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.

  1. Apply a manual patch with test title/content and valid post ID from a site.
    diff --git a/android/app/src/main/java/com/example/gutenbergkit/SitePreparationViewModel.kt b/android/app/src/main/java/com/example/gutenbergkit/SitePreparationViewModel.kt
    index bb1a6c81..35a8dcf3 100644
    --- a/android/app/src/main/java/com/example/gutenbergkit/SitePreparationViewModel.kt
    +++ b/android/app/src/main/java/com/example/gutenbergkit/SitePreparationViewModel.kt
    @@ -231,6 +231,7 @@ class SitePreparationViewModel(
                arrayOf()
            }
    
    +        val postId: UInt = 0000u;
            return EditorConfiguration.builder(
                siteURL = config.siteUrl,
                siteApiRoot = siteApiRoot,
    @@ -241,8 +242,9 @@ class SitePreparationViewModel(
                .setSiteApiNamespace(siteApiNamespace)
                .setNamespaceExcludedPaths(arrayOf())
                .setAuthHeader(config.authHeader)
    -            .setTitle("")
    -            .setContent("")
    +            .setPostId(postId)
    +            .setTitle("Test")
    +            .setContent("<!-- wp:paragraph --><p>Hello</p><!-- /wp:paragraph -->")
                .setHideTitle(false)
                .setCookies(emptyMap())
                .setEnableNetworkLogging(true)
    
  2. Replace 0000 with a valid post ID for your test site.
  3. Open the editor for your test site via the Start button.
  4. Wait a few seconds for initial fetches to complete.
  5. Verify the editor title and content is not cleared.

Accessibility Testing Instructions

No UI changes; not applicable.

Screenshots or screencast

N/A — bug fix with no visible UI changes.

dcalhoun and others added 3 commits April 7, 2026 17:49
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.
@github-actions github-actions bot added the [Type] Bug An existing feature does not function as intended label Apr 7, 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"
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@dcalhoun dcalhoun marked this pull request as ready for review April 8, 2026 01:51
@dcalhoun dcalhoun requested a review from jkmassel April 8, 2026 01:51
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.
@dcalhoun dcalhoun force-pushed the fix/android-rest-base-namespace-payload branch from 8bc5ea4 to 944fbfc Compare April 8, 2026 14:00
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
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

@jkmassel jkmassel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes the immediate problem and we'll revisit the further improvements

@dcalhoun dcalhoun merged commit eaba3dd into trunk Apr 8, 2026
16 checks passed
@dcalhoun dcalhoun deleted the fix/android-rest-base-namespace-payload branch April 8, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants