Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Event for adding custom tabs to element "Edit" screens at runtime #7258

Closed
michaelrog opened this issue Dec 11, 2020 · 6 comments
Closed
Labels
enhancement improvements to existing features extensibility 🔌 features related to plugin/module dev
Milestone

Comments

@michaelrog
Copy link

michaelrog commented Dec 11, 2020

Continuing the conversation we started in the Commerce repo...

It'd be great to have a way for plugins to add custom tabs to element edit screens at runtime.

Something like...

Event::on(
    Fields::class,
    Fields::EVENT_MODIFY_TABS,
    function(ElementTabsEvent $event) {
        if ($event->element instanceof Entry) {
            $tabs = $event->tabs;
            $tabs[] = [
                'label' => "My Tab",
                'url' => 'mytab',
                'class' => 'custom-tab',
                'content' => Craft::$app->getView()->renderTemplate('my-plugin/_myTab',
            ];
            $event->tabs = $tabs;
        }
    }
);

For Commerce Orders, an additional "static" rendering would also potentially be needed:

Event::on(
    Fields::class,
    Fields::EVENT_MODIFY_TABS,
    function(ElementTabsEvent $event) {
        if ($event->element instanceof Order) {
            $tabs = $event->tabs;
            $tabs[] = [
                'label' => "My Tab",
                'class' => 'custom-tab',
                'content' => Craft::$app->getView()->renderTemplate('my-plugin/_myTab',
                'staticContent' => Craft::$app->getView()->renderTemplate('my-plugin/_myTab_static',
            ];
            $event->tabs = $tabs;
        }
    }
);

It's already technically possible to add custom tabs, by hijacking the Twig context in template hooks... but it feels icky. Having an officially supported method would be much nicer. 😄

brandonkelly added a commit that referenced this issue Dec 14, 2020
@brandonkelly
Copy link
Member

brandonkelly commented Dec 14, 2020

Just added a new EVENT_CREATE_FORM event to craft\models\FieldLayout for Craft 3.6.

This will trigger right before createForm() starts looping through the field layout’s tabs, and gives you a chance to modify the existing tabs or add new ones.

Note that at this stage you are dealing with FieldLayoutTab and FieldLayoutElement models, not the raw HTML. It is up to each individual field layout element to define its rendered HTML, via formHtml().

Here’s an example of how to add a new tab to a field layout, with a text field, HR, and rendered template:

use craft\elements\Entry;
use craft\events\CreateFieldLayoutFormEvent;
use craft\fieldlayoutelements\HorizontalRule;
use craft\fieldlayoutelements\StandardTextField;
use craft\fieldlayoutelements\Template;
use craft\models\FieldLayout;
use craft\models\FieldLayoutTab;
use yii\base\Event;

Event::on(
    FieldLayout::class,
    FieldLayout::EVENT_CREATE_FORM,
    function(CreateFieldLayoutFormEvent $event) {
        if ($event->element instanceof Entry) {
            $event->tabs[] = new FieldLayoutTab([
                'name' => 'My Tab',
                'elements' => [
                    new StandardTextField([
                        'attribute' => 'myTextField',
                        'label' => 'My Text Field',
                    ]),
                    new HorizontalRule(),
                    new Template([
                        'template' => '_layout-elements/info'
                    ]),
                ],
            ]);
        }
    }
);

You can tell if the form should be rendered statically via $event->static.

@brandonkelly brandonkelly added enhancement improvements to existing features extensibility 🔌 features related to plugin/module dev and removed enhancement labels Dec 14, 2020
@brandonkelly brandonkelly added this to the 3.6 milestone Dec 14, 2020
brandonkelly added a commit that referenced this issue Dec 14, 2020
@brandonkelly
Copy link
Member

Craft 3.6 RC2 is out now with that new event.

@brandonkelly
Copy link
Member

Craft 3.6 has now been officially released ✨

@michaelrog
Copy link
Author

Just finished a hefty refactor of our Commerce plugin's tab UI to use this new event instead of our previous hacks. It's so much cleaner (and less bug-prone) now!

@brandonkelly this was a really nice implementation. The FieldLayoutElement models are easy to work with, and all the abstractions feel like they're in just the right spots. Bravo, and thanks! 🙏🏼

@michaelrog
Copy link
Author

p.s. To my future self (and maybe to @mattstein for docs)... 😃

The Template UI element renders its target template in the site template mode. In this context, plugin templates are not automatically available.

This is easily solved by using the EVENT_REGISTER_SITE_TEMPLATE_ROOTS event to register my template root for the site context. (Craft already registers cp template roots automatically, in BasePlugin; it's up to the user to register site template roots manually.)

And if you're getting really fancy, trying to render templates from other plugins, modules, or Craft, then you can invoke the renderTemplate function directly (from one of your own templates), to force the cp context:

{{ craft.app.view.renderTemplate(
    'some-other-plugin/_includeThatNeedsToBeRenderedInCp',
    { ... },
    'cp'
) | raw }}

@brandonkelly
Copy link
Member

brandonkelly commented Jun 5, 2021

For plugin-provided UI, it’s probably better to just define your own custom field layout UI elements, by extending craft\fieldlayoutelements\BaseUiElement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement improvements to existing features extensibility 🔌 features related to plugin/module dev
Projects
None yet
Development

No branches or pull requests

2 participants