feat: add real editor-driven save post mechanism#445
Draft
Conversation
Add `window.editor.savePost()` that delegates to Gutenberg's internal save flow and returns the saved entity to the native host. For new posts (id <= 0), a `__unstableFetch` wrapper captures the server-assigned ID so the editor store can be switched to the created entity via `setEditedPost`, preventing duplicate POST requests on subsequent saves. A pre-save filter (`editor.preSavePost`) calls `hydratePost` to let the native host enrich the entity record (e.g. categories, tags changed in native UI) before the PUT is sent. Meta fields are stripped from the hydrated response to avoid REST API type-validation failures caused by the Foundation↔JSON round-trip. Also adds `hydratePost` bridge method, allows write requests through `filterEndpointsMiddleware`, and wires up `useSyncSaveAvailability` to notify the native host of save-state changes.
Unit tests cover the new savePost bridge method including: - __unstableFetch usage for new posts and setEditedPost with created ID - No setEditedPost call for existing posts - Pre-save filter hydration, meta stripping, and id stripping for new posts - Save error surfacing via didPostSaveRequestFail E2E test verifies the full POST→PUT flow: first save creates (POST), editor store updates to server-assigned ID, second save updates (PUT) to the correct endpoint. Uses X-HTTP-Method-Override header detection since Gutenberg's httpV1Middleware converts PUT to POST.
Add `savePost()` method that calls the JS bridge and decodes the returned entity into `EditorPost`. Introduces `EditorPersistenceDelegate` protocol with `willSavePost` (pre-save hydration), `didSavePost`, and `didFailToSavePost` callbacks. Registers `hydratePost` and `requestLatestContent` WKWebView message handlers for the native↔JS bridge communication.
db4971d to
dab4ab8
Compare
Add `savePost()` method, `EditorSaveListener` interface with pre/post save callbacks, and `hydratePost` / `requestLatestContent` JS interface methods for the Android↔JS bridge. Include `restBase` and `restNamespace` in the GBKit post payload.
…eware filtering
Call finishResolution('getEntityRecord', ...) after receiveEntityRecords in
useEditorSetup so Gutenberg's data layer knows the entity is already resolved.
This eliminates the need for filterEndpointsMiddleware, which previously blocked
the refetch by intercepting GET requests to the post endpoint.
Closes #434
Move the X-HTTP-Method-Override header stripping from a standalone function in api-fetch.js into the existing fetch interceptor wrapper. The interceptor now always wraps window.fetch (even when network logging is disabled) so the CORS fix applies universally.
89fb199 to
7c3310a
Compare
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.
Summary
Adds a
window.editor.savePost()bridge method that delegates to Gutenberg's nativesavePost()action, replacing the previous fake save approach. This enables real POST/PUT persistence through the WordPress REST API from both iOS and Android host apps.savePost()captures the server-assigned ID for new posts via__unstableFetch, records it as an entity edit (avoidingsetEditedPostwhich causes title loss), and returns the saved entity to the native hosteditor.preSavePostfilter round-trips the entity through the native host so it can inject metadata (categories, tags, featured media) before the REST request is sent. Meta fields are stripped to avoid Foundation↔JSON type coercion issues (e.g. integer meta returned as doubles)globalThis.fetchto undohttpV1Middleware'sX-HTTP-Method-Overrideheader, which isn't in the CORS allow-list for WordPress.com. The middleware stays in the chain for servers that need it — the fix only strips the header at the network boundaryuseSyncSaveAvailabilityhook dispatches bridge events so native hosts can enable/disable the save button based on editor statesavePostcallbacks, save availability listeners, and latest-post/content providers in the demo appsTest plan
npx vitest run src/components/editor/test/use-host-bridge.test.jsx— 26 tests pass