Skip to content

Admin UI: move EntitiesSavedStates out of the editor into @wordpress/admin-ui - #80074

Closed
enejb wants to merge 2 commits into
WordPress:trunkfrom
enejb:try/boot-admin-ui
Closed

Admin UI: move EntitiesSavedStates out of the editor into @wordpress/admin-ui#80074
enejb wants to merge 2 commits into
WordPress:trunkfrom
enejb:try/boot-admin-ui

Conversation

@enejb

@enejb enejb commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What?

Move the entity-save "review changes" UI (EntitiesSavedStates) out of @wordpress/editor and into @wordpress/admin-ui, so @wordpress/boot can render it without loading the editor. @wordpress/editor — and its heavy @wordpress/block-library / @wordpress/media-utils dependencies — are no longer part of boot's dependency graph; the editor loads only when actually editing (the canvas loads it).

This is an alternative to #71948 and to the earlier @wordpress/core-data-ui approach (#80022), following review feedback to reuse the existing @wordpress/admin-ui package instead of introducing a new one.

Why?

Follow-up to #79913. Boot's always-mounted save UI statically imported EntitiesSavedStates from @wordpress/editor. Because a classic-script import lands in a script module's eager dependencies (static or dynamic), this forced @wordpress/editor and everything it pulls in — most significantly @wordpress/block-library (all core blocks) and @wordpress/media-utils — to load on every boot-powered view, including dashboard/list views that never open the editor.

How?

  • @wordpress/admin-ui gains EntitiesSavedStates, EntitiesSavedStatesExtensible, and useEntitiesSavedStatesIsDirty, moved from @wordpress/editor. They are regular exports — admin-ui is a bundled package, so per the repo guidance it avoids exposing/using private APIs. The component's styles ship through admin-ui's build-style, which @wordpress/editor and @wordpress/boot pull in via @use "@wordpress/admin-ui/build-style/style.css".
  • saveDirtyEntities is promoted to a public @wordpress/core-data action (it was a private @wordpress/editor store action). This lets the bundled admin-ui component trigger a save without reaching for private APIs. The private core/editor saveDirtyEntities action is retained as a thin backwards-compatible wrapper delegating to it.
  • @wordpress/editor re-exports the component and hook unchanged (public), and locks EntitiesSavedStatesExtensible into its own private API for edit-site; its hasPostMetaChanges selector, getTemplateInfo/getTemplatePartIcon utils are unaffected.
  • @wordpress/boot imports EntitiesSavedStates from @wordpress/admin-ui (which it already depends on) and no longer depends on @wordpress/editor.
  • Carries the @wordpress/build companion fix from Boot: lazy-load the editor instead of importing it eagerly in the save UI #79913 (routes enqueue their own classic deps, e.g. wp-viewport).

Verified against the built assets: boot's module depends on @wordpress/admin-ui (bundled inline) and dynamically imports @wordpress/lazy-editor, with no wp-editor / wp-block-library / wp-media-utils in its static graph. The entities-saved-states styles are present in both admin-ui, boot, and editor build-style output.

Backwards compatibility

Intended to be non-breaking across environments (npm, WordPress script handles, editors):

  • @wordpress/editor public API (EntitiesSavedStates, useEntitiesSavedStatesIsDirty, getTemplatePartIcon, getTemplateInfo) and private API (EntitiesSavedStatesExtensible, hasPostMetaChanges) are preserved.
  • The private core/editor saveDirtyEntities action is retained (delegating wrapper); edit-site is unchanged.
  • Behavior is preserved: the block-editor __unstableMarkLastChangeAsPersistent() undo marking and the per-record "Post Meta." indicator are both kept.
  • Adding a public saveDirtyEntities action to @wordpress/core-data is additive.

Testing Instructions

On the experimental Dashboard (Beta) page (gutenberg-dashboard-widgets experiment), which mounts @wordpress/boot:

  1. Enable "Dashboard (Beta)" and open it.
  2. DevTools → Network: confirm editor.min.js, block-library.min.js, and media-utils.min.js are not requested; the page renders. window.wp.editor is undefined; window.wp.viewport is defined.
  3. In the Post/Site editor, make an entity change and Save (button and Cmd/Ctrl+S): the "Review changes" modal opens and saving works, including the per-record "Post Meta." note where applicable.
  4. Regression-check edit-site save button / save panel and the editor publish panels.

🤖 Generated with Claude Code

@github-actions github-actions Bot added [Package] Core data /packages/core-data [Package] Editor /packages/editor labels Jul 9, 2026
…admin-ui

Boot's always-mounted save UI statically imported `EntitiesSavedStates` from
`@wordpress/editor`. Because a classic-script import lands in a script module's
eager dependencies, this forced `@wordpress/editor` — and its heavy
`block-library` / `media-utils` dependencies — to load on every boot-powered
view, including dashboard/list views that never edit.

Move the entity-save "review changes" UI to `@wordpress/admin-ui` so boot can
render it without pulling in the editor:

- Add `EntitiesSavedStates` (+ `EntitiesSavedStatesExtensible` and
  `useEntitiesSavedStatesIsDirty`) to `@wordpress/admin-ui` as regular exports
  (admin-ui is a bundled package, so it avoids private-API surface). Styles
  ship via admin-ui's `build-style`, which `editor` and `boot` `@use`.
- Promote the entity-save orchestration to a public `saveDirtyEntities`
  `@wordpress/core-data` action (previously a private `@wordpress/editor`
  action) so a bundled UI package can trigger it without private APIs. The
  private `core/editor` `saveDirtyEntities` action is retained as a thin
  backwards-compatible wrapper.
- `@wordpress/editor` re-exports the component/hook unchanged; boot imports
  from `@wordpress/admin-ui` and no longer depends on `@wordpress/editor`.

Behavior is preserved (undo persistence marking and the per-record
"Post Meta." indicator are retained). Alternative to WordPress#71948 and the
`@wordpress/core-data-ui` approach.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Warning: Type of PR label mismatch

To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.

  • Required label: Any label starting with [Type].
  • Labels found: [Package] Core data, [Package] Editor.

Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task.

@enejb

enejb commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

@youknowriad and @Mamaduka - Let me know if there is any different direction we want to take 🙏 .

@enejb
enejb requested review from tyxla and youknowriad July 9, 2026 21:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR decouples boot’s always-mounted “review changes” UI from @wordpress/editor by moving EntitiesSavedStates into @wordpress/admin-ui, enabling @wordpress/boot to render the save/review UI without pulling the full editor (and heavy dependencies) into the eager dependency graph.

Changes:

  • Move EntitiesSavedStates (+ extensible variant + dirty-state hook) to @wordpress/admin-ui, and update boot/editor to consume/re-export it.
  • Promote saveDirtyEntities to a public @wordpress/core-data action and keep core/editor’s private action as a thin wrapper for backward compatibility.
  • Update wp-build route templates to merge each route module’s classic-script dependencies into the generated prerequisites script.

Reviewed changes

Copilot reviewed 36 out of 41 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/wp-build/templates/routes-registration.php.template Collect classic script deps from route/content module assets and pass them into route registration.
packages/wp-build/templates/page.php.template Track and enqueue merged per-route classic dependencies via prerequisites script/style deps.
packages/wp-build/templates/page-wp-admin.php.template Same as page.php.template, for wp-admin pages.
packages/wp-build/CHANGELOG.md Document the generated-page dependency enqueue fix.
packages/editor/tsconfig.json Add TS project reference to admin-ui.
packages/editor/src/style.scss Pull admin-ui build-style and drop editor-local entities-saved-states styles import.
packages/editor/src/store/private-actions.js Replace private core/editor saveDirtyEntities implementation with wrapper delegating to core-data.
packages/editor/src/private-apis.js Source EntitiesSavedStatesExtensible from @wordpress/admin-ui for editor private APIs.
packages/editor/src/components/save-publish-panels/index.js Consume EntitiesSavedStates from @wordpress/admin-ui.
packages/editor/src/components/index.js Re-export EntitiesSavedStates and useEntitiesSavedStatesIsDirty from @wordpress/admin-ui.
packages/editor/README.md Update generated docs; currently shows “Undocumented declaration.” for re-exports.
packages/editor/package.json Add runtime dependency on @wordpress/admin-ui.
packages/editor/CHANGELOG.md Note component move + action promotion while preserving public/private API.
packages/core-data/tsconfig.json Add TS project reference to notices.
packages/core-data/src/actions.js Add new public saveDirtyEntities action (logic moved from editor).
packages/core-data/README.md Document the new saveDirtyEntities action.
packages/core-data/package.json Add @wordpress/notices dependency (block-editor already present).
packages/core-data/CHANGELOG.md Announce new saveDirtyEntities action.
docs/reference-guides/data/data-core.md Add reference guide entry for saveDirtyEntities.
packages/boot/tsconfig.json Remove TS project reference to editor.
packages/boot/src/style.scss Pull admin-ui build-style for moved component styles.
packages/boot/src/components/save-panel/use-save-shortcut.ts Avoid importing editor store; use registry with store name string.
packages/boot/src/components/save-panel/index.tsx Import EntitiesSavedStates from @wordpress/admin-ui.
packages/boot/src/components/save-button/index.tsx Import EntitiesSavedStates from @wordpress/admin-ui.
packages/boot/package.json Remove dependency on @wordpress/editor.
packages/boot/CHANGELOG.md Document boot dependency-graph reduction.
packages/admin-ui/tsconfig.json Add references needed for moved component and utilities.
packages/admin-ui/src/index.ts Export EntitiesSavedStates, EntitiesSavedStatesExtensible, and useEntitiesSavedStatesIsDirty.
packages/admin-ui/src/style.scss Add admin-ui style entry to build entities-saved-states styles.
packages/admin-ui/src/entities-saved-states/index.js Switch saving dispatch to core-data’s public saveDirtyEntities.
packages/admin-ui/src/entities-saved-states/hooks/use-is-dirty.js Add hook implementation for dirty entities tracking (moved from editor).
packages/admin-ui/src/entities-saved-states/entity-type-list.js Add entity grouping UI logic for the moved component.
packages/admin-ui/src/entities-saved-states/entity-record-item.js Replace editor-private selector usage with core-data-based meta change detection + template info.
packages/admin-ui/src/entities-saved-states/style.scss Add styles for entities-saved-states in admin-ui build-style output.
packages/admin-ui/src/entities-saved-states/test/use-is-dirty.js Add unit tests for the moved dirty-state hook.
packages/admin-ui/src/utils/get-template-info.js Add template info helper used by moved UI.
packages/admin-ui/src/utils/get-template-part-icon.js Add template-part icon helper used by moved UI.
packages/admin-ui/README.md Document new admin-ui exports for the moved UI and hook.
packages/admin-ui/package.json Add build-style export + dependencies required by moved UI (incl. fast-deep-equal).
packages/admin-ui/CHANGELOG.md Announce new EntitiesSavedStates feature in admin-ui.
package-lock.json Update lockfile; currently includes an extraneous @wordpress/core-data-ui entry.

Comment thread packages/editor/README.md Outdated
Comment thread packages/editor/README.md
_Returns_

- `Object`: An object containing the following properties: - dirtyEntityRecords: An array of dirty entity records. - isDirty: A boolean indicating if there are any dirty entity records. - setUnselectedEntities: A function to set the unselected entities. - unselectedEntities: An array of unselected entities.
Undocumented declaration.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Undocumented declaration.

### useEntitiesSavedStatesIsDirty

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looking at the diff here, to be honest, this doesn't scream "admin-ui" for me. So the more I think about it, the more I see "core-data" as the right place for this, so basically just refresh my original PR. WDYT @Mamaduka

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry, I think I didn't get my point across on that issue. Commented below.

Also, why not duplicate the component/hook for Dashboard (Beta)? Do we really need a shared component for a single use case outside the editors?

@Mamaduka

Copy link
Copy Markdown
Member

Sorry for the confusion in my comment, I didn't mean that everything should just move to admin-ui, instead of a new package.

The admin-ui should house generic components that can be reused on different pages. It shouldn't care where data is coming from; that's up to the consumer to provide the right data.

Can we add a general EntitiesSavedStates esque composable component admin-ui? Then the consumer could easily copy and paste and provide data handlers.

@youknowriad

Copy link
Copy Markdown
Contributor

Can we add a general EntitiesSavedStates esque composable component admin-ui? Then the consumer could easily copy and paste and provide data handlers.

What kind of UI component you would extract out of this? This component is data-heavy, and it just renders basic UI components. Extracting a UI component out of this is just an over abstraction as there's no other use for such UI component without entities.

@Mamaduka

Copy link
Copy Markdown
Member

Then we could extract the general data handling as a new private hook in core-data and duplicate the UI parts. The former seems to be the complex part; folks would rather not maintain it separately.

@youknowriad

Copy link
Copy Markdown
Contributor

I still don't understand the resistance to move the component to core-data, It's a UI component that tailored to "entities" and core-data is about entities and already has all the necessary dependencies.

@Mamaduka

Copy link
Copy Markdown
Member

Mostly sharing my opinion, don't want to block anything.

I don't think core-data should be coupled to how these entities are displayed for saving. Each package and page might have a slightly different approach, handling all these edge cases and maintaining a new component can become complex.

Instead, why not let core-data handle the data part and the consumer handle the UI?

P.S. I always thought of core-data as a data module package providing CRUD methods for WP entities.

cc @tyxla, @jsnajdr

@youknowriad

Copy link
Copy Markdown
Contributor

Instead, why not let core-data handle the data part and the consumer handle the UI?

I think these components are complex enough and are worth sharing basically. I don't think duplicating this component is a good idea.

@youknowriad

Copy link
Copy Markdown
Contributor

The question to me is: Is having a "core-data-ui" package worth it, compared to just having these components in "core-data". Because IMO, there's no other valid place where to put these components.

@tyxla

tyxla commented Jul 10, 2026

Copy link
Copy Markdown
Member

I'd like to avoid unnecessary duplication if possible. And it does feel odd for that component to live in an admin UI package - I'd expect the components there are generic and ideally don't have coupling with data at all.

The question to me is: Is having a "core-data-ui" package worth it, compared to just having these components in "core-data". Because IMO, there's no other valid place where to put these components.

This resonates with me. And we already have hooks in the package (like useEntityId or useEntityProp), so why not have generic components that are tigthly coupled to core-data?

Now, whether EntitiesSavedStates is generic enough, I doubt that. Currently it seems like it's a bit coupled to the editor package. And it may be unnecessary or unreasonable to create a generic "entities saved state" component that works across all editors and contexts. But it's worth considering IMO. If not, the editor package seems like the best and most generic place right now.

@youknowriad

Copy link
Copy Markdown
Contributor

The main motivation for this work is to be able to lazy load the editor, while ensuring the "boot"/"frame" is not. The save button and saved entities modal/panel are higher level than the editor, they're always there in all pages. The editor is not.

@tyxla

tyxla commented Jul 10, 2026

Copy link
Copy Markdown
Member

The main motivation for this work is to be able to lazy load the editor, while ensuring the "boot"/"frame" is not. The save button and saved entities modal/panel are higher level than the editor, they're always there in all pages. The editor is not.

Got it. But my point above still stands:

it does feel odd for that component to live in an admin UI package - I'd expect the components there are generic and ideally don't have coupling with data at all.

@enejb

enejb commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@youknowriad, @Mamaduka and @tyxla so what is the next step here? Does the approach needs further discussion?

As far as I understand @tyxla and @youknowriad seems to agree that we should add the component to core-data.

Which implies a rebase the #71948 and merge that part?

Besides that anything else that needs to be consisted?
@youknowriad do you want me to rebase the PR?

@youknowriad

Copy link
Copy Markdown
Contributor

For me, either of these two are acceptable:

  • Move the component to core-data
  • Create a bundled core-data-ui package (like you attempted initially)

@tyxla

tyxla commented Jul 13, 2026

Copy link
Copy Markdown
Member

Fine with either of those, too.

@enejb enejb closed this Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Core data /packages/core-data [Package] Editor /packages/editor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants