Content Guidelines AI: restore compatibility with the Gutenberg 23.6 Guidelines page#50658
Content Guidelines AI: restore compatibility with the Gutenberg 23.6 Guidelines page#50658aagam-shah wants to merge 2 commits into
Conversation
Gutenberg 23.6 dissolved the Guidelines singleton into per-scope wp_knowledge rows (GB#79263) and deleted the core/guidelines data store the integration consumed for section drafts. Every injected component that selected or dispatched on that store now crashes its React root, so none of the AI generate/accept UI renders on the new Guidelines page. Since the page keeps its drafts in React component state only, the DOM textareas are the one observable source: a new lib/drafts.js snapshots them and notifies subscribers from a capture-phase input listener plus a MutationObserver that re-checks the watched values on DOM churn (catching value writes Gutenberg makes without input events, e.g. Clear guidelines). Accepting a section suggestion now writes the textarea through the native setter so Gutenberg's own onChange keeps its state in sync, and keeps the suggestion when the textarea is missing rather than silently dropping accepted text. Generate handlers snapshot drafts at click time; render-time hook values only drive the labels. The block modal's Generate/Improve label now keys off the live modal textarea (which opens prefilled with the saved guideline) instead of the deleted getBlockGuideline selector — matching what was already sent to the AI endpoint as existing content. Verified end-to-end against the new page on a local Gutenberg wp-env: injection, label reactivity, generate/diff/accept, Gutenberg save and clear, and the block modal flows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! Jetpack plugin: No scheduled milestone found for this plugin. If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack. |
There was a problem hiding this comment.
Pull request overview
This PR restores the Jetpack Content Guidelines AI UI on the Gutenberg 23.6+ Guidelines page by removing reliance on the deleted core/guidelines data store and instead reading/updating guideline drafts directly from the page’s DOM textareas (with reactive subscriptions for button labels and click-time snapshotting for API calls).
Changes:
- Introduce a DOM draft tracking layer (
lib/drafts.js) and reactive hooks (hooks/use-drafts.js) built onuseSyncExternalStoreto keep “Generate/Improve” labels in sync with live textarea content. - Update generate/accept flows to snapshot draft content at click time and, on accept, write through the native textarea setter + bubbling
inputevent so Gutenberg’s internal state stays consistent. - Add Jest coverage for the new draft layer and include
_inc/content-guidelines-ai/in the client Jest config roots/coverage.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| projects/plugins/jetpack/tests/jest.config.client.js | Expands Jest roots and coverage collection to include Content Guidelines AI client code. |
| projects/plugins/jetpack/changelog/fix-content-guidelines-ai-gb-store-removal | Adds a compat changelog entry describing the Gutenberg 23.6 compatibility fix. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/lib/drafts.js | Implements DOM-based draft reads plus input/MO-driven subscription notifications. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/hooks/use-drafts.js | Adds useSyncExternalStore hooks to consume the DOM draft layer in UI components. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/lib/dom.js | Adds section-suggestion acceptance that writes via native setter + input event. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/lib/inject.js | Starts draft tracking on injection and centralizes modal textarea lookup. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/hooks/use-generate-all.js | Removes store reads and snapshots all section drafts from DOM at click time. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/constants.js | Removes the core/guidelines store constant. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/components/suggestion-actions.jsx | Accept now writes into the textarea (DOM) rather than dispatching to a removed store. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/components/suggest-all-button.jsx | Button label now reflects DOM draft emptiness via useAllSectionsEmpty. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/components/section-generate-button.jsx | Uses useSectionDraft for labels and snapshots DOM draft on click for requests/tracks. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/components/block-suggestion-buttons.jsx | Uses modal textarea draft for labels and click-time snapshots, matching new page behavior. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/components/block-suggestion-actions.jsx | Uses shared modal textarea getter for consistent DOM access. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/test/fixtures/index.js | Adds DOM fixtures to mimic the Guidelines page and block modal structures in tests. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/test/drafts.test.js | Adds unit tests for draft reads, subscriptions, input events, and mutation-driven reactivity. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/test/use-drafts.test.jsx | Adds hook-level tests verifying reactive draft reads for sections and the block modal. |
| projects/plugins/jetpack/_inc/content-guidelines-ai/test/dom.test.js | Adds tests for native-setter textarea writes and section acceptance behavior. |
Code Coverage Summary20 files are newly checked for coverage. Only the first 5 are listed here.
Full summary · PHP report · JS report If appropriate, add one of these labels to override the failing coverage check:
Covered by non-unit tests
|
Performance pass over the draft tracker: - Funnel the input listener and the MutationObserver through one checkAndNotify that compares the watched values before notifying, so typing in unrelated fields (block combobox, admin search) and non-draft DOM churn cost a single ~11us read pass with no subscriber fan-out. - Compare the watched values element-wise instead of joining them into one string; guideline text can reach 5000 chars per section, and the join copied up to ~25KB per check. - Make the label hooks return booleans (useSectionHasDraft, useBlockHasDraft, useAllSectionsEmpty was already boolean): the consumers only choose Generate-vs-Improve labels, so components now re-render at the empty/non-empty boundary instead of every keystroke. Measured on the wp-env Guidelines page: a value-changing keystroke costs the bundle ~39us end-to-end (listener + compare + boolean snapshots); unrelated-field keystrokes ~14us with zero fan-out; observer checks on DOM churn ~11us. Gutenberg's own controlled-form re-render (~1.5ms per keystroke) dominates and is unchanged by this bundle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes N/A — compatibility fix for a Gutenberg refactor.
Proposed changes
Gutenberg 23.6 dissolved the Guidelines singleton into per-scope
wp_knowledgerows (WordPress/gutenberg#79263) and deleted thecore/guidelinesdata store. Five files in the Content Guidelines AI integration selected or dispatched on that store, so on the new Guidelines page every injected component crashes its React root and none of the AI UI renders. The page now keeps section drafts in React component state only, so the DOM textareas are the one place drafts are observable from our bundle.lib/drafts.js: snapshot-style draft reads (readSectionDraft,readAllSectionDrafts,areAllSectionDraftsEmpty,getSectionTextarea,getBlockModalTextarea) plus a subscription layer fed by a capture-phaseinputlistener and a MutationObserver that re-checks the watched values on DOM churn — catching value writes Gutenberg makes without input events (e.g. Clear guidelines resetting the form), while skipping notifications when no draft actually changed.hooks/use-drafts.js(useSectionDraft,useAllSectionsEmpty,useBlockDraft) built onuseSyncExternalStore, replacing thegetGuideline/getBlockGuidelineselectors for the Generate ↔ Improve labels.inputevent so Gutenberg's ownonChangeupdates its draft state (same pattern the block modal already used); the user then saves via Gutenberg's Save button as before. If the textarea can't be found, the suggestion is kept instead of being silently discarded.setGuideline/STORE_NAMEusage is removed everywhere.inputlistener, MutationObserver) funnel through a single value-compare gate, so unrelated typing and non-draft DOM churn cause no subscriber fan-out; the label hooks return booleans so buttons re-render only at the empty/non-empty boundary. Measured on the wp-env page: ~39µs per value-changing keystroke for the whole bundle path, ~14µs for unrelated-field keystrokes, ~11µs per DOM-churn observer check (Gutenberg's own form re-render, ~1.5ms/keystroke, dominates and is unchanged)._inc/content-guidelines-ai/in the client jest config roots.Works on both the old and new Guidelines pages: the DOM anchors used here (
.guidelines__list-item[data-slug], form/textarea structure,.block-guideline-modal) are unchanged between the pre- and post-refactor Gutenberg, so rollout order doesn't matter.Related product discussion/links
Does this pull request change what data or activity we track or use?
No new tracking. Existing
jetpack_content_guidelines_*events unchanged; theaction(generate/improve) property for block-modal events is now derived from the live modal textarea instead of the deleted store selector.Testing instructions
Unit tests:
cd projects/plugins/jetpack && pnpm exec jest --config=tests/jest.config.client.js _inc/content-guidelines-aiManual (needs a Gutenberg checkout at 23.6+, e.g. trunk, in wp-env, since wpcom still runs the old page):
npm run wp-env start, enable the "Guidelines" experiment (Settings → Gutenberg → Experiments), then open Settings → Guidelines and confirmwp.data.select( 'core/guidelines' )isundefinedin the console — this is the environment where trunk Jetpack crashes.content-guidelines-aibundle on that page (jetpack-beta on a test site once wpcom ships the new GB, or a dev bundle in the console).🤖 Generated with Claude Code