Repository navigation
[6.x] Let elements and plugins add buttons to the editor footer - #19921
brianjhanson wants to merge 4 commits into
Conversation
Element types override defineAdditionalButtonDescriptors() and plugins listen for ElementAdditionalButtonDescriptorsResolving to add footer buttons. These buttons use the action menu's behavior descriptors, so they can open links, downloads, modals and slideouts without submitting the form. The additional-buttons layout slot now sits at the end of the content footer, and the new footer-meta slot beside the save controls holds the autosave status. Slideouts now render the same ContentFooter as full pages. The Yii adapter renders Craft 5 additional buttons HTML from getAdditionalButtons(), EVENT_DEFINE_ADDITIONAL_BUTTONS and additionalButtonsHtml() into the same slot. Bridged cp/Screen pages now render additionalButtonsHtml(), which was previously dropped. Fixes #19910 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
📚 Storybook previews@craftcms/ui — open Storybook No changed components detected in this Storybook. resources/js — open Storybook No changed components detected in this Storybook. |
|
We should probably remove the old methods from src/ and only have them in the adapter if we have alternatives for them |
Descriptors replace the HTML API, so core no longer declares getAdditionalButtons() or fires ElementAdditionalButtonsResolving. The only core caller built HTML that the legacy JSON slideout response never sent. The adapter now adds getAdditionalButtons() to elements and fires EVENT_DEFINE_ADDITIONAL_BUTTONS directly, so Craft 5 overrides and handlers still render in the Inertia editor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
riasvdv
left a comment
There was a problem hiding this comment.
We should remove any other HTML methods that currently have an alternative in either descriptors or maybe as a Form Node/Control, but that can be done in a follow up PR
…uttons # Conflicts: # resources/js/modules/elements/composables/useElementActionMenu.ts
|
This PR had conflicts with Claude's response
|
The Inertia element editor had no way for element types or plugins to add a button that doesn't submit the form, such as a link, a download or a modal. Craft 5 supported this with
getAdditionalButtons()andadditionalButtonsHtml().This PR adds a descriptor-based API for those buttons and moves the
additional-buttonslayout slot to the end of the content footer, where they render.Descriptors replace the element-level HTML API, so that API now lives only in the Yii adapter. Core no longer declares
getAdditionalButtons()or firesElementAdditionalButtonsResolving. The adapter still renders Craft 5 HTML buttons in the same slot.additionalButtonDescriptors()(public, fires the event)defineAdditionalButtonDescriptors()(element-type hook)ElementAdditionalButtonDescriptorsResolving(plugin event)getAdditionalButtons()(HTML) andEVENT_DEFINE_ADDITIONAL_BUTTONSCpScreenResponse::additionalButtonsHtml()/additionalButtonsTemplate()Usage (v6)
Each button is a descriptor with a
label, an optionaliconandvariant(defaultoutline), and abehavior. Behaviors are the same ones the element action menu dispatches, so the buttons work without submitting the editor's form. They render at the end of the editor's footer, on full pages and in slideouts.Custom element types
Override
defineAdditionalButtonDescriptors():Plugins adding buttons to other element types
Listen for
ElementAdditionalButtonDescriptorsResolving:formModalendpoints work like this:modalUrlis fetched withGETandparams. It returns{ui, title?, submitLabel?}, whereuiis a resolvedUiPayload.actionUrlreceives aPOSTof the form values merged withparams. It returns{message?}, or a 422 witherrorskeyed by field path.The full list of behaviors is
link,download,submit,slideout,formModalandcopyUrl, plus the element-specific ones the action menu uses. SeeElementActionBehaviorinuseElementActionMenu.ts.Other screens
Your own Vue (Inertia) page: fill the slot with the global layout slot component.
Your own server-rendered screen (a
CpScreenResponsewithout aninertiaPage()):$response->additionalButtonsHtml(...)oradditionalButtonsTemplate(...)still work, and now render in the slot on full pages.Someone else's screen that isn't an element editor, e.g. a core settings page: there's no API for this, as in Craft 5. A
LayoutSloton a page the plugin doesn't own renders nothing. A screen-level descriptor event would be a natural follow-up.Layout slots for Vue pages
additional-buttonsnow sits at the end of the content footer, after a spacer.footer-metaslot sits right after the save controls. The element editor puts its autosave status there.ContentFooteras full pages, with the same slots, includingcontent-footer. Their Cancel/Close button sits at the far right, afteradditional-buttons.What happens to plugins using the Craft 5 API
With the Yii adapter installed, the Craft 5 APIs keep working and render into the same
additional-buttonsslot:getAdditionalButtons(): stringon an element class: the adapter addsgetAdditionalButtons()to every element, with the Craft 5 signature, so overrides (including ones callingparent::) keep working. The returned HTML is rendered in the editor's footer.Element::EVENT_DEFINE_ADDITIONAL_BUTTONShandlers: the adapter'sgetAdditionalButtons()fires the event directly, including for handlers registered under Craft 5 class names likecraft\elements\Entry, so their HTML is rendered too.$response->additionalButtonsHtml()/additionalButtonsTemplate()called fromprepareEditScreen(): rendered alongside the above.defineAdditionalButtonDescriptors()andElementAdditionalButtonDescriptorsResolving.Behavior changes to be aware of:
getAdditionalButtons()or fireEVENT_DEFINE_ADDITIONAL_BUTTONS, so that HTML isn't rendered. Port to descriptors.cp/Screenpages (aCpScreenResponsewithout aninertiaPage()):additionalButtonsHtml()used to be sent to the page but never rendered. It now renders inadditional-buttonson full pages. Slideouts don't receive it, as in Craft 5.Breaking changes for 6.x code
CraftCms\Cms\Element\Contracts\ElementInterface::getAdditionalButtons()and itsHasControlPanelUIimplementation.CraftCms\Cms\Element\Events\ElementAdditionalButtonsResolving.EditElementController::additionalButtons(). It built the legacy header buttons (preview, Create a draft, Apply draft, revert, and the element's own HTML) for the non-Inertia branch, but that branch only answers JSON slideout requests, whose payload never included them. The Inertia editor builds these fromeditorActions,previewTargetsand the new descriptors.v6 code calling
$element->getAdditionalButtons()or listening forElementAdditionalButtonsResolvingshould useadditionalButtonDescriptors(),defineAdditionalButtonDescriptors()andElementAdditionalButtonDescriptorsResolvinginstead. These were added during the 6.x alphas.Testing
tests/Feature/Element/ElementAdditionalButtonsTest.phpcovers the element-type hook, the event, and that the buttons are sent asadditionalButtons, apart fromeditorActions.buttons.yii2-adapter/tests-laravel/Bridge/ElementEditorCompatibilityTest.phpcovers:getAdditionalButtons()override, theEVENT_DEFINE_ADDITIONAL_BUTTONShandler andadditionalButtonsHtml(), including their JS;craft\elements\Entry);resources/js/common/layouts/screens/page/ContentFooter.test.tsis a regression test: it fills, empties and refills a footer slot.Fixes #19910.