Skip to main content
Version: 2026.1

Registering a Widget Type

After implementing the repository, hydrator, data resolver, and frontend class, wire them into the bundle through configuration and the Studio UI plugin system.

Backend Registration

1. Register the widget type identifier

Add the type string to pimcore_studio_dashboards.widget_types so it appears in the add-widget dialog:

# config/packages/pimcore_studio_dashboards.yaml
pimcore_studio_dashboards:
widget_types:
- 'top_assets'

2. Add a config node for the widget storage (optional)

If your repository uses AbstractConfigRepository and LocationAwareConfigRepository, add a configuration node for widget storage in your own bundle.

The Studio Dashboards extension wires storage parameters automatically only for built-in widget types and custom_reports. For arbitrary custom nodes (for example top_assets_widgets), you must provide the storage config and constructor arguments in your own extension/service configuration.

The built-in widget nodes follow this pattern:

// In your DependencyInjection/Configuration.php
$node->children()
->arrayNode('top_assets_widgets')
->defaultValue([])
->useAttributeAsKey('id')
->arrayPrototype()
->children()
// widget-specific fields
->scalarNode('limit')->defaultValue(10)->end()
->end()
->end()
->end()
->end();

3. Tag service classes

The three service classes are picked up automatically by the tagged-iterator loaders when decorated with the correct #[AutoconfigureTag] attribute:

ClassTag constant
Config repositoryTaggedIteratorRepository::REPOSITORY_TAG (pimcore.studio_dashboards.widget_repository)
Config hydratorTaggedIteratorHydrator::HYDRATOR_TAG (pimcore.studio_dashboards.widget_hydrator)
Data resolverTaggedIteratorDataResolver::RESOLVER_TAG (pimcore.studio_dashboards.widget_data_resolver)

With standard Symfony autowiring and autoconfigure: true, annotating the classes is sufficient:

use Pimcore\Bundle\StudioDashboardsBundle\Service\Loader\Widget\TaggedIteratorRepository;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

#[AutoconfigureTag(TaggedIteratorRepository::REPOSITORY_TAG)]
final class TopAssetsConfigRepository extends AbstractConfigRepository { ... }
use Pimcore\Bundle\StudioDashboardsBundle\Service\Loader\Widget\TaggedIteratorHydrator;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

#[AutoconfigureTag(TaggedIteratorHydrator::HYDRATOR_TAG)]
final class TopAssetsConfigHydrator implements ConfigHydratorInterface { ... }
use Pimcore\Bundle\StudioDashboardsBundle\Service\Loader\Widget\TaggedIteratorDataResolver;
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

#[AutoconfigureTag(TaggedIteratorDataResolver::RESOLVER_TAG)]
final class TopAssetsResolver implements DataResolverInterface { ... }

Frontend Registration

Register the frontend class through your Studio UI bundle plugin.

1. Bind the service in the plugin's onInit

// src/plugins.ts
import { type IAbstractPlugin } from '@pimcore/studio-ui-bundle'
import { DynamicTypeWidgetTypeTopAssets } from './top-assets/dynamic-type-widget-type-top-assets'

export const TopAssetsPlugin: IAbstractPlugin = {
name: 'top-assets-plugin',

onInit: ({ container }): void => {
container
.bind('StudioDashboards/DynamicTypes/WidgetType/TopAssets')
.to(DynamicTypeWidgetTypeTopAssets)
.inSingletonScope()
},

onStartup: ({ moduleSystem }): void => {
moduleSystem.registerModule(TopAssetsExtension)
}
}

2. Register the dynamic type in the module's onInit

The widget type registry service ID is the plain string 'StudioDashboards/DynamicTypes/WidgetType/Registry'. Use it directly with the DI container - no import from the dashboards bundle is needed.

// src/top-assets-extension.ts
import { container, type AbstractModule } from '@pimcore/studio-ui-bundle'

const DASHBOARDS_REGISTRY_ID = 'StudioDashboards/DynamicTypes/WidgetType/Registry'
const TOP_ASSETS_WIDGET_ID = 'StudioDashboards/DynamicTypes/WidgetType/TopAssets'

export const TopAssetsExtension: AbstractModule = {
onInit: (): void => {
const widgetTypeRegistry = container.get<any>(DASHBOARDS_REGISTRY_ID)
widgetTypeRegistry.registerDynamicType(
container.get(TOP_ASSETS_WIDGET_ID)
)
}
}
note

The Studio Dashboards Bundle exposes its module federation entry point under the name pimcore_studio_dashboards_bundle.

Configure the dashboards bundle as a Module Federation remote in your rsbuild.config.ts if your extension needs to consume the dashboards plugin entry point.

Do not import deep internal module paths from the remote (for example pimcore_studio_dashboards_bundle/modules/...). The dashboards bundle exposes only its root plugin entry (.) through module federation.

Remote configuration example:

// In rsbuild.config.ts remotes:
'pimcore_studio_dashboards_bundle': 'promise new Promise(resolve => { ... })',

Events

The bundle dispatches Symfony events before returning responses from its API controllers. Listen to them to enrich or modify the payload without overriding core services:

Event classConstantTriggered when
DashboardEventpre_response.dashboardA single dashboard is returned
SimpleDashboardEventpre_response.dashboard_simpleA dashboard summary is returned
WidgetConfigEventpre_response.studio_dashboards.widget.config.getA widget configuration is returned
WidgetConfigConfigurationEventpre_response.studio_dashboards.widget.config.configurationWidget config options are returned
WidgetTypeEventpre_response.studio_dashboards.widget.typeWidget type metadata is returned
LayoutOptionEventpre_response.dashboard.layout_optionLayout options are returned
use Pimcore\Bundle\StudioDashboardsBundle\Event\WidgetTypeEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

#[AsEventListener(event: WidgetTypeEvent::EVENT_NAME)]
final class MyWidgetTypeListener
{
public function __invoke(WidgetTypeEvent $event): void
{
$widgetType = $event->getWidgetType();
// modify $widgetType as needed
}
}