Dashboard Widgets: declarative actions in the widget schema - #80363
Conversation
Carry declared actions from widget.json to the client through the build manifest, the widget-modules REST endpoint, and the useWidgetTypes merge.
Render a widget type's declared actions as a More dropdown of links in the normal-mode toolbar.
Cover the actions field in the widget-primitives README and CHANGELOG, and across the four pipeline stages in the architecture doc.
Give the demo widget types help notes and a goal-progress actions example so the story exercises both surfaces.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: +11 B (0%) Total Size: 7.73 MB 📦 View Changed
|
|
Flaky tests detected in b490d34. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/29564835163
|
chihsuan
left a comment
There was a problem hiding this comment.
Nice work! @retrofox Overall looks good.
One small issue: Would it make sense to include the actions trigger in the inline-controls reserve? The fit currently calculation reserves room for Settings, but not for the new Actions button.
Add a callback fulfillment for client-generated downloads (a handler that produces the file), beyond the declarative link.
Looking ahead to callbacks, just sharing a few thoughts for the callback follow-up based on reviewing the Premium Analytics CSV POC (Automattic/jetpack#50362, Automattic/jetpack#50569):
- Some actions need live, per-widget state, such as the rows currently loaded in the widget.
- Availability may change with feature flags, empty data, missing parameters, or error states.
- Async actions need a loading state, duplicate-click prevention, and somewhere to surface failures.
- Downloads may be generated locally or fetched from a server before being handed to the browser.
- Static action metadata will need a clear way to connect with its runtime handler, likely through the action ID.
- The full report page may use a different presentation from the compact widget action, while still sharing the same underlying behavior.
Nothing that needs to be addressed here. Just a few scenarios that hope it will be useful when shaping the follow-up.
yes yes, good call. |
@chihsuan, we need to keep working on that. I suggest continuing with a follow-up thought. The issue is already in trunk and was not introduced by this PR. WDYT?
👍 |
|
Issue #80398 |
chihsuan
left a comment
There was a problem hiding this comment.
we need to keep working on that. I suggest continuing with a follow-up thought. The issue is already in trunk and was not introduced by this PR. WDYT?
Sounds good! No further feedback from me. Thanks!
* add widget actions to schema and REST pipeline Carry declared actions from widget.json to the client through the build manifest, the widget-modules REST endpoint, and the useWidgetTypes merge. * add actions more menu to dashboard widget chrome Render a widget type's declared actions as a More dropdown of links in the normal-mode toolbar. * add actions to the hello-dolly widget * docs: document widget actions Cover the actions field in the widget-primitives README and CHANGELOG, and across the four pipeline stages in the architecture doc. * improve jsdoc * docs: add actions and help to the dashboard story Give the demo widget types help notes and a goal-progress actions example so the story exercises both surfaces. * docs: link the field types story from the README * update: clarify hello-dolly action label * docs: add WithActions story to widget-render * docs: cover actions in the anatomy doc * docs: add the Actions story page * docs: drop the Storybook link from the README * simplifies Actions story doc page * docs: add changelog entries for widget actions
What
Adds an optional
actionsfield to the widget schema: a declarative list of the verbs a widget type exposes, such as navigating to a report or downloading a file.Each
WidgetActioncarriesid,label,href, and optionaldownload/openInNewTab.The only fulfillment today is a
link: the widget declares the intent and a target, and the host renders it as an anchor and owns placement.The dashboard surfaces the actions in a "More" (three-dots) menu in the widget toolbar. Because navigation and downloads are handled by the browser, the widget stays host-agnostic.
The field travels from
widget.jsonto the client through the full pipeline (build manifest → PHP registry → REST → TypeScript merge), mirroringhelp.Why
Widgets had no way to declare the verbs a user triggers.
How
Contract (
@wordpress/widget-primitives)A
WidgetActiontype ({ id, label, href, download?, openInNewTab? }), plusactions?onWidgetTypeMetadataandWidgetModuleRecordOverrides, merged inuseWidgetTypes.Server pipeline (mirrors
helpat every layer)The build manifest (
build.mjstoPhpActionsLiteral),WP_Widget_Type($actions), registration with sanitization and label i18n, and the REST controller (exposure plus item schema).PHP coverage in the widget-modules controller test.
UI (
@wordpress/widget-dashboard):A
WidgetActionscomponent rendering a three-dotsIconButtonthat opens aMenuofLinkitems, mounted in the normal-mode toolbar.Demo
The
hello-dollywidget declares two actions: a link to its plugin page and a lyrics download.Docs:
The widget-primitives README (
WidgetAction), CHANGELOG, and the architecture doc (actions across the four pipeline stages).The dashboard Storybook includes story exercises, actions, and help notes.
Testing
gutenberg-dashboard-widgetsexperiment.hello-dollytile shows a three-dots menu in its toolbar.hello-dolly-lyrics.txt.Screen.Recording.2026-07-16.at.7.34.36.PM.mov
vendor/bin/phpunit phpunit/experimental/class-wp-rest-widget-modules-controller-test.php.Screen.Recording.2026-07-16.at.7.24.28.PM.mov
You can take a look at the widget-module endpoint to see the
actionsproperty:Follow-ups
scope: 'local' | 'global'axis so a host can surface an action beyond the widget (for example, the dashboard command palette).callbackfulfillment for client-generated downloads (a handler that produces the file), beyond the declarativelink.stepsfulfillment backed by the connection language.