Phase 2: Capture Suggest-mode edits as an in-memory overlay#77404
Draft
adamsilverstein wants to merge 2 commits intosuggest-mode-phase-1from
Draft
Phase 2: Capture Suggest-mode edits as an in-memory overlay#77404adamsilverstein wants to merge 2 commits intosuggest-mode-phase-1from
adamsilverstein wants to merge 2 commits intosuggest-mode-phase-1from
Conversation
This was referenced Apr 16, 2026
|
Size Change: +2.22 kB (+0.03%) Total Size: 7.75 MB 📦 View Changed
ℹ️ View Unchanged
|
edf102e to
fa199f5
Compare
f78a787 to
3ca48fe
Compare
8043af8 to
b1af20a
Compare
3ca48fe to
4bdfdda
Compare
Add the suggestion-overlay subsystem that powers the `suggest` editor
intent added in the previous step. An `editor.BlockEdit` filter wraps
every block; when the intent is `suggest` it diverts `setAttributes`
into an overlay reducer keyed by `clientId` and passes merged
`{ ...real, ...overlay }` attributes into the block for rendering.
The block-editor store is never touched, so autosave, undo, and RTC
sync stay at the real baseline.
A `SuggestionCommitBar` exposes Submit / Discard controls in the
block toolbar when the selected block has a pending overlay. Submit
creates a note comment carrying a versioned `_wp_suggestion` JSON
payload (`blockName`, `baseRevision`, `operations`) via REST; discard
clears the overlay. The `applySuggestion` / `rejectSuggestion` hooks
are stubbed behind the same provider interface so Phase 3 can plug in
without UI changes, and a future Yjs AttributionManager-backed
provider can drop in with the same shape.
PHP-side registers `_wp_suggestion` and `_wp_suggestion_status`
comment meta with REST exposure. Both require `edit_comment`; no new
routes are added.
Refs #73411
b1af20a to
6ae1fa6
Compare
Move the baseline-captured signal from a local ref onto the reducer's entry map so Submit/Discard/orphan-prune cleanly resets it — a second edit after the overlay is cleared now reliably captures a new baseline instead of silently no-op'ing on the stale ref. Split the HOC into an outer Suggest-mode check and an inner SuggestingBlockEdit component. The overlay's context lookup, refs, and merge memo only run when intent === suggest; in Edit/View the wrapper executes a single useSelect and returns the original BlockEdit untouched, removing measurable per-render overhead on timing-sensitive e2e specs running on shards 4/5. Add unit coverage for View-intent pass-through and for re-capturing a baseline after the overlay is cleared.
6ae1fa6 to
b09c96d
Compare
|
Flaky tests detected in b09c96d. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/24542664950
|
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.
Overview
This is one of 5 stacked PRs implementing Suggest mode for the WordPress editor — a Google Docs–style workflow where reviewers can propose changes that the post author can Accept or Reject. Tracked in #73411, with design direction from #73410 and jasmussen's mockups.
Architecture & Yjs readiness
The eventual long-term storage primitive for suggestions is the Yjs
AttributionManagerarriving in Yjs v14 (PR #77005), which attributes CRDT document changes to specific clients — exactly what suggested edits need. However, Yjs v14 is pre-release with an unstable API, and even with Yjs, server-side persistence is still needed for non-RTC users.Rather than block on Yjs, this series builds the full feature now with a comment-meta backend behind a swappable
SuggestionsProviderinterface shaped to match Yjs attribution semantics:attribute-set) — not HTML diffs — so they map directly to whatAttributionManagerwould emit.createSuggestion,updateSuggestion,deleteSuggestion,applySuggestion,rejectSuggestion. Today's implementation reads/writes comment meta; a futureyjs-provider.jscan drop in with the same methods.When #77005 stabilizes, the migration is: implement
yjs-provider.jsagainst the same interface, useAttributionManagerfor live-session attribution, and keep comment-meta as the fallback for users without RTC.The 5 phases
editorIntentpreference (edit/suggest/view), a mode selector in the Options kebab, read-only gating for View intent, keyboard shortcuts, and a "You're suggesting/editing/viewing" snackbar on mode change.editor.BlockEditfilter divertssetAttributesinto a React context so the user sees their edit live but the block-editor store stays at the baseline. The HOC is split so non-Suggest intents only run a singleuseSelect._wp_suggestioncomment meta, theSuggestionsProviderinterface (create/update/delete/apply/reject), and the accept/reject icon buttons in the notes sidebar.This PR (Phase 2)
Builds the in-memory suggestion overlay:
SuggestionOverlayProvider— React context that stores pending attribute changes perclientId, plus a baseline snapshot captured on the first edit. The block-editor store is never written.withSuggestionOverlayHOC — registered as aneditor.BlockEditfilter. The HOC is split into an outeruseSelectwrapper and an innerSuggestingBlockEditcomponent: non-Suggest intents run a singleuseSelectand return the wrappedBlockEdituntouched, so the overlay's context lookup, refs, and merge memo add no measurable overhead on timing-sensitive e2e specs.{ ...realAttributes, ...overlayAttributes }for rendering, so the user sees their in-progress change live. Object-valued attributes (style,metadata) are one-level merged so untouched fields survive.What's NOT in this PR
_wp_suggestioncomment meta and REST plumbing (Phase 3)Phase 2 test plan
wp.data.select('core/editor').getEditedPostContent()and confirm the serialized content does not include your suggested textnpm run test:unit -- packages/editor/src/components/suggestion-mode/test/overlay-context.jsnpm run test:unit -- packages/editor/src/components/suggestion-mode/test/with-suggestion-overlay.js🗺️ PR Stack Navigation
_wp_suggestionmeta, provider, sidebar actions📋 Tracking issue: #73411