PSR-14 Events
The extension provides three PSR-14 events to customize the Edit Menu and Toolbar.
FrontendEditDropdownModifyEvent
Use the Frontend to modify the Edit Menu for content elements.
You can add, remove or modify buttons for specific content elements.
Available methods:
get- Returns the content element data arrayContent Element () get- Returns the current menu buttonMenu Button () set- Sets the modified menu buttonMenu Button () get- Returns the return URL for edit linksReturn Url ()
Example:
<?php
declare(strict_types=1);
namespace Vendor\Package\EventListener;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\Core\Imaging\IconFactory;
use Xima\XimaTypo3FrontendEdit\Enumerations\ButtonType;
use Xima\XimaTypo3FrontendEdit\Event\FrontendEditDropdownModifyEvent;
use Xima\XimaTypo3FrontendEdit\Template\Component\Button;
#[AsEventListener(
identifier: 'my-extension/modify-edit-menu',
)]
class ModifyEditMenuListener
{
public function __construct(
protected readonly IconFactory $iconFactory,
protected readonly UriBuilder $uriBuilder
) {}
public function __invoke(FrontendEditDropdownModifyEvent $event): void
{
$contentElement = $event->getContentElement();
$menuButton = $event->getMenuButton();
// Add a custom button for a specific plugin
if ($contentElement['CType'] === 'list' && $contentElement['list_type'] === 'news_pi1') {
$menuButton->appendAfterChild(new Button(
'Edit news settings',
ButtonType::Link,
$this->uriBuilder->buildUriFromRoute(
'record_edit',
[
'edit' => ['tt_content' => [$contentElement['uid'] => 'edit']],
'returnUrl' => $event->getReturnUrl(),
],
)->__toString(),
$this->iconFactory->getIcon('content-news', 'small')
),
'edit_page',
'edit_news_settings'
);
}
// Remove a button
$menuButton->removeChild('div_action');
$event->setMenuButton($menuButton);
}
}
FrontendEditPageDropdownModifyEvent
Use the Frontend to modify the Toolbar menu for page-level actions.
Available methods:
get- Returns the current page IDPage Id () get- Returns the current language UIDLanguage Uid () get- Returns the current menu buttonMenu Button () set- Sets the modified menu buttonMenu Button () get- Returns the return URL for edit linksReturn Url ()
Example:
<?php
declare(strict_types=1);
namespace Vendor\Package\EventListener;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\Core\Imaging\IconFactory;
use Xima\XimaTypo3FrontendEdit\Enumerations\ButtonType;
use Xima\XimaTypo3FrontendEdit\Event\FrontendEditPageDropdownModifyEvent;
use Xima\XimaTypo3FrontendEdit\Template\Component\Button;
#[AsEventListener(
identifier: 'my-extension/modify-toolbar',
)]
class ModifyToolbarListener
{
public function __construct(
protected readonly IconFactory $iconFactory,
protected readonly UriBuilder $uriBuilder
) {}
public function __invoke(FrontendEditPageDropdownModifyEvent $event): void
{
$menuButton = $event->getMenuButton();
// Add a custom page action
$menuButton->appendChild(new Button(
'Clear page cache',
ButtonType::Link,
$this->uriBuilder->buildUriFromRoute(
'tce_db',
[
'cacheCmd' => $event->getPageId(),
'redirect' => $event->getReturnUrl(),
],
)->__toString(),
$this->iconFactory->getIcon('actions-system-cache-clear', 'small')
),
'clear_cache'
);
$event->setMenuButton($menuButton);
}
}
FrontendEditDataEnrichmentEvent
Use the Frontend to attach structured, serializable
data to content elements - e.g. a status color, an assignee, a comment count -
which the frontend JavaScript can then render, for example via a
register call. Since element data is delivered via the
uncached edit AJAX request, this is also the only cache-safe
transport for volatile third-party data, and it rides along on the existing
request without an extra roundtrip.
The event is dispatched once per request, with the full filtered content element list - not once per element - so a listener backed by a database can resolve its data in a single query instead of being invoked N times with no way to batch.
Available methods:
get- Returns all content element rows for this request, keyed by uid (read-only)Content Elements () get- Returns just the uids, for a batched lookupContent Element Uids () get/Page Id () get/Language Uid () get- Request contextReturn Url () add- Attaches data for one element under your namespace;Element Data (int $uid, string $namespace, array $data) $datamust be serializable (scalar, null, or arrays thereof)get- Returns the data attached so far for one element (namespace => data)Element Data (int $uid)
Data attached via add is merged into the JSON payload under
element - namespacing prevents key collisions
between listeners, and _ext is reserved for this purpose (core
frontend-edit keys are never exposed under it). Namespaces must be lowercase
letters, digits and underscores, starting with a letter (e.g. your extension key).
Example:
<?php
declare(strict_types=1);
namespace Vendor\Package\EventListener;
use TYPO3\CMS\Core\Attribute\AsEventListener;
use Xima\XimaTypo3FrontendEdit\Event\FrontendEditDataEnrichmentEvent;
#[AsEventListener(
identifier: 'my-extension/enrich-comment-data',
)]
class EnrichCommentDataListener
{
public function __construct(
protected readonly CommentRepository $commentRepository,
) {}
public function __invoke(FrontendEditDataEnrichmentEvent $event): void
{
// One query for all elements on this page instead of N.
$counts = $this->commentRepository->countByContentElementUids(
$event->getContentElementUids(),
);
foreach ($counts as $uid => $count) {
$event->addElementData($uid, 'my_extension', [
'color' => $count > 0 ? '#ff9800' : '#9e9e9e',
'count' => $count,
]);
}
}
}
On the frontend, render it via register when the element is rendered:
document.addEventListener('xfe:element-rendered', (event) => {
const { uid, payload } = event.detail;
const data = payload.element._ext?.my_extension;
if (!data) return;
window.XimaFrontendEdit.registerBadge(uid, {
html: `<span style="background:${data.color}">${data.count}</span>`,
});
});