Skip to content

Instantly share code, notes, and snippets.

Last active Oct 14, 2021
What would you like to do?
Example code for various TYPO3 v11 features
This Gist contains code examples, related to the talk hold at the TMUG on 11.10.2021.
The slides and further information can be found here:
Note: The Gist contains a couple of additional examples, not shown during the demo.
// The configuration module can be extended by custom providers
// See for reference:
namespace Vendor\Site;
use TYPO3\CMS\Lowlevel\ConfigurationModuleProvider\AbstractProvider;
class CustomConfigurationProvider extends AbstractProvider
* Since we extend from AbstractProvider, we only need to implement getConfiguration(),
* containing the configuration to be displayed as array.
public function getConfiguration(): array
return [
'my-key' => [
'my-sub-key' => 'my-value'
// The corresponding registration in Services.yaml
class: 'Vendor\Site\CustomConfigurationProvider'
- name: 'lowlevel.configuration.module.provider'
identifier: 'customConfiguration'
label: 'Custom configuration'
after: 'httpMiddlewareStacks'
before: 'siteConfiguration'
// In case we just want to display custom global configuration, core's "GlobalVariableProvider" can be used
class: 'TYPO3\CMS\Lowlevel\ConfigurationModuleProvider\GlobalVariableProvider'
- name: 'lowlevel.configuration.module.provider'
identifier: 'customConfiguration'
label: 'My global var'
globalVariableKey: 'MY_GLOBAL_VAR'
// The above will display the contents of $GLOBALS['MY_GLOBAL_VAR']
// Use of PSR-7 request in a custom content object
// See for reference:
namespace Vendor\Site\UserFunctions;
use Psr\Http\Message\ServerRequestInterface;
class CustomContentObject
public function render(string $content, array $configuration, ServerRequestInterface $request): string
return 'You are on page: ' . $request->getAttribute('normalizedParams')->getRequestUri();
// Add the content object to your PAGE
page.2 = USER
page.2.userFunc = Vendor\Site\UserFunctions\CustomContentObject->render
// A custom module controller for a TYPO3 backend module, adding the "Link sharing" button
// See for reference:
namespace Vendor\Site\Backend;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
class CustomModuleController
protected ResponseFactoryInterface $responseFactory;
protected StreamFactoryInterface $streamFactory;
protected ModuleTemplateFactory $moduleTemplateFactory;
public function __construct(
ResponseFactoryInterface $responseFactory,
StreamFactoryInterface $streamFactory,
ModuleTemplateFactory $moduleTemplateFactory
) {
$this->responseFactory = $responseFactory;
$this->streamFactory = $streamFactory;
$this->moduleTemplateFactory = $moduleTemplateFactory;
public function handleRequest(ServerRequestInterface $request): ResponseInterface
// Creating the moduleTemplate instance via the new ModuleTemplateFactory
$moduleTemplate = $this->moduleTemplateFactory->create($request);
// Assigning content to the moduleTemplate
$moduleTemplate->setContent('My module');
// Retrieving the button bar component
$buttonBar = $moduleTemplate->getDocHeaderComponent()->getButtonBar();
// Adding the "share link" button
$button = $buttonBar->makeShortcutButton()
->setDisplayName('Custom Module');
// With ->setCopyUrlToClipboard(false) the sharing button whould not be displayed, but only the bookmark button
// Adding the button to the button bar
// Creating the PSR-7 Response, using PRS-17 factories
return $this->responseFactory->createResponse()->withBody(
// Note: Module needs to be added in ext_tables.php
'routeTarget' => \Vendor\Site\Backend\CustomModuleController::class . '::handleRequest',
'name' => 'web_custom',
'access' => 'user,group',
'iconIdentifier' => 'tx-site-icon',
'labels' => 'LLL:EXT:site/Resources/Private/Language/locallang_custom_module.xlf',
// Note: Since we use DI, but the controller is called via GeneralUtility::makeInstance, we need to make it
// public in the service configuration. This can be done by tagging the service with "backend.controller"
tags: [ 'backend.controller' ]
// Registration of icons via Configuration/Icons.php
// See for reference:
use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider;
return [
'tx-site-icon' => [
'provider' => SvgIconProvider::class,
'source' => 'EXT:site/Resources/Public/Icons/Extension.svg'
Various settings for MFA, see for reference:
1. Hide the "mfa" field in the user settings:
setup.fields.mfaProviders.disabled = 1
2. Require MFA being set up (via globals configuration):
$GLOBALS['TYPO3_CONF_VARS']['BE']['requireMfa'] = 0|1|2|3|4
3. Require MFA for users / user groups (user TSconfig):
auth.mfa.required = 1
4. Define a recommended MFA provider (via globals configuration):
$GLOBALS['TYPO3_CONF_VARS]['BE]['recommendedMfaProvider'] = 'provider-identifier'
5. Define a recommended MFA provider for user / user groups (user TSconfig):
auth.mfa.recommendedProvider = totp
6. Disabled providers for users / user groups (user TSconfig):
auth.mfa.disableProviders := addToList(provider-identifier)
// A couple of new PSR-14 events is available. Furthermore is the "event" tag argument not required anymore, since the event
// is automatically determined, based on the corresponding method argument.
// Example Event listener for the page module, using the "stoppable events" feature of PSR-14
namespace Vendor\Site\EventListener;
use TYPO3\CMS\Backend\View\Event\BeforeSectionMarkupGeneratedEvent;
class PageLayoutEventListener
public function __invoke(BeforeSectionMarkupGeneratedEvent $event): void
$event->setContent('Custom markup for the page module');
public function addAdditionalContent(BeforeSectionMarkupGeneratedEvent $event): void
// This will not be added since the method above - executed beforehand - stops rendering
$event->setContent($event->getContent() . ' - Additional content');
# Registration without "event" tag attribute. Also "method" is only used once, since the first listener uses __invoke()
- name: event.listener
identifier: 'before-section-page-layout'
- name: event.listener
identifier: 'before-section-page-layout-2'
method: 'addAdditionalContent'
Use site configuration values in TCA foreign_table_where
See for reference:
// Configuration/TCA/my_table.php
'columns' => [
'label' => 'Content',
'description' => 'Select a content element'
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'foreign_table' => 'tt_content',
'foreign_table_where' => 'AND {#tt_content}.{#uid} = ###SITE:settings.contentPid###'
// config/sites/my_site.yaml
rootPageId: 1
websiteTitle: 'My website'
contentPid: 11
// Using PSR-7 and PSR-17 in an extbase controller
// See for reference:
// See for reference:
// See for reference:
namespace Vendor\Site\Controller;
use Vendor\Site\Domain\Repository\StoreRepository;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Extbase\Http\ForwardResponse;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class StoreController extends ActionController
protected StoreRepository $storeRepository;
public function __construct(StoreRepository $storeRepository)
// Inject a repository
$this->storeRepository = $storeRepository;
public function listAction(): ResponseInterface
// Fetch records from a repository
$stores = $this->storeRepository->findAll();
// Access PSR-7 request object through ExtbaseRequest, which implements PSR-7
$testParam = $this->request->getQueryParams()['param'] ?? '';
if ($testParam === 'other') {
// Return PSR-7 response, forwarding to another action
return new ForwardResponse('other');
// Assign stores to the View
$this->view->assign('stores', $stores);
// Manually create a PSR-7 response using PSR-17 factories
return $this->responseFactory->createResponse()
// Or, simly use the helper method
// return $this->htmlResponse();
protected function initializeOtherAction(): void
$this->defaultViewObjectName = JsonView::class;
public function otherAction(): ResponseInterface
// In this action, we return the first stores' title as JSON
$this->view->assign('value', [
return $this->jsonResponse();
// Calling the plugin via a custom page type
store = PAGE
store {
typeNum = 100
10 = USER
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
vendorName = Vendor
extensionName = Site
pluginName = Store
controllerName = Store
// Configure the plugin in ext_localconf.php
\Vendor\Site\Controller\StoreController::class => 'list,other'
\Vendor\Site\Controller\StoreController::class => 'list,other'
This file contains links to further code examples in the official changelog
1. TypoScript Condition for page layout
2. Deault values in NewRecordViewHelper
3. Icon overlay in NewContentElementWizard
4. Override TCA field description with page TSconfig
5. TCA description for palettes
6. TCA type "language":
7. TCA type "category":
Also have a look at
This could be used like this:
$GLOBALS['TCA']['my_table']['columns']['categories'] = [
'label' => 'categories',
'config' => [
'type' => 'category',
'treeConfig' => [
'startingPoints' => '2,18'
8. Add buttons to the page module docheader, using the "drawItemHook"
# Allowing widgets to be refreshed
# See for reference:
class: 'TYPO3\CMS\Dashboard\Widgets\DoughnutChartWidget'
$view: '@dashboard.views.widget'
$dataProvider: '@dashboard.provider.myWidgetProvider'
refreshAvailable: true
name: dashboard.widget
identifier: 'myWidget'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment