You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is an overview issue for a customizable WordPress dashboard — a widget-based surface users can arrange, resize, and compose.
It builds on the design direction in #74616 and sits downstream of the broader admin work in #70913, where Widget is defined as a first-class primitive. The direction is reflected in the WordPress 7.0 planning post — "bring grid layout customization to dashboard experience or other screens" — and in the 7.0 product review, which captured the desire to turn the dashboard into a more customizable homepage with remixable widgets.
All runtime code lands behind a new gutenberg-dashboard-widgets experiment while the APIs settle. Nothing is promoted out of __experimental until the shape is proven in real use.
Architecture
The dashboard is composed of three layers, each depending only on the layer below. Identity (what a widget is) is decoupled from wiring (how a widget reaches a given page's import map), which keeps widget types reusable across surfaces — dashboards, sidebars, plugin panels, future screens.
The build pipeline discovers widgets and emits a registry. The data layer (@wordpress/widget-types) populates a surface-agnostic store and exposes a helper for surfaces to wire widget modules into their page's import map. Each surface opts in by hooking its own page filter; the data layer never names a specific page.
%%{init: {
"flowchart": {
"padding": 26,
"nodeSpacing": 78,
"rankSpacing": 90,
"subGraphTitleMargin": { "top": 21, "bottom": 23 },
"curve": "basis"
},
"themeVariables": {
"edgeLabelBackground": "transparent",
"fontSize": "20px"
}
}}%%
graph TB
subgraph s1["<span style='font-size:22px;font-weight:600'>① Build · @wordpress/build</span>"]
direction LR
SRC["widgets/{name}/<br/>widget.json · widget.ts · render.tsx"]
OUT["build/widgets/registry.php<br/>build/widgets.php"]
SRC --> OUT
end
subgraph s2["<span style='font-size:22px;font-weight:600'>② Data layer · @wordpress/widget-types</span>"]
direction LR
PHP["widget-types.php<br/>(injects window.__registeredWidgetTypes)"]
BOOT["bootstrapWidgetTypes()"]
STORE[("core/widget-types<br/>store")]
PHP --> BOOT --> STORE
end
subgraph s3["<span style='font-size:22px;font-weight:600'>③ Surface · dashboard, analytics, …</span>"]
direction LR
FILTER["{page}_script_module_dependencies<br/>filter hook"]
CONSUMER["consume store +<br/>lazy-load renderModule"]
FILTER --> CONSUMER
end
HELPER["gutenberg_get_widget_module_dependencies()"]
s1 ==> s2
s2 ==> s3
s2 -.exposes.-> HELPER
HELPER -.used in.-> FILTER
classDef default fill:#8898a815,stroke:#8898a8,stroke-width:1px,rx:13,ry:13
classDef accent fill:#f59e0b15,stroke:#f59e0b,stroke-width:1.5px,rx:13,ry:13
classDef layer fill:transparent,stroke:#8898a880,stroke-width:1px,rx:18,ry:18
class HELPER accent
class s1,s2,s3 layer
Loading
Grid primitive
A reusable grid primitive for tile layouts — drag to reorder, resize, fill and full-width spans. Designed to be usable outside the dashboard as well.
A convention for authoring widgets (metadata + render component) that is auto-discovered and registered with minimal boilerplate, following the same file-based pattern used elsewhere in the build system.
A surface-agnostic registry for widget types, so any screen can consume them. Includes a PHP-side registration API that bridges into a client-side store, mirroring how block types are wired in core. No coupling to any particular surface.
The dashboard rendering surface is built on the grid primitive and the widget registry. Defines the widget shell (header, content, actions) and composes the full dashboard, including inserter and empty-state affordances.
Layout flows in as props — persistence is a separate concern.
Additional widgets are welcome as follow-up contributions once the shell lands.
Important
This is meant to be an ongoing working document. Tracking issues and PRs will be linked back as they're opened, and the structure will evolve as pieces land.
This is an overview issue for a customizable WordPress dashboard — a widget-based surface users can arrange, resize, and compose.
It builds on the design direction in #74616 and sits downstream of the broader admin work in #70913, where Widget is defined as a first-class primitive. The direction is reflected in the WordPress 7.0 planning post — "bring grid layout customization to dashboard experience or other screens" — and in the 7.0 product review, which captured the desire to turn the dashboard into a more customizable homepage with remixable widgets.
All runtime code lands behind a new
gutenberg-dashboard-widgetsexperiment while the APIs settle. Nothing is promoted out of__experimentaluntil the shape is proven in real use.Architecture
The dashboard is composed of three layers, each depending only on the layer below. Identity (what a widget is) is decoupled from wiring (how a widget reaches a given page's import map), which keeps widget types reusable across surfaces — dashboards, sidebars, plugin panels, future screens.
The build pipeline discovers widgets and emits a registry. The data layer (@wordpress/widget-types) populates a surface-agnostic store and exposes a helper for surfaces to wire widget modules into their page's import map. Each surface opts in by hooking its own page filter; the data layer never names a specific page.
%%{init: { "flowchart": { "padding": 26, "nodeSpacing": 78, "rankSpacing": 90, "subGraphTitleMargin": { "top": 21, "bottom": 23 }, "curve": "basis" }, "themeVariables": { "edgeLabelBackground": "transparent", "fontSize": "20px" } }}%% graph TB subgraph s1["<span style='font-size:22px;font-weight:600'>① Build · @wordpress/build</span>"] direction LR SRC["widgets/{name}/<br/>widget.json · widget.ts · render.tsx"] OUT["build/widgets/registry.php<br/>build/widgets.php"] SRC --> OUT end subgraph s2["<span style='font-size:22px;font-weight:600'>② Data layer · @wordpress/widget-types</span>"] direction LR PHP["widget-types.php<br/>(injects window.__registeredWidgetTypes)"] BOOT["bootstrapWidgetTypes()"] STORE[("core/widget-types<br/>store")] PHP --> BOOT --> STORE end subgraph s3["<span style='font-size:22px;font-weight:600'>③ Surface · dashboard, analytics, …</span>"] direction LR FILTER["{page}_script_module_dependencies<br/>filter hook"] CONSUMER["consume store +<br/>lazy-load renderModule"] FILTER --> CONSUMER end HELPER["gutenberg_get_widget_module_dependencies()"] s1 ==> s2 s2 ==> s3 s2 -.exposes.-> HELPER HELPER -.used in.-> FILTER classDef default fill:#8898a815,stroke:#8898a8,stroke-width:1px,rx:13,ry:13 classDef accent fill:#f59e0b15,stroke:#f59e0b,stroke-width:1.5px,rx:13,ry:13 classDef layer fill:transparent,stroke:#8898a880,stroke-width:1px,rx:18,ry:18 class HELPER accent class s1,s2,s3 layerGrid primitive
A reusable grid primitive for tile layouts — drag to reorder, resize, fill and full-width spans. Designed to be usable outside the dashboard as well.
Build pipeline for widgets
A convention for authoring widgets (metadata + render component) that is auto-discovered and registered with minimal boilerplate, following the same file-based pattern used elsewhere in the build system.
Widget registration API
A surface-agnostic registry for widget types, so any screen can consume them. Includes a PHP-side registration API that bridges into a client-side store, mirroring how block types are wired in core. No coupling to any particular surface.
widget.jsonmetadata schema #77629Rendering engine
The dashboard rendering surface is built on the grid primitive and the widget registry. Defines the widget shell (header, content, actions) and composes the full dashboard, including inserter and empty-state affordances.
Layout flows in as props — persistence is a separate concern.
Layout persistence
User-saved dashboard layouts, with plugin-provided defaults that users can override, and a reset-to-default action.
First-party widgets
A small set of widgets adapted to the new shell:
Additional widgets are welcome as follow-up contributions once the shell lands.
Important
This is meant to be an ongoing working document. Tracking issues and PRs will be linked back as they're opened, and the structure will evolve as pieces land.