Feature: #99459 - Respect record type while creating new records
See forge#99459
Description
The "Create new record" component in the backend, which is accessible in the Content > List module, has been enhanced to automatically detect and display all available record types for tables that support sub-schemas (record types). This improvement simplifies creating specific record types and eliminates the need to change the type afterward in the editing form, which could previously lead to invalid record states being stored in the database.
The interface now features automatic record type detection. Tables with multiple record types are automatically expanded to show all available types in a collapsible dropdown interface.
The options to create new pages now also show the different page types
(
doktype) as expandable options when creating new pages "inside" or
"after" an existing page.
To disable direct creation of a specific record type, a new TCA option
['creation is available at
the record type level:
use TYPO3\CMS\Core\Domain\Repository\PageRepository´;
// Disable direct creation of shortcuts
$GLOBALS['TCA']['pages']['types'][(string)PageRepository::DOKTYPE_SHORTCUT]['creationOptions']['enableDirectRecordTypeCreation'] = false;
Individual titles for each record type are automatically picked up from the
type-specific
title configuration in the types section (see
Feature #108027),
falling back to the select item label if no type-specific title is defined.
Additionally, the new PSR-14 event
\TYPO3\
allows for complete customization of the creation links.
Impact
For tables that support sub-schemas (multiple record types), the new record wizard automatically detects all available types and displays them in a collapsible interface. This includes:
- All tables with TCA type fields (such as
sys_orfile_ collection index_)config - The
pagestable with its differentdoktypevalues - Extension tables with custom record types
Note
The collapsible interface keeps the view clear while providing access to all options. Icons and labels are automatically generated for each record type based on the TCA configuration.
The
Modify provides complete control over
the creation link structure, allowing extensions to:
- Add custom record creation options
- Modify existing groups and items
- Override icons, labels, and URLs
- Create entirely custom wizard interfaces
Data Structure
The event works with a nested array structure representing grouped creation links:
[
'content' => [
'title' => 'Content',
'icon' => '<img src="..." />',
'items' => [
'sys_file_collection' => [
'label' => 'File Collection',
'icon' => '<typo3-backend-icon ...>',
'types' => [
'static' => [
'url' => '/typo3/record/edit?edit[sys_file_collection][1]=new&defVals[sys_file_collection][type]=static',
'icon' => '<typo3-backend-icon ...>',
'label' => 'Static File Collection'
],
'folder' => [
'url' => '/typo3/record/edit?edit[sys_file_collection][1]=new&defVals[sys_file_collection][type]=folder',
'icon' => '<typo3-backend-icon ...>',
'label' => 'Folder from Storage'
]
]
]
]
],
'pages' => [
'title' => 'Create New Page',
'icon' => '<typo3-backend-icon ...>',
'items' => [
'inside' => [
'label' => 'Page (inside)',
'icon' => '<typo3-backend-icon ...>',
'types' => [
'1' => [
'url' => '/typo3/record/edit?edit[pages][1]=new&defVals[pages][doktype]=1',
'icon' => '<typo3-backend-icon ...>',
'label' => 'Standard Page'
],
'254' => [
'url' => '/typo3/record/edit?edit[pages][1]=new&defVals[pages][doktype]=254',
'icon' => '<typo3-backend-icon ...>',
'label' => 'Folder'
]
]
]
]
]
]
Event Listener Example
The event provides access to:
$event->grouped- The complete structure of creation linksCreation Links $event->page- The current page's TSconfig arrayTS $event->page- The current page IDId $event->request- The current server request object
This allows for comprehensive customization while maintaining backward compatibility with existing setups.
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\EventListener;
use TYPO3\CMS\Backend\Controller\Event\ModifyNewRecordCreationLinksEvent;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Imaging\IconSize;
final readonly class CustomizeNewRecordWizardEventListener
{
public function __construct(
private IconFactory $iconFactory,
private UriBuilder $uriBuilder,
) {}
#[AsEventListener]
public function __invoke(ModifyNewRecordCreationLinksEvent $event): void
{
// Add a custom creation group
$customGroup = [
'title' => 'Custom Records',
'icon' => $this->iconFactory->getIcon('apps-pagetree-category')->render(),
'items' => [
'tx_myext_domain_model_item' => [
'url' => (string)$this->uriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['tx_myext_domain_model_item' => [$event->pageId => 'new']],
'returnUrl' => $event->request->getAttribute('normalizedParams')->getRequestUri(),
]),
'icon' => $this->iconFactory->getIconForRecord('tx_myext_domain_model_item', []),
'label' => 'Custom Item',
]
]
];
// Add the custom group to the existing structure
$event->groupedCreationLinks['custom'] = $customGroup;
// Modify existing groups, for example, remove specific items
if (isset($event->groupedCreationLinks['system']['items']['sys_template'])) {
unset($event->groupedCreationLinks['system']['items']['sys_template']);
}
// Add custom types to an existing table
if (isset($event->groupedCreationLinks['content']['items']['sys_note'])) {
$event->groupedCreationLinks['content']['items']['sys_note']['types'] = [
'important' => [
'url' => (string)$this->uriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['sys_note' => [$event->pageId => 'new']],
'defVals' => ['sys_note' => ['category' => '1']],
'returnUrl' => $event->request->getAttribute('normalizedParams')->getRequestUri(),
]),
'icon' => $this->iconFactory->getIcon('status-dialog-warning', IconSize::SMALL),
'label' => 'Important Note',
],
'info' => [
'url' => (string)$this->uriBuilder->buildUriFromRoute('record_edit', [
'edit' => ['sys_note' => [$event->pageId => 'new']],
'defVals' => ['sys_note' => ['category' => '0']],
'returnUrl' => $event->request->getAttribute('normalizedParams')->getRequestUri(),
]),
'icon' => $this->iconFactory->getIcon('status-dialog-information', IconSize::SMALL),
'label' => 'Information Note',
]
];
}
}
}