TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:09 +02:00
commit af8cc155b5
6818 changed files with 642608 additions and 0 deletions
@@ -0,0 +1,51 @@
.. include:: /Includes.rst.txt
.. _deprecation-97923-1673529717:
====================================================
Deprecation: #97923 - Deprecate UserFileMountService
====================================================
See :issue:`97923`
Description
===========
The class :php:`\TYPO3\CMS\Core\Resource\Service\UserFileMountService` is not
used anymore within the TYPO3 Core and has been marked deprecated. The class
will finally be removed in TYPO3 v13.
Impact
======
Using the class will raise a deprecation level log entry and will stop
working with TYPO3 v13.
Affected installations
======================
Instances with extensions that use the class are affected.
The extension scanner reports affected extensions.
Migration
=========
Instead of using the class in TCA for an :php:`itemsProcFunc`, the TCA
type `folder` should be used, to improve the usability of selecting a folder.
.. code-block:: php
'identifier' => [
'label' => 'Folder selection',
'config' => [
'type' => 'folder',
'elementBrowserEntryPoints' => [
'_default' => '1:/user_upload/'
]
]
],
.. index:: Backend, TCA, FullyScanned, ext:core
@@ -0,0 +1,162 @@
.. include:: /Includes.rst.txt
.. _deprecation-99120-1670428555:
====================================================
Deprecation: #99120 - Deprecate old TypoScriptParser
====================================================
See :issue:`99120`
Description
===========
To phase out usages of the old TypoScript parser by switching to the
:ref:`new parser approach <breaking-97816-1664800747>`, a couple of classes
and methods have been marked deprecated in TYPO3 v12 that will be
removed in TYPO3 v13:
* Class :php:`\TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser`
* Class :php:`\TYPO3\CMS\Core\Configuration\Loader\PageTsConfigLoader`
* Class :php:`\TYPO3\CMS\Core\Configuration\PageTsConfig`
* Class :php:`\TYPO3\CMS\Core\Configuration\Parser\PageTsConfigParser`
* Event :php:`\TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent`
* Method :php:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getPagesTSconfig()`
The existing main API to retrieve page TSconfig using
:php:`\TYPO3\CMS\Backend\Utility\BackendUtility::getPagesTSconfig()`
and user TSconfig using :php:`$backendUser->getTSConfig()` is kept.
Impact
======
Using one of the above classes will raise a deprecation level log entry and
will stop working with TYPO3 v13.
Affected installations
======================
Instances with extensions that use one of the above classes are affected. The
extension scanner will find usages with a mixture of weak and strong matches
depending on the usage.
Most deprecations are rather "internal" since extensions most likely use the
existing outer API already. Some may be affected when using the
:php:`\TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent` event
or the frontend related method :php:`TypoScriptFrontendController->getPagesTSconfig()`,
though.
Migration
=========
:php:`\TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent`
------------------------------------------------------------------------
This event is consumed by some extensions to modify calculated page TSconfig strings
before parsing. The old event :php:`\TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent`
has been marked as deprecated and will be removed with TYPO3 v13, the new event
:php:`\TYPO3\CMS\Core\TypoScript\IncludeTree\Event\ModifyLoadedPageTsConfigEvent` has been
created with same signature. The TYPO3 v12 Core triggers *both* the old
and the new event, and TYPO3 v13 will stop calling the old event.
Extension that want to stay compatible with both TYPO3 v11 and v12 and prepare v13
compatibility as much as possible should start listening for the new event as well,
and suppress handling of the old event in TYPO3 v12 to not handle things twice.
Example from b13/bolt extension:
Register for both events in Services.yaml:
.. code-block:: yaml
B13\Bolt\TsConfig\Loader:
public: true
tags:
# Remove when TYPO3 v11 compat is dropped
- name: event.listener
identifier: 'add-site-configuration-v11'
event: TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent
method: 'addSiteConfigurationCore11'
# TYPO3 v12 and above
- name: event.listener
identifier: 'add-site-configuration'
event: TYPO3\CMS\Core\TypoScript\IncludeTree\Event\ModifyLoadedPageTsConfigEvent
method: 'addSiteConfiguration'
Handle old event in TYPO3 v11, but skip old event with TYPO3 v12:
.. code-block:: php
use TYPO3\CMS\Core\Configuration\Event\ModifyLoadedPageTsConfigEvent as LegacyModifyLoadedPageTsConfigEvent;
use TYPO3\CMS\Core\TypoScript\IncludeTree\Event\ModifyLoadedPageTsConfigEvent;
class Loader
{
public function addSiteConfigurationCore11(LegacyModifyLoadedPageTsConfigEvent $event): void
{
if (class_exists(ModifyLoadedPageTsConfigEvent::class)) {
// TYPO3 v12 calls both old and new event. Check for class existence of new event to
// skip handling of old event in v12, but continue to work with < v12.
// Simplify this construct when v11 compat is dropped, clean up Services.yaml.
return;
}
$this->findAndAddConfiguration($event);
}
public function addSiteConfiguration(ModifyLoadedPageTsConfigEvent $event): void
{
$this->findAndAddConfiguration($event);
}
protected function findAndAddConfiguration($event): void
{
// Business code
}
}
:php:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getPagesTSconfig()`
--------------------------------------------------------------------------------------
The TYPO3 frontend should usually not need to retrieve backend related page TSconfig.
Extensions using the method should avoid relying on bringing backend related configuration
into frontend scope. However, the TYPO3 Core comes with one place that does this: Class
:php:`\TYPO3\CMS\Frontend\Typolink\DatabaseRecordLinkBuilder` uses page TSconfig related
information in frontend scope. Extensions with similar use cases could have a similar
implementation as done with :php:`DatabaseRecordLinkBuilder->getPageTsConfig()`. Note that
any implementation of this will have to rely on :php:`@internal` usages of the new
TypoScript parser approach, and using this low level API may thus break without
further notice. Extensions are encouraged to cover usages with functional tests to find
issues quickly in case the TYPO3 Core still changes used classes.
:php:`\TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser`
---------------------------------------------------------
In general, extensions probably don't need to use the old :php:`TypoScriptParser`
often: Frontend TypoScript is :ref:`available as request attribute <deprecation-99020-1667911024>`,
page TSconfig should be retrieved using :php:`BackendUtility::getPagesTSconfig()` and
user TSconfig should be retrieved using :php:`$backendUser->getTSConfig()`.
In case extensions want to parse any other strings that follow a TypoScript-a-like syntax,
they can use :php:`\TYPO3\CMS\Core\TypoScript\TypoScriptStringFactory`, or could set up
their own factory using the new parser classes for more complex scenarios. Note that the new parser
approach is still marked :php:`@internal`, using this low level API may thus break without
further notice. Extensions are encouraged to cover usages with functional tests to find
issues quickly in case the TYPO3 Core still changes used classes.
:php:`\TYPO3\CMS\Core\Configuration\PageTsConfig`
-------------------------------------------------
There is little need to use :php:`\TYPO3\CMS\Core\Configuration\PageTsConfig` and their helper
classes :php:`\TYPO3\CMS\Core\Configuration\Loader\PageTsConfigLoader` and
:php:`\TYPO3\CMS\Core\Configuration\Parser\PageTsConfigParser` directly: The main API
in backend context is :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::getPagesTSconfig()`.
See the hint on :php:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->getPagesTSconfig()`
above for notes on how to migrate usages in frontend context.
.. index:: PHP-API, TSConfig, TypoScript, FullyScanned, ext:core
@@ -0,0 +1,55 @@
.. include:: /Includes.rst.txt
.. _deprecation-99416-1671746489:
====================================================================
Deprecation: #99416 - Various doctype related properties and methods
====================================================================
See :issue:`99416`
Description
===========
Due to the introduction of a unified definition of the DocType that should render
HTML, XML or XHTML-compliant content either in TYPO3 frontend rendering or
backend rendering, various methods and properties have been marked as
deprecated, as they are superfluous now:
* :php:`\TYPO3\CMS\Core\Page\PageRenderer->setRenderXhtml()`
* :php:`\TYPO3\CMS\Core\Page\PageRenderer->getRenderXhtml()`
* :php:`\TYPO3\CMS\Core\Page\PageRenderer->setMetaCharsetTag()`
* :php:`\TYPO3\CMS\Core\Page\PageRenderer->getMetaCharsetTag()`
* :php:`\TYPO3\CMS\Core\Page\PageRenderer->setCharSet()`
* :php:`\TYPO3\CMS\Core\Page\PageRenderer->getCharSet()`
* :php:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->xhtmlDoctype`
* :php:`\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->xhtmlVersion`
Impact
======
Calling one of the methods or accessing / writing one of the properties mentioned
will trigger a PHP deprecation message.
Affected installations
======================
TYPO3 installations with custom extensions reading or writing these properties or
methods directly in PHP, which is unlikely.
Migration
=========
Use :php:`PageRenderer->setDocType()` to manipulate the output in
a programmatic way, or use :php:`PageRenderer->getDocType()` to read the
current doctype — for example "is the current page HTML5 compliant".
Various TypoScript properties will instruct the :php:`PageRenderer` as before,
there is no need to use other configuration options. However, it is recommended to use
:typoscript:`config.doctype` in favor of :typoscript:`config.xhtmlDoctype` in
TypoScript as it considers more possible options.
.. index:: Frontend, TypoScript, FullyScanned, ext:frontend
@@ -0,0 +1,67 @@
.. include:: /Includes.rst.txt
.. _deprecation-99454-1672842347:
=================================================================================
Deprecation: #99454 - Restore visibility for soft hyphens and non-breaking spaces
=================================================================================
See :issue:`99454`
Description
===========
Non-breaking spaces and soft hyphens are now visible in
the rich-text editor to help the editor to identify them visually.
Keyboard shortcuts are now working for non-breaking spaces
and soft hyphens and use more common defaults:
* :kbd:`ctrl` + :kbd:`shift` + :kbd:`space` for non-breaking space
* :kbd:`ctrl` + :kbd:`shift` + :kbd:`dash` for soft hyphen
The :js:`SoftHyphen` plugin for the CKEditor is now deprecated and
replaced with a new whitespace plugin that handles
non-breaking spaces and soft hyphens. Loading the
:js:`SoftHyphen` will trigger a console warning.
Impact
======
Including the :js:`SoftHyphen` plugin will trigger a deprecation warning.
Affected installations
======================
All installations that include the :js:`SoftHyphen` plugin manually.
Migration
=========
Replace the module to resolve the deprecation.
Before
------
.. code-block:: yaml
editor:
config:
importModules:
- '@typo3/rte-ckeditor/plugin/soft-hyphen.js'
After
-----
.. code-block:: yaml
editor:
config:
importModules:
- { module: '@typo3/rte-ckeditor/plugin/whitespace.js', exports: ['Whitespace'] }
.. index:: Backend, JavaScript, RTE, NotScanned, ext:rte_ckeditor
@@ -0,0 +1,59 @@
.. include:: /Includes.rst.txt
.. _deprecation-99519-1673444609:
==============================================================
Deprecation: #99519 - Deprecated BackendUtility::getFuncMenu()
==============================================================
See :issue:`99519`
Description
===========
Method :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::getFuncMenu()` has
been marked deprecated and should no longer be used.
Impact
======
Calling the method will raise a deprecation level log error and will
stop working with TYPO3 v13.
Affected installations
======================
The method may be used in extensions that add backend modules. The
extension scanner finds usages with a strong match.
Migration
=========
:php:`BackendUtility::getFuncMenu()` is a helper method that renders a
select drop down and is typically used to trigger a `GET` request when
the user selects an option.
In general, such HTML should not be generated by PHP, but by Fluid templating.
The method is thus typically used by old school backend modules that have not
or only partially been transferred to Fluid, improving the controller-view
separation.
The most simple and ugly migration is to copy the method to an own controller
that consumes the method. The better solution is to add the arguments as variables
to the Fluid template and render the dropdown in Fluid. This should be a pretty
straight transition as well and typically avoids another :html:`<f:format.raw>`
ViewHelper usage.
Note that requests send by these dropdowns should switch from GET to POST in
case they change server state (for example, changing records) along the way: State changing
requests should be restricted to `POST` as an additional security measure, and to
not violate the HTTP protocol. The TYPO3 Core comes with more and more examples
on how to handle this properly. For instance all dropdowns and checkbox toggles
of the `tstemplate` extension (:guilabel:`Site Management > TypoScript` backend module)
have been changed to do this and can be studied on how to trigger immediate
`POST` actions when clicking such elements.
.. index:: Backend, PHP-API, FullyScanned, ext:backend
@@ -0,0 +1,50 @@
.. include:: /Includes.rst.txt
.. _deprecation-99523-1673454068:
========================================================
Deprecation: #99523 - Deprecate type="none" pass_content
========================================================
See :issue:`99523`
Description
===========
The TCA option :php:`pass_content` for :php:`type="none"` fields has been
marked deprecated in TYPO3 v12 and will be removed with v13.
Impact
======
Using the option should be avoided and has no impact anymore.
Instances with field configurations, section `config` of :php:`type="none"`
having key :php:`pass_content` will trigger a deprecation warning during
TCA cache warmup.
Affected installations
======================
The :php:`type="none"` TCA field is a rarely used type, its main purpose is
to allow virtual fields (a field without corresponding database column).
Instances are affected when the backend "lowlevel" search
in :php:`$GLOBALS['TCA']` for "pass_content" reveals matches.
Migration
=========
The :php:`pass_content=true` option was documented to not :php:`htmlspecialchars()`
the value. This is an edge case anyways, since the :php:`type="none"` is designed
to not have a database field at all, so there is usually no value. Additionally,
the current behavior still applies :php:`htmlspecialchars()` to the value. This has
not been fixed in TYPO3 v11 and v12 since it may open a security issue with existing
instances.
Instances that need non-HTML escaped output with :php:`type="none"` should register an
own :php:`renderType` element for the field, as documented in
the :ref:`TYPO3 explained FormEngine chapter<t3coreapi:FormEngine-Rendering-NodeFactory>`.
.. index:: Backend, TCA, NotScanned, ext:backend
@@ -0,0 +1,46 @@
.. include:: /Includes.rst.txt
.. _deprecation-99531-1673606839:
===============================================================
Deprecation: #99531 - Backwards-compatible language key mapping
===============================================================
See :issue:`99531`
Description
===========
Before TYPO3 v4.0, TYPO3 had inconsistencies in its language keys, such as "ja" (= Japan)
instead of "jp" (= Japanese), which was still applicable. However, the old language keys
have not been in use for TYPO3's built-in translation servers.
In recent years, it was not even possible to use these keys for custom label files anymore.
However, the mapping was still used to detect the language of the user agent,
primarily for the backend login screen when no language was detected.
For this reason, the method :php:`Locales->getIsoMapping()` has been deprecated.
Impact
======
Calling the method above will trigger a PHP deprecation warning.
Affected installations
======================
TYPO3 installations which have been maintained for more than 15 years, still
using this method, or still using this legacy language keys.
Migration
=========
Migrate to the official language keys / locales by renaming the language files.
It is highly unlikely that the outdated language keys worked in the past major
versions of TYPO3.
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,40 @@
.. include:: /Includes.rst.txt
.. _deprecation-99558-1673887807:
===========================================================
Deprecation: #99558 - Deprecate PageRepository->getExtURL()
===========================================================
See :issue:`99558`
Description
===========
The method :php:`\TYPO3\CMS\Core\Domain\Repository\PageRepository->getExtURL()`
has been marked as deprecated and should not be used any longer.
Impact
======
Calling the method triggers a deprecation level log message since
TYPO3 v12 and will stop working in v13.
Affected installations
======================
:php:`PageRepository->getExtURL()` is a detail method and relatively unlikely
to be used by extensions. The extension scanner will find affected code places.
Migration
=========
The method has been discontinued and there is no direct migration.
If needed, the most simple solution is to copy the method to an extensions
code base and maintain it within the extension.
.. index:: Backend, PHP-API, FullyScanned, ext:core
@@ -0,0 +1,58 @@
.. include:: /Includes.rst.txt
.. _deprecation-99564-1673958788:
==================================================================
Deprecation: #99564 - Deprecated BackendUtility::getDropdownMenu()
==================================================================
See :issue:`99564`
Description
===========
Method :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::getDropdownMenu()` has
been marked deprecated and should no longer be used.
Impact
======
Calling the method will raise a deprecation level log error and will
stop working with TYPO3 v13.
Affected installations
======================
The method may be used in extensions that add backend modules. The
extension scanner finds usages with a strong match.
Migration
=========
:php:`BackendUtility::getDropdownMenu()` is a helper method that renders a
select dropdown and is typically used to trigger a `GET` request when
the user selects an option.
In general, such HTML should not be generated by PHP, but by Fluid templating.
The method is thus typically used by old school backend modules that have not
or only partially been transferred to Fluid, improving the controller-view
separation.
The most simple and ugly migration is to copy the method to an own controller
that consumes the method. The better solution is to add the arguments as variables
to the Fluid template and render the dropdown in Fluid. This should be a pretty
straight transition as well and typically avoids another :html:`<f:format.raw>`
ViewHelper usage.
Note that requests send by these dropdowns should switch from `GET` to `POST` in
case they change the server state (e. g. changing records) along the way: State changing
requests should be restricted to POST as an additional security measure, and to
not violate the HTTP protocol. The TYPO3 Core comes with more and more examples
on how to handle this properly. For instance, all drop downs and checkbox toggles
of the `tstemplate` extension (:guilabel:`Site Management > TypoScript` backend module)
have been changed to do this and can be studied on how to trigger immediate
`POST` actions when clicking such elements.
.. index:: Backend, PHP-API, FullyScanned, ext:backend
@@ -0,0 +1,59 @@
.. include:: /Includes.rst.txt
.. _deprecation-99579-1673983578:
====================================================
Deprecation: #99579 - BackendUtility::getFuncCheck()
====================================================
See :issue:`99579`
Description
===========
The method :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::getFuncCheck()` has
been marked as deprecated and should not be used any longer.
Impact
======
Calling the method will raise a deprecation level log error and will
stop working with TYPO3 v13.
Affected installations
======================
The method may be used in extensions that add backend modules. The
extension scanner finds usages with a strong match.
Migration
=========
:php:`BackendUtility::getFuncCheck()` is a helper method that renders a
select dropdown and is typically used to trigger a `GET` request when
the user selects an option.
In general, such HTML should not be generated by PHP, but by Fluid templating.
The method is thus typically used by old school backend modules that have not
or only partially been transferred to Fluid, improving the controller-view
separation.
The most simple and ugly migration is to copy the method to an own controller
that consumes the method. The better solution is to add the arguments as variables
to the Fluid template and render the dropdown in Fluid. This should be a pretty
straight transition as well and typically avoids another :html:`<f:format.raw>`
ViewHelper usage.
Note that requests send by these drop-downs should switch from `GET` to `POST` in
case they change the server state (e. g. changing records) along the way: State changing
requests should be restricted to POST as an additional security measure, and to
not violate the HTTP protocol. The TYPO3 Core comes with more and more examples
on how to handle this properly. For instance, all dropdowns and checkbox toggles
of the `tstemplate` extension (:guilabel:`Site Management > TypoScript` backend module)
have been changed to do this and can be studied on how to trigger immediate
`POST` actions when clicking such elements.
.. index:: Backend, PHP-API, FullyScanned, ext:backend
@@ -0,0 +1,80 @@
.. include:: /Includes.rst.txt
.. _deprecation-99586-1673990657:
==================================================================
Deprecation: #99586 - Registration of upgrade wizards via $GLOBALS
==================================================================
See :issue:`99586`
Description
===========
Registration of upgrade wizards via
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']`,
usually placed in an extension's :file:`ext_localconf.php` has been deprecated
in favor of the :ref:`new service tag <feature-99586-1673989775>`.
Additionally, the :php:`\TYPO3\CMS\Install\Updates\UpgradeWizardInterface`, which all upgrade wizards must
implement, does no longer require the :php:`getIdentifier()` method. TYPO3 does
not use this method anymore since an upgrade wizard's identifier is now
defined using the new service tag.
Impact
======
Upgrade wizards, registered via
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']`
will no longer be recognized in TYPO3 v13.
The definition of the :php:`getIdentifier()` method has no effect anymore.
Affected installations
======================
All installations registering custom upgrade wizards using
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']`.
All installations implementing the :php:`getIdentifier()` method in their
upgrade wizards.
Migration
=========
Use the new service tag to register custom upgrade wizards and remove the
registration via
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']`.
Before
~~~~~~
.. code-block:: php
:caption: EXT:my_extension/ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']['myUpgradeWizard']
= \MyVendor\MyExtension\Updates\MyUpgradeWizard::class;
After
~~~~~
.. code-block:: php
:caption: EXT:my_extension/Classes/Updates/MyUpgradeWizard.php
namespace MyVendor\MyExtension\Updates;
use TYPO3\CMS\Install\Attribute\UpgradeWizard;
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
#[UpgradeWizard('myUpgradeWizard')]
class MyUpgradeWizard implements UpgradeWizardInterface
{
}
Drop any :php:`getIdentifier()` method in custom upgrade wizards.
.. index:: Backend, PHP-API, FullyScanned, ext:install
@@ -0,0 +1,56 @@
.. include:: /Includes.rst.txt
.. _deprecation-99588-1673995832:
=========================================================
Deprecation: #99588 - Public Properties in PageRepository
=========================================================
See :issue:`99588`
Description
===========
One of TYPO3's main classes for fetching page records and content in the TYPO3 frontend is
:php:`\TYPO3\CMS\Core\Domain\Repository\PageRepository` previously known as `sys_page`.
This class has been around for a long time, and due to several improvements in TYPO3 v8
with Doctrine DBAL and in TYPO3 v9 with Context API and defining state via the Context API
and multiple instances of this class, it is not necessary to define public properties to modify
the behaviour of this class anymore.
For this reason, the following public properties are marked deprecated:
* :php:`\TYPO3\CMS\Core\Domain\Repository\PageRepository->where_hid_del`
* :php:`\TYPO3\CMS\Core\Domain\Repository\PageRepository->where_groupAccess`
Impact
======
Setting or reading these properties via PHP code in custom extensions will
trigger a PHP deprecation notice, however they continue to work in
TYPO3 v12.
Affected installations
======================
TYPO3 installations with custom extensions making use of these properties,
which is highly unlikely.
Migration
=========
It is recommended to migrate towards creating custom instances of this class with custom
contexts (for example, to show hidden records, or to use other workspace constraints),
as this is already done in TYPO3 Core since various versions.
If it is needed to build queries with the common restrictions, it is recommended to use
the API methods of this class, where most of the methods already have a
`$disableGroupAccessCheck` argument, or `enableFields()` which allows to return
common constraints, or to use the :php:`FrontendRestrictionContainer` when building
custom SQL queries with TYPO3's database layer directly.
.. index:: Frontend, PHP-API, FullyScanned, ext:core
@@ -0,0 +1,38 @@
.. include:: /Includes.rst.txt
.. _deprecation-99592-1674033859:
==================================================
Deprecation: #99592 - Deprecated "flushByTag" hook
==================================================
See :issue:`99592`
Description
===========
The hook :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/cache/frontend/class.t3lib_cache_frontend_abstractfrontend.php']['flushByTag']`
has been marked as deprecated.
It is recommended to implement a custom cache
frontend using :ref:`Frontend API<t3coreapi:caching-frontend>` when custom cache
functionality is required.
Impact
======
Any hook implementation registered will not be executed anymore
in TYPO3 v13. The extension scanner will report possible usages.
Affected installations
======================
All installations making use of the deprecated hook.
Migration
=========
Migrate corresponding cache functionality in the :php:`flushByTag()` method of your
own cache frontend implementation.
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,67 @@
.. include:: /Includes.rst.txt
.. _deprecation-99615-1674056024:
=================================================
Deprecation: #99615 - GeneralUtility::_GPmerged()
=================================================
See :issue:`99615`
Description
===========
The method :php:`\TYPO3\CMS\Core\Utility\GeneralUtility::_GPmerged()` has
been marked as deprecated and should not be used any longer.
Modern code should access `GET` and `POST` data from the PSR-7
:php:`\Psr\Http\Message\ServerRequestInterface`, and should avoid accessing
super-globals :php:`$_GET` and :php:`$_POST` directly. This helps creating
controller classes with a clean architecture. Some
:php:`\TYPO3\CMS\Core\Utility\GeneralUtility` related helper methods like
:php:`_GPmerged()` violate this, using them is considered a technical debt.
They are being phased out.
Impact
======
Calling the method will raise a deprecation level log error and will
stop working with TYPO3 v13.
Affected installations
======================
Instances with extensions using :php:`GeneralUtility::_GPmerged()` are affected.
The extension scanner will find usages with a strong match.
Migration
=========
:php:`GeneralUtility::_GPmerged()` is a helper method that retrieves
request parameters and returns the value, while `POST` parameters take
precedence over `GET` parameters, if both exist.
The same result can be achieved by retrieving arguments from the request object.
An instance of the PSR-7 :php:`ServerRequestInterface` is handed over to
controllers by TYPO3 Core's PSR-15 :php:`\TYPO3\CMS\Core\Http\RequestHandlerInterface`
and middleware implementations, and is available in various related scopes
like the frontend :php:`\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer`.
Typical code:
.. code-block:: php
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\ArrayUtility;
// Before
$getMergedWithPost = GeneralUtility::_GPmerged('tx_scheduler');
// After
$getMergedWithPost = $request->getQueryParams()['tx_scheduler'];
ArrayUtility::mergeRecursiveWithOverrule($getMergedWithPost, $request->getParsedBody()['tx_scheduler']);
.. index:: Backend, PHP-API, FullyScanned, ext:backend
@@ -0,0 +1,66 @@
.. include:: /Includes.rst.txt
.. _deprecation-99633-1674121794:
=============================================
Deprecation: #99633 - GeneralUtility::_POST()
=============================================
See :issue:`99633`
Description
===========
The method :php:`\TYPO3\CMS\Core\Utility\GeneralUtility::_POST()` has
been marked deprecated and should not be used any longer.
Modern code should access GET and POST data from the PSR-7
:php:`\Psr\Http\Message\ServerRequestInterface`, and should avoid accessing
super-globals :php:`$_GET` and :php:`$_POST`
directly. This will avoid future side-effects when using sub-requests. Some
:php:`GeneralUtility` related helper methods like :php:`_POST()` violate this,
using them is considered a technical debt. They are being phased out.
Impact
======
Calling the method from PHP code will trigger a PHP deprecation notice.
Affected installations
======================
TYPO3 installations with third-party extensions using :php:`GeneralUtility::_POST()`
are affected. This typically occurs in TYPO3 installations which
have been migrated to latest TYPO3 Core versions and
haven't been adapted properly yet.
The extension scanner will find usages with a strong match.
Migration
=========
:php:`GeneralUtility::_POST()` is a helper method that retrieves
incoming HTTP body parameters / `POST` parameters and returns the value.
The same result can be achieved by retrieving arguments from the request object.
An instance of the PSR-7 :php:`ServerRequestInterface` is handed over to
controllers by TYPO3 Core's PSR-15 :php:`\TYPO3\CMS\Core\Http\RequestHandlerInterface`
and middleware implementations, and is available in various related scopes
like the frontend :php:`\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer`.
Typical code:
.. code-block:: php
use TYPO3\CMS\Core\Utility\GeneralUtility;
// Before
$value = GeneralUtility::_POST('tx_scheduler');
// After
$value = $request->getParsedBody()['tx_scheduler']);
.. index:: Backend, PHP-API, FullyScanned, ext:backend
@@ -0,0 +1,44 @@
.. include:: /Includes.rst.txt
.. _deprecation-99638-1674127318:
===================================================
Deprecation: #99638 - Environment::getBackendPath()
===================================================
See :issue:`99638`
Description
===========
TYPO3's backend path `/typo3` is currently resolved statically in
:php:`Environment::getBackendPath()` to return the full path to the
backend entrypoint.
However, as TYPO3's code base is evolving, the usages to the hardcoded path have been reduced
and the functionality is now migrated into a new :php:`BackendEntryPointResolver` class,
which allows for dynamically adjusting the entry point in the future.
Impact
======
Calling the method will trigger a PHP deprecation warning.
Affected installations
======================
TYPO3 installations with custom extensions using the method in PHP code.
Migration
=========
Check for the extension scanner, and see if the code is necessary, or if any alternative,
such as the :php:`\TYPO3\CMS\Core\Routing\BackendEntryPointResolver`
or :php:`\TYPO3\CMS\Core\Http\NormalizedParams` might be better
suited as third-party extensions should not rely on the hard-coded paths to resources from
:file:`typo3/*` anymore.
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,48 @@
.. include:: /Includes.rst.txt
.. _deprecation-99650-1674205203:
=======================================================================
Deprecation: #99650 - Global Request object usage in Extbase UriBuilder
=======================================================================
See :issue:`99650`
Description
===========
Usage of the global request object (:php:`$GLOBALS['TYPO3_REQUEST']`) as
fallback in the EXT:extbase :php:`\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder`
has been deprecated and will be removed in TYPO3 v13. The :php:`UriBuilder` will
then solely rely on a locally set request object.
Impact
======
Using the :php:`UriBuilder` class of Extbase without a local
request object will trigger a PHP deprecation warning.
Additionally, when using the :php:`UriBuilder` to build frontend URLs, the
current content object is required. It is initialized from the handed in local
request object. This means, in case extensions do set the request object,
a automatic fallback is applied in v12, triggering a PHP deprecation warning, as
it will be removed in v13, too.
Affected installations
======================
TYPO3 installations with custom extensions initializing the :php:`UriBuilder`
without handing in a request object and using it to build URIs.
Migration
=========
Make sure to call :php:`setRequest($request)` before using the
:php:`UriBuilder`, when no other component has done this already.
Using ViewHelpers will not trigger the warning, as the TYPO3 Core ensures
the proper setup.
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,49 @@
.. include:: /Includes.rst.txt
.. _deprecation-99685-1674497039:
================================================================
Deprecation: #99685 - PageRenderer::removeLineBreaksFromTemplate
================================================================
See :issue:`99685`
Description
===========
The following methods have been marked as deprecated and will be removed
in TYPO3 v13:
* :php:`\TYPO3\CMS\Core\Page\PageRenderer::enableRemoveLineBreaksFromTemplate()`
* :php:`\TYPO3\CMS\Core\Page\PageRenderer::disableRemoveLineBreaksFromTemplate()`
* :php:`\TYPO3\CMS\Core\Page\PageRenderer::getRemoveLineBreaksFromTemplate()`
The methods provide a means to remove line break characters from the rendered output,
what would reduce the size of the response. There are better options available nowadays
though and no need to rely on a static code replacement.
Impact
======
Using the methods will raise a deprecation level log entry and will stop
working with TYPO3 v13.
Affected installations
======================
Instances with extensions that call these methods are affected.
The extension scanner reports shows usages found.
Migration
=========
These methods only remove linebreaks from the rendered HTML output. They are not
much use in terms of reducing response size. Migrate to a proper output
optimization tool like `tidy <https://www.html-tidy.org/>`__.
All calls to the deprecated messages should be removed from the codebase.
.. index:: Backend, TCA, FullyScanned, ext:core
@@ -0,0 +1,39 @@
.. include:: /Includes.rst.txt
.. _deprecation-99717-1674654675:
=========================================================================
Deprecation: #99717 - Deprecated "modifyBlindedConfigurationOptions" hook
=========================================================================
See :issue:`99717`
Description
===========
The hook :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Lowlevel\Controller\ConfigurationController']['modifyBlindedConfigurationOptions']`
has been deprecated in favor of the new PSR-14
:php:`\TYPO3\CMS\Lowlevel\Event\ModifyBlindedConfigurationOptionsEvent`,
which acts as a direct replacement.
Impact
======
Using the hook will trigger a deprecation log entry and any hook
implementation registered will not be executed anymore in TYPO3 v13.
Affected installations
======================
All installations using the deprecated hook. The extension scanner
will report possible usages.
Migration
=========
Use the :ref:`PSR-14 event <feature-99717-1674654720>` as a direct replacement.
.. index:: Backend, LocalConfiguration, PHP-API, FullyScanned, ext:lowlevel
@@ -0,0 +1,44 @@
.. include:: /Includes.rst.txt
.. _deprecation-99811-1675447357:
============================================================
Deprecation: #99811 - Deprecate JavaScript bootstrap tooltip
============================================================
See :issue:`99811`
Description
===========
Bootstrap-related backend tooltips initiated with
:html:`data-bs-toggle="tooltip"` together with the core
JavaScript class :js:`typo3/backend/tooltip.js` have been marked
as deprecated and should not be used anymore.
Impact
======
Loading :js:`typo3/backend/tooltip.js` in a backend-related module
will trigger a :js:`console.warn()`. The module will vanish in TYPO3 v13.
Affected installations
======================
Instances with extensions that add backend modules using the bootstrap-related
tooltips plugin may be affected. A typical sign for this is
using the :html:`data-bs-toggle="tooltip"` attribute on elements, loading the
JavaScript module :js:`typo3/backend/tooltip.js` and calling :js:`Tooltip.initialize()`.
Migration
=========
Some parts of the Core will fall back to the :html:`title` attribute for now. However,
both the bootstrap tooltips as well as the title attribute raise accessibility
concerns. See `MDN <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title#accessibility_concerns>`_
for more information on this. The Core will continue to improve the situation.
.. index:: Backend, JavaScript, NotScanned, ext:backend
@@ -0,0 +1,27 @@
.. include:: /Includes.rst.txt
.. _feature-77072-1671089957:
==============================================================================
Feature: #97390 - Use password policy for backend user password in ext:install
==============================================================================
See :issue:`77072`
Description
===========
The password used to create the backend user during install (GUI and setup
command) now considers the configurable password policy introduced in
:ref:`#97388 <feature-97388>`.
Impact
======
The globally configured password policy is now taken into account
when the backend user is created during the install process.
For each violation of the password policy a message will be
displayed to the user (GUI and setup command).
.. index:: Backend, ext:install
@@ -0,0 +1,60 @@
.. include:: /Includes.rst.txt
.. _feature-86913-1673955088:
======================================================================================
Feature: #86913 - Automatic support for language files of languages with region suffix
======================================================================================
See :issue:`86913`
Description
===========
TYPO3's native support for label files - that is: translatable text for system
labels such as from plugins, and for texts within TYPO3 backend - supports over
50 languages. Languages are identified by their "language key" of the ISO 639-1
standard, which also allows the use of a region-specific language. This happens
mostly in countries/regions that have a variation of the language, such
as "en-US" for American English, or "de-CH" for the German language
in Switzerland.
To support these region-specific language keys, which are composed of ISO 639-1
and ISO 3166-1 and separated with `-`, TYPO3 integrators had to configure the
additional language manually to translate region-specific terms.
Common examples are "Behavior" (American English) vs. "Behaviour"
(British English), or "Offerte" (Swiss German) vs. "Angebot" (German),
where all labels except a few terms should stay the same.
Impact
======
TYPO3 now allows integrators to use a custom label file with the
locale prefix :file:`de_CH.locallang.xlf` in an extension next to
:file:`de.locallang.xlf` and :file:`locallang.xlf`
(default language English).
When integrators then use `de-CH` within their site configuration, TYPO3
first checks if a term is available in the translation file :file:`de_CH.locallang.xlf`,
and then automatically falls back to the non-region-specific `de`
translation file :file:`de.locallang.xlf` without any further configuration to
TYPO3.
Previously, such region-specific locales had to be configured via:
.. code-block:: php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['localization']['locales']['user'] = [
'de-CH' => 'German (Switzerland)',
];
The same fallback functionality also works when overriding labels via TypoScript:
.. code-block:: typoscript
plugin.tx_myextension._LOCAL_LANG.de = Angebot
plugin.tx_myextension._LOCAL_LANG.de-CH = Offerte
.. index:: LocalConfiguration, TypoScript, ext:core
@@ -0,0 +1,61 @@
.. include:: /Includes.rst.txt
.. _feature-88137-1673993076:
========================================================================
Feature: #88137 - Multi-level fallback for content in frontend rendering
========================================================================
See :issue:`88137`
Description
===========
TYPO3's site handling was introduced in TYPO3 v9 and allows to define a
"fallback type".
A fallback type allows to define the behavior of how pages and the content
should be fetched from the database when rendering a page in the frontend.
The option `strict` only renders content which was explicitly translated or
created in the defined language, and keeps the sorting behavior of the
default language.
The option `free` does not consider the default language or its sorting,
and only fetches directly content of the given language ID.
The option `fallback` allows to define a fallback chain of languages.
If a certain page is not available in the given language, TYPO3
first checks the fallback chain if a page is available in one of the languages
in the fallback chain.
A common scenario is this:
* German (Austria) - Language = 2
* German (Germany) - Language = 1
* English (Default) - Language = 0
TYPO3 now can deal with the language chain in fallback mode not only for pages,
but also for any kind of content.
Impact
======
When working in a scenario with `fallback` and multiple languages in the fallback
chain, TYPO3 now checks for each content if the target language is available,
and then checks for the same content if it is translated in the language of the
fallback chain (example above in "German (Germany)"), before falling back to
the default language - which was the behavior until now.
The language chain processing works with fallback mode (a.k.a. "overlays in mixed mode"),
both in TypoScript and Extbase code. Under the hood, the method
:php:`PageRepository->getLanguageOverlay()` is responsible for the chaining.
Current limitations:
* Content fallback only works in `fallbackType=fallback`
* Content fallback always stops at the default language (as this was the
previous behavior)
.. index:: Frontend, PHP-API, TypoScript, ext:core
@@ -0,0 +1,30 @@
.. include:: /Includes.rst.txt
.. _feature-92517-1671616097:
==============================================================
Feature: #92517 - Custom namespace for Extbase plugin enhancer
==============================================================
See :issue:`92517`
Description
===========
The Extbase plugin enhancer for frontend routing allows to either set `extension`
and `plugin` OR to set `namespace`. If `extension` and `plugin` were given,
those were used.
However, the `namespace` option is automatically constituted by the extension and
plugin options if it was not set intentionally. It is mainly used when overriding
the custom extension and plugin options with a custom (usually shortened) namespace,
so that the `namespace` is now always respected and preferred if all three options
are set.
Impact
======
If all of `namespace` and `extension` and `plugin` options are configured,
the namespace option is now preferred within the Extbase plugin enhancer.
.. index:: Frontend, ext:frontend
@@ -0,0 +1,27 @@
.. include:: /Includes.rst.txt
.. _feature-97392-1672220371:
================================================================================
Feature: #97392 - Use password policy for new admin users created in ext:install
================================================================================
See :issue:`97392`
Description
===========
The password for a new administrative backend user created using EXT:install
now considers the configurable password policy introduced by
:ref:`#97388 <feature-97388>`.
Impact
======
The global password policy is now taken into account when a
new administrative backend user is created using EXT:install.
Password policy requirements are shown below the password field and a message
is shown, if the new password does not meet the password policy requirements.
.. index:: Backend, ext:install
@@ -0,0 +1,266 @@
.. include:: /Includes.rst.txt
.. _feature-97700-1672214769:
====================================================================
Feature: #97700 - Adopt Symfony Messenger as a message bus and queue
====================================================================
See :issue:`97700`
Description
===========
This feature provides a basic implementation of a message bus based on the
`Symfony Messenger component <https://symfony.com/doc/current/messenger.html>`__.
For backwards compatibility, the default implementation uses the synchronous
transport. This means that the message bus will behave exactly as before, but it
will be possible to switch to a different (async) transport on a per-project
base. To offer asynchronicity, the feature also provides a transport implementation
based on the Doctrine DBAL messenger transport from Symfony and a basic
implementation of a consumer command.
As an example, the workspace :class:`StageChangeNotification` has been rebuilt as a
message and corresponding handler.
"Everyday" usage - as a developer
---------------------------------
Dispatch a message
~~~~~~~~~~~~~~~~~~
- Add a PHP class for your message object (arbitrary PHP class)
(:php:`DemoMessage`)
.. code-block:: php
<?php
namespace TYPO3\CMS\Queue\Message;
final class DemoMessage
{
public function __construct(public readonly string $content)
{
}
}
- Inject :php:`\Symfony\Component\Messenger\MessageBusInterface` into your class
- Call :php:`dispatch()` method with a message as argument
.. code-block:: php
public function __construct(private readonly MessageBusInterface $bus)
{
}
public function yourMethod(): void
{
// ...
$this->bus->dispatch(new DemoMessage('test'));
// ...
}
Register a handler
~~~~~~~~~~~~~~~~~~
Use a tag to register a handler. Use before/after to define order.
Define handled message by argument type reflection or by key `message`.
.. code-block:: php
namespace TYPO3\CMS\Queue\Handler;
use TYPO3\CMS\Queue\Message\DemoMessage;
class DemoHandler
{
public function __invoke(DemoMessage $message): void
{
// do something with $message
}
}
.. code-block:: yaml
TYPO3\CMS\Queue\Handler\DemoHandler:
tags:
- name: 'messenger.message_handler'
TYPO3\CMS\Queue\Handler\DemoHandler2:
tags:
- name: 'messenger.message_handler'
before: 'TYPO3\CMS\Queue\Handler\DemoHandler'
Everyday Usage - as a sysadmin/integrator
-----------------------------------------
By default, the system behaves as before. This means that the message bus
uses the synchronous transport and all messages are handled immediately.
To benefit from the message bus, it is recommended to switch to an asynchronous
transport. Using asynchronous transports increases the resilience of the system
by decoupling external dependencies even further.
The TYPO3 Core currently provides an asynchronous transport based on the
Doctrine DBAL messenger transport. This transport is configured to use the
default TYPO3 database connection. It is pre-configured and can be used
by changing the settings in :file:`config/settings.php`:
.. code-block:: php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['messenger']['routing']['*'] = 'doctrine';
This will route all messages to the asynchronous transport.
If you are using the Doctrine transport, make sure to take care of running the
consume command (see below).
Async message handling - The consume command
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run the command :bash:`./bin/typo3 messenger:consume <receiver-name>` to consume messages.
By default, you should run `./bin/typo3 messenger:consume doctrine`. The command is a
slimmed-down wrapper for the Symfony command `messenger:consume`, it only provides
the basic consumption functionality. As this command is running as a worker,
it is stopped after 1 hour to avoid memory leaks. The command should therefore
be run from a service manager like `systemd` to automatically restart it after
the command exits due to the time limit.
Create a service via :file:`/etc/systemd/system/typo3-message-consumer.service`:
.. code-block:: ini
[Unit]
Description=Run the TYPO3 message consumer
Requires=mariadb.service
After=mariadb.service
[Service]
Type=simple
User=www-data
Group=www-data
ExecStart=/usr/bin/php8.1 /var/www/myproject/vendor/bin/typo3 messenger:consume doctrine --exit-code-on-limit 133
# Generally restart on error
Restart=on-failure
# Restart on exit code 133 (which is returned by the command when limits are reached)
RestartForceExitStatus=133
# ..but do not interpret exit code 133 as an error (as it's just a restart request)
SuccessExitStatus=133
[Install]
WantedBy=multi-user.target
The message worker can than be enabled and started via
:bash:`systemctl enable --now typo3-message-consumer`
Advanced Usage
--------------
Configure a custom transport (senders/receivers)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set up transports in services configuration. To configure one transport per
message, the TYPO3 configuration (:file:`config/settings.php`,
:file:`config/additional.php` on system level or :file:`ext_localconf.php`) is
used. The transport/sender name used in the settings is
resolved to a service that has been tagged with `message.sender` and the
respective identifier.
.. code-block:: php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['messenger'] = [
'routing' => [
// use "messenger.transport.demo" as transport for DemoMessage
\TYPO3\CMS\Queue\Message\DemoMessage::class => 'demo',
// use "messenger.transport.default" as transport for all other messages
'*' => 'default',
]
];
.. code-block:: yaml
messenger.transport.demo:
factory: [ '@TYPO3\CMS\Core\Messenger\DoctrineTransportFactory', 'createTransport' ]
class: 'Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineTransport'
arguments:
$options:
queue_name: 'demo'
tags:
- name: 'messenger.sender'
identifier: 'demo'
- name: 'messenger.receiver'
identifier: 'demo'
messenger.transport.default:
factory: [ '@Symfony\Component\Messenger\Transport\InMemory\InMemoryTransportFactory', 'createTransport' ]
class: 'Symfony\Component\Messenger\Transport\InMemory\InMemoryTransport'
arguments:
$dsn: 'in-memory://default'
$options: [ ]
tags:
- name: 'messenger.sender'
identifier: 'default'
- name: 'messenger.receiver'
identifier: 'default'
The TYPO3 Core has been tested with three transports:
- :php:`\Symfony\Component\Messenger\Transport\Sync\SyncTransport` (default)
- :php:`\Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineTransport` (using the Doctrine DBAL messenger transport)
- :php:`\Symfony\Component\Messenger\Transport\InMemory\InMemoryTransport` (for testing)
InMemoryTransport for testing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:php:`\Symfony\Component\Messenger\Transport\InMemory\InMemoryTransport` is a
transport that should only be used while testing. See the `SymfonyCasts
tutorial <https://symfonycasts.com/screencast/messenger/test-in-memory>`__
for more details.
.. code-block:: yaml
messenger.transport.default:
factory: [ '@Symfony\Component\Messenger\Transport\InMemory\InMemoryTransportFactory', 'createTransport' ]
class: 'Symfony\Component\Messenger\Transport\InMemory\InMemoryTransport'
public: true
arguments:
$dsn: 'in-memory://default'
$options: [ ]
tags:
- name: 'messenger.sender'
identifier: 'default'
- name: 'messenger.receiver'
identifier: 'default'
Configure a custom middleware
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Set up a middleware in the services configuration. By default,
:php:`\Symfony\Component\Messenger\Middleware\SendMessageMiddleware`
and :php:`\Symfony\Component\Messenger\Middleware\HandleMessageMiddleware`
are registered - see also `Symfony's documentation
<https://symfony.com/doc/current/components/messenger.html#bus>`__.
To add your own message middleware, tag it as :yaml:`messenger.middleware`
and set the order using TYPO3's `before` and `after` ordering mechanism.
.. code-block:: yaml
Symfony\Component\Messenger\Middleware\SendMessageMiddleware:
arguments:
$sendersLocator: '@Symfony\Component\Messenger\Transport\Sender\SendersLocatorInterface'
$eventDispatcher: '@Psr\EventDispatcher\EventDispatcherInterface'
tags:
- { name: 'messenger.middleware' }
Symfony\Component\Messenger\Middleware\HandleMessageMiddleware:
arguments:
$handlersLocator: '@Symfony\Component\Messenger\Handler\HandlersLocatorInterface'
tags:
- name: 'messenger.middleware'
after: 'Symfony\Component\Messenger\Middleware\SendMessageMiddleware'
.. index:: PHP-API, ext:core
@@ -0,0 +1,42 @@
.. include:: /Includes.rst.txt
.. _feature-97923-1673529192:
=====================================================================================
Feature: #97923 - Improve performance and usability while editing sys_file_collection
=====================================================================================
See :issue:`97923`
Description
===========
The two fields :sql:`storage` and :sql:`folder` of the :sql:`sys_file_collection`
table are now combined into the new field :sql:`folder_identifier`. The field
contains the so-called combined identifier in the format `storage:folder`,
where `storage` is the :sql:`uid` of the corresponding :sql:`sys_file_storage`
record and `folder` the absolute path to the folder, e.g. `1:/user_upload`.
An upgrade wizard is in place to migrate the two fields of the existing records
to the new field.
The TCA type `folder` is now used in the backend editing form to improve the
usability on selecting the corresponding folder via the folder selector, when
using the file collections with type `folder`.
Impact
======
Editing :sql:`sys_file_collection` records for the record type `folder` in the
backend is improved. Instead of selecting the storage first, reloading the form
and selecting the folder in a possibly large list afterwards, are users now
able to select the folder using the folder selector in a single step.
This additionally improves the performance of the backend form, especially for
storages with a huge amount of folders.
Also working with such records is improved, since only one field has to be
taken into account.
.. index:: Backend, ext:core
@@ -0,0 +1,59 @@
.. include:: /Includes.rst.txt
.. _feature-98394-1674070213:
==========================================================================
Feature: #98394 - Introduce event to prevent downloading of language packs
==========================================================================
See :issue:`98394`
Description
===========
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
services:
MyVendor\MyExtension\EventListener\ModifyLanguagePacks:
tags:
- name: event.listener
identifier: 'modifyLanguagePacks'
event: TYPO3\CMS\Install\Service\Event\ModifyLanguagePacksEvent
method: 'modifyLanguagePacks'
.. code-block:: php
:caption: EXT:my_extension/Classes/EventListener/ModifyLanguagePacks.php
<?php
namespace MyVendor\MyExtension\EventListener;
use TYPO3\CMS\Install\Service\Event\ModifyLanguagePacksEvent;
final class ModifyLanguagePacks
{
public function modifyLanguagePacks(ModifyLanguagePacksEvent $event): void
{
$extensions = $event->getExtensions();
foreach ($extensions as $key => $extension){
if($extension['type'] === 'typo3-cms-framework'){
$event->removeExtension($key);
}
}
$event->removeIsoFromExtension('de', 'styleguide');
}
}
Impact
======
With the newly introduced event, it is possible to ignore extensions or
individual language packs for extensions when downloading the language packs.
However, only language packs for extensions and languages
available in the system can be downloaded. The options of the `language:update`
command can be used to further restrict the download (ignore additional
extensions or download only specific languages), but not to ignore decisions
made by the event.
.. index:: ext:install
@@ -0,0 +1,41 @@
.. include:: /Includes.rst.txt
.. _feature-98528-1674126393:
===========================================================
Feature: #98528 - New file location for ENABLE_INSTALL_TOOL
===========================================================
See :issue:`98528`
Description
===========
To access the standalone :guilabel:`Install Tool`, the file
:file:`typo3conf/ENABLE_INSTALL_TOOL` needed to be created.
With TYPO3 v12, the location of this file has been changed.
For Composer-based installations the following file paths are checked:
* :file:`var/transient/ENABLE_INSTALL_TOOL`
* :file:`config/ENABLE_INSTALL_TOOL`
For legacy installations the following file paths are checked:
* :file:`typo3temp/var/transient/ENABLE_INSTALL_TOOL`
* :file:`typo3conf/ENABLE_INSTALL_TOOL`
Using the previous known path :file:`typo3conf/ENABLE_INSTALL_TOOL` is
still possible.
Impact
======
Especially for Composer-based installation this change allows to completely
drop the usage of the :file:`typo3conf/` directory.
Add the new paths to your :php:`.gitignore` file to avoid deploying this file to
production environments.
.. index:: Backend, ext:install
@@ -0,0 +1,34 @@
.. include:: /Includes.rst.txt
.. _feature-99191-1669906308:
===========================================
Feature: #99191 - Create folders via modals
===========================================
See :issue:`99191`
Description
===========
The creation of new folders in the :guilabel:`File > Filelist` module has been
improved. Instead of a new window, the :guilabel:`Create Folder` button
now opens a modal window to create a folder.
Both the button in the docheader and the corresponding option in the context
menu are affected.
The modal window also contains the folder tree to select the parent folder.
To allow editors creating folders sequentially, the modal is not
automatically closed.
Impact
======
With the new modal window, backend users are able to create folders in an
improved way: They do not lose focus of the current view anymore.
Additionally, the parent folder can easily be changed inside the modal window,
which allows to create folders for different levels without leaving the form.
After closing the modal window, the :guilabel:`File > Filelist` module
automatically reloads to instantly display the latest changes.
.. index:: Backend, ext:filelist
@@ -0,0 +1,90 @@
.. include:: /Includes.rst.txt
.. _feature-99220-1670250156:
====================================================
Feature: #99220 - Add event to modify search results
====================================================
See :issue:`99220`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Backend\Search\Event\ModifyResultItemInLiveSearchEvent`
is added to allow extension developers to take control over search result items
rendered in the backend search.
The event has a public method called :php:`getResultItem()`, returning the
:php:`\TYPO3\CMS\Backend\Search\LiveSearch\ResultItem` instance of the search
result item.
Impact
======
Search result items may be modified within a custom event listener, e.g. to add
custom actions.
Example
-------
.. code-block:: php
:caption: EXT:my_extension/Classes/Search/EventListener/AddLiveSearchResultActionsListener.php
<?php
namespace MyVendor\MyExtension\Search\EventListener;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Backend\Search\Event\ModifyResultItemInLiveSearchEvent;
use TYPO3\CMS\Backend\Search\LiveSearch\DatabaseRecordProvider;
use TYPO3\CMS\Backend\Search\LiveSearch\ResultItemAction;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
final class AddLiveSearchResultActionsListener
{
protected LanguageService $languageService;
public function __construct(
protected readonly IconFactory $iconFactory,
protected readonly LanguageServiceFactory $languageServiceFactory,
protected readonly UriBuilder $uriBuilder
) {
$this->languageService = $this->languageServiceFactory->createFromUserPreferences($GLOBALS['BE_USER']);
}
public function __invoke(ModifyResultItemInLiveSearchEvent $event): void
{
$resultItem = $event->getResultItem();
if ($resultItem->getProviderClassName() !== DatabaseRecordProvider::class) {
return;
}
if (($resultItem->getExtraData()['table'] ?? null) === 'tt_content') {
/**
* WARNING: THIS EXAMPLE OMITS ANY ACCESS CHECK FOR SIMPLICITY REASONS.
* DO NOT USE AS-IS!
*/
$showHistoryAction = (new ResultItemAction('view_history'))
->setLabel($this->languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:history'))
->setIcon($this->iconFactory->getIcon('actions-document-history-open', Icon::SIZE_SMALL))
->setUrl((string)$this->uriBuilder->buildUriFromRoute('record_history', [
'element' => $resultItem->getExtraData()['table'] . ':' . $resultItem->getExtraData()['uid']
]));
$resultItem->addAction($showHistoryAction);
}
}
}
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Search\EventListener\AddLiveSearchResultActionsListener:
tags:
- name: event.listener
identifier: 'site/add-live-search-result-actions-listener'
.. index:: Backend, ext:backend
@@ -0,0 +1,72 @@
.. include:: /Includes.rst.txt
.. _feature-99285-1670321970:
==========================================
Feature: #99285 - Add Fluid TrimViewHelper
==========================================
See :issue:`99285`
Description
===========
A trim ViewHelper to trim strings is now available.
Possible sides are:
* `both` Strip whitespace (or other characters) from the beginning and end of a string
* `left` Strip whitespace (or other characters) from the beginning of a string
* `right` Strip whitespace (or other characters) from the end of a string
Examples
--------
Trim from both sides
~~~~~~~~~~~~~~~~~~~~
.. code-block:: html
#<f:format.trim> String to be trimmed. </f:format.trim>#
Results in the output:
.. code-block:: text
#String to be trimmed.#
Trim only one side
~~~~~~~~~~~~~~~~~~
.. code-block:: html
#<f:format.trim side="right"> String to be trimmed. </f:format.trim>#
Results in the output:
.. code-block:: text
# String to be trimmed.#
Trim special characters
~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: html
#<f:format.trim characters=" St."> String to be trimmed. </f:format.trim>#
Results in the output:
.. code-block:: text
#ring to be trimmed#
Impact
======
The new ViewHelper can be used in all new projects. There is no interference
with any part of existing code.
.. index:: Fluid, Frontend, ext:fluid
@@ -0,0 +1,63 @@
.. include:: /Includes.rst.txt
.. _feature-99312:
=======================================================================
Feature: #99312 - PSR-14 Event for fetching YouTube/Vimeo preview image
=======================================================================
See :issue:`99312`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Core\Resource\OnlineMedia\Event\AfterVideoPreviewFetchedEvent`
has been introduced. The purpose of this event is to modify the preview file
of online media previews (like YouTube and Vimeo).
If, for example, a processed file is bad (blank or outdated), this event can be
used to modify and/or update the preview file.
The event features the following methods:
- :php:`getFile()`: Returns the :php:`\TYPO3\CMS\Core\Resource\File` in question
- :php:`getOnlineMediaId()`: Returns the video ID
- :php:`getPreviewImageFilename()`: Returns the filename of the preview image
- :php:`setPreviewImageFilename()`: Set the filename for the preview image
Registration of the event in your extension's :file:`Services.yaml`:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\EventListener\ExampleEventListener:
tags:
- name: event.listener
identifier: 'exampleEventListener'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/EventListener/ExampleEventListener.php
namespace MyVendor\MyExtension\EventListener;
use TYPO3\CMS\Core\Resource\OnlineMedia\Event\AfterVideoPreviewFetchedEvent;
final class ExampleEventListener
{
public function __invoke(AfterVideoPreviewFetchedEvent $event): void
{
$event->setPreviewImageFilename(
'/var/www/websites/typo3temp/assets/online_media/new-preview-image.jpg'
);
// An extension could use this to fetch new images again.
}
}
Impact
======
It is now possible to change the filename for the preview image of a YouTube
or Vimeo thumbnail image.
.. index:: Backend, Frontend, ext:core
@@ -0,0 +1,51 @@
.. include:: /Includes.rst.txt
.. _feature-99341-1670827943:
===================================================
Feature: #99341 - Introduce CLI create user command
===================================================
See :issue:`99341`
Description
===========
A new CLI command `backend:user:create`, which automates backend user creation,
is introduced as an alternative to the existing backend module.
Impact
======
You can now use `./bin/typo3 backend:user:create` to create a backend user
without touching the GUI.
Example
-------
Interactive / guided setup (questions/answers):
.. code-block:: bash
./bin/typo3 backend:user:create
User creation using environment variables:
.. code-block:: bash
TYPO3_BE_USER_NAME=username \
TYPO3_BE_USER_EMAIL=admin@example.com \
TYPO3_BE_USER_GROUPS=<comma-separated-list-of-group-ids> \
TYPO3_BE_USER_ADMIN=0 \
TYPO3_BE_USER_MAINTAINER=0 \
./bin/typo3 backend:user:create --no-interaction
.. warning::
Variable `TYPO3_BE_USER_PASSWORD` and options `-p` or `--password` can be
used to provide a password. Using this can be a security risk since the password
may end up in shell history files. Prefer the interactive mode. Additionally,
writing a command to shell history can be suppressed by prefixing the command
with a space when using `bash` or `zsh`.
.. index:: ext:backend
@@ -0,0 +1,61 @@
.. include:: /Includes.rst.txt
.. _feature-99430-1672129914:
=================================================================
Feature: #99430 - Add event after record publishing in workspaces
=================================================================
See :issue:`99430`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Workspaces\Event\AfterRecordPublishedEvent`
has been added to allow extension developers to react on record publishing
in workspaces.
The new event is fired after a record has been published in a workspace and
provides the following methods:
- :php:`getTable()`: The record's table name
- :php:`getRecordId()`: The record's UID
- :php:`getWorkspaceId()`: The workspace the record has been published in
Example
=======
Registration of the :php:`AfterRecordPublishedEvent` in your extension's
:file:`Services.yaml`:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Workspaces\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/after-record-published'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/Workspaces/MyEventListener.php
namespace MyVendor\MyExtension\Workspaces;
use TYPO3\CMS\Workspaces\Event\AfterRecordPublishedEvent;
final class MyEventListener {
public function __invoke(AfterRecordPublishedEvent $event): void
{
// Do your magic here
}
}
Impact
======
With the new PSR-14 event :php:`AfterRecordPublishedEvent` it is possible to
execute custom functionality after a record has been published in a workspace.
.. index:: PHP-API, ext:workspaces
@@ -0,0 +1,27 @@
.. include:: /Includes.rst.txt
.. _feature-99552-1673955499:
=============================================================
Feature: #99552 - Introduce "Missing Meta Description" widget
=============================================================
See :issue:`99552`
Description
===========
To make it more convenient for TYPO3 users to optimise their website for search
engines, TYPO3 now offers a dashboard widget that shows pages without
a meta description.
Impact
======
TYPO3 users who have access to the :guilabel:`Dashboard` module and are
granted access to the new widget can now add and use the widget.
The users will only see pages with missing meta description they are
allowed to edit.
.. index:: Backend, ext:seo
@@ -0,0 +1,26 @@
.. include:: /Includes.rst.txt
.. _feature-99584-1673985938:
==========================================================================
Feature: #99584 - Allow to provide name for new admin users in ext:install
==========================================================================
See :issue:`99584`
Description
===========
The field `realName` has been added to the "Create Administrative User" modal
in ext:install, so it is possible to provide the name of a new admin user.
The notice in the header of the model has been removed, since it is
superfluous now.
Impact
======
It is now possible to provide the field `realName`, when a new admin user
is created in ext:install.
.. index:: Backend, ext:install
@@ -0,0 +1,51 @@
.. include:: /Includes.rst.txt
.. _feature-99586-1673989775:
=================================================================
Feature: #99586 - Registration of upgrade wizards via service tag
=================================================================
See :issue:`99586`
Description
===========
Upgrade wizards are used to execute one time migrations when
updating a TYPO3 installation. The registration was previously done
in an extension's :php:`ext_localconf.php` file. This has now been
improved by introducing the custom PHP attribute
:php:`\TYPO3\CMS\Install\Attribute\UpgradeWizard`. All upgrade wizards,
defining the new attribute, are automatically tagged and registered
in the service container. The registration via
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/install']['update']`
has been deprecated.
The registration of an upgrade wizard is therefore now be done
directly in the class by adding the new attribute with the upgrade
wizard's unique identifier as constructor argument:
.. code-block:: php
use TYPO3\CMS\Install\Attribute\UpgradeWizard;
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
#[UpgradeWizard('myUpgradeWizard')]
class MyUpgradeWizard implements UpgradeWizardInterface
{
}
.. note::
All upgrade wizards have to implement the
:php:`\TYPO3\CMS\Install\Updates\UpgradeWizardInterface`.
Impact
======
It is now possible to tag upgrade wizards with the PHP attribute
:php:`\TYPO3\CMS\Install\Attribute\UpgradeWizard` to have them
auto-configured and auto-registered.
.. index:: Backend, PHP-API, ext:install
@@ -0,0 +1,124 @@
.. include:: /Includes.rst.txt
.. _feature-99618-1674063182:
==========================================================================
Feature: #99618 - List of countries in the world and their localized names
==========================================================================
See :issue:`99618`
Description
===========
TYPO3 now ships a list of countries of the world. The list is based on the
ISO 3166-1 standard, with the alpha-numeric short name ("FR" or "FRA" in its
three-letter short name), the English name ("France"), the official name
("Republic of France"), also the numerical code, and the country's flag as
emoji (UTF-8 representation).
This list is based on Debian's ISO code list https://salsa.debian.org/iso-codes-team/iso-codes,
and shipped statically as PHP content in a new country API.
Impact
======
It is now possible to load a list of all countries via PHP:
.. code-block:: php
use TYPO3\CMS\Core\Utility\GeneralUtility;
$countryProvider = GeneralUtility::makeInstance(CountryProvider::class);
$france = $countryProvider->getByIsoCode('FR');
// or
$france = $countryProvider->getByEnglishName('France');
// or
$france = $countryProvider->getByAlpha3IsoCode('FRA');
// or
$allCountries = $countryProvider->getAll();
// or
$filter = new CountryFilter();
$filter
->setOnlyCountries(['AT', 'DE', 'FR', 'DK'])
->setExcludeCountries(['AUT', 'DK']);
$filteredCountries = $countryProvider->getFiltered($filter); // will be array with DE & FR
A country object can be used to fetch all information about this,
also with translatable labels:
.. code-block:: php
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
$languageService = GeneralUtility::makeInstance(LanguageServiceFactory::class)->create('de');
echo $france->getName(); // "France"
echo $languageService->sL($france->getLocalizedNameLabel()); // "Frankreich"
echo $france->getOfficialName(); // "French Republic"
echo $languageService->sL($france->getLocalizedOfficalNameLabel()); // "Französische Republik"
echo $france->getNumericRepresentation(); // 250
echo $france->getAlpha2IsoCode(); // "FR"
echo $france->getFlag(); // "🇫🇷"
A Fluid ViewHelper is also shipped with TYPO3 to render a dropdown
for forms:
.. code-block:: html
<f:form.countrySelect
name="country"
value="AT"
sortByOptionLabel="true"
prioritizedCountries="{0: 'DE', 1: 'AT', 2: 'CH'}"
/>
Available options
-----------------
- :html:`disabled`: Specifies that the form element should be disabled when
the page loads.
- :html:`required`: If set no empty value is allowed.
- :html:`size`: Size of select field, a numeric value to show the amount of
items to be visible at the same time - equivalent to HTML :html:`<select>`
site attribute
- :html:`multiple`: If set multiple options may be selected
- :html:`errorClass`: Specify the CSS class to be set if there are errors for
this ViewHelper.
- :html:`sortByOptionLabel`: Whether the country list should be sorted by
option label or not.
- :html:`optionLabelField`: Specify the type of label of the country list.
Available options are: "name", "localizedName", "officialName" or
"localizedOfficialName". Default option is "localizedName".
- :html:`alternativeLanguage`: If specified, the country list will be shown
in the given language.
- :html:`prioritizedCountries`: Define a list of countries which should be
listed as first options in the form element.
- :html:`onlyCountries`: Restrict the countries to be rendered in the list.
- :html:`excludeCountries`: Define which countries should not be shown in
the list.
- :html:`prependOptionLabel`: Provide an additional option at first position
with the specified label.
- :html:`prependOptionValue`: Provide an additional option at first position
with the specified value.
.. hint::
A combination of :html:`optionLabelField` and :html:`alternativeLanguage` is
possible. For instance, if you want to show the localized official names but
not in your default language but in French.
You can achieve this by using the following combination:
.. code-block:: html
<f:form.countrySelect
name="country"
optionLabelField="localizedOfficialName"
alternativeLanguage="fr"
sortByOptionLabel="true"
/>
.. index:: Fluid, PHP-API, ext:core
@@ -0,0 +1,27 @@
.. include:: /Includes.rst.txt
.. _feature-99626-1674115749:
====================================================================
Feature: #99626 - Sites configuration (YAML) in configuration module
====================================================================
See :issue:`99626`
Description
===========
Currently, it is difficult to have a global overview of the YAML configuration
of sites (especially the route enhancers). Since those configurations are basic
information, it is important for site administrators to have an overview of them.
Therefore, the configuration module now lists all site configurations
with their identifier and corresponding configuration.
Impact
======
It is now possible for site administrators to get an overview of the YAML
configuration of all sites in the configuration module.
.. index:: Backend, ext:lowlevel
@@ -0,0 +1,49 @@
.. include:: /Includes.rst.txt
.. _feature-99632-1674121967:
===================================================================
Feature: #99632 - Introduce PHP attribute to mark a webhook message
===================================================================
See :issue:`99632`
Description
===========
A new custom PHP attribute :php:`\TYPO3\CMS\Core\Attribute\WebhookMessage` has
been added in order to register a message as a specific webhook message,
to send as remote status.
The attribute must have an identifier for the webhook type (unique),
and a description that explains the purpose of the message.
Optionally, a property method can be set for the attribute,
that contains the factory method. By default this is `createFromEvent`,
which is typically used when creating a message by an event listener, see
webhooks documentation for more details.
Example
-------
.. code-block:: php
use TYPO3\CMS\Core\Attribute\WebhookMessage;
#[WebhookMessage(
identifier: 'typo3/file-updated',
description: 'LLL:EXT:webhooks/Resources/Private/Language/locallang_db.xlf:sys_webhook.webhook_type.typo3-file-updated'
)]
final class AnyKindOfMessage
{
// ...
}
Impact
======
It is now possible to tag any PHP class as webhook message by the PHP attribute
:php:`\TYPO3\CMS\Core\Attribute\WebhookMessage`.
.. index:: Backend, Frontend, PHP-API, ext:core
@@ -0,0 +1,123 @@
.. include:: /Includes.rst.txt
.. _feature-99647-1674134370:
=====================================================
Feature: #99647 - Specific routes for backend modules
=====================================================
See :issue:`99647`
Description
===========
With :issue:`96733` the new module registration API has been introduced. One
of the main features is the explicit definition of the module routes. To
further improve the registration, it is now possible to define specific routes
for the modules, targeting any controller / action combination. Previously
the `target` of a module usually targeted a controller action like
:php:`handleRequest()`, which then forwarded the request internally to a
specific action, specified by e.g. a query argument. Such umbrella method can
now be omitted by directly using the target action as :php:`target` in the
module configuration.
Additionally, this also makes any HTTP method check in the controller
superfluous, since the allowed methods can now also be defined directly in the
module configuration for each sub-route.
Example
-------
.. code-block:: php
:caption: EXT:my_extension/Configuration/Backend/Modules.php
return [
'my_module' => [
'parent' => 'web',
'path' => '/module/web/my-module',
'routes' => [
'_default' => [
'target' => MyModuleController::class . '::overview',
],
'edit' => [
'path' => '/custom-path',
'target' => MyModuleController::class . '::edit',
],
'manage' => [
'target' => AnotherController::class . '::manage',
'methods' => ['POST'],
],
],
],
];
In case the :php:`path` option is omitted for a sub-route, its identifier is
automatically used as :php:`path`, e.g. :php:`/manage`.
All sub-routes are automatically registered in a :php:`\TYPO3\CMS\Core\Routing\RouteCollection`.
The full route identifier syntax is :php:`<module_identifier>.<sub_route>`, for
example :php:`my_module.edit`. Using the :php:`\TYPO3\CMS\Backend\Routing\UriBuilder`
to create a link to such sub-route could therefore look like this:
.. code-block:: php
UriBuilder->buildUriFromRoute('my_module.edit')
Extbase modules
^^^^^^^^^^^^^^^
Also Extbase backend modules are enhanced and define now automatically
explicit routes for each controller / action combination,
as long as the :typoscript:`enableNamespacedArgumentsForBackend`
feature toggle is turned off, which is the default. This means,
the following module configuration
.. code-block:: php
:caption: EXT:my_extension/Configuration/Backend/Modules.php
return [
'web_ExtkeyExample' => [
'parent' => 'web',
'position' => ['after' => 'web_info'],
'access' => 'admin',
'workspaces' => 'live',
'iconIdentifier' => 'module-example',
'path' => '/module/web/ExtkeyExample',
'labels' => 'LLL:EXT:beuser/Resources/Private/Language/locallang_mod.xlf',
'extensionName' => 'Extkey',
'controllerActions' => [
MyModuleController::class => [
'list',
'detail'
],
],
],
];
now leads to following URLs:
- `https://example.com/typo3/module/web/ExtkeyExample`
- `https://example.com/typo3/module/web/ExtkeyExample/MyModuleController/list`
- `https://example.com/typo3/module/web/ExtkeyExample/MyModuleController/detail`
The route identifier of corresponding routes is registered with similar syntax
as standard backend modules: :php:`<module_identifier>.<controller>_<action>`.
Above configuration will therefore register the following routes:
- `web_ExtkeyExample`
- `web_ExtkeyExample.MyModuleController_list`
- `web_ExtkeyExample.MyModuleController_detail`
Impact
======
It is now possible to configure specific routes for a module, which all can
target any controller / action combination.
As long as :typoscript:`enableNamespacedArgumentsForBackend` is turned off
for Extbase backend modules, all controller / action combinations are explicitly
registered as individual routes. This effectively means human-readable URLs,
since the controller / action combinations are no longer defined via query
parameters but are now part of the path.
.. index:: Backend, PHP-API, ext:backend
@@ -0,0 +1,59 @@
.. include:: /Includes.rst.txt
.. _feature-99694-1674552209:
=====================================================================
Feature: #99694 - Unified Locale handling for translation files (XLF)
=====================================================================
See :issue:`99694`
Description
===========
TYPO3 now internally uses a "locale" format following the
`IETF RFC 5646 language tag standard <https://www.rfc-editor.org/rfc/rfc5646.html>`__.
A locale supported by TYPO3 consists of the following parts (tags and subtags):
* ISO 639-1 / ISO 639-2 compatible language key in lowercase (such as "fr" French, or "de" for German)
* optionally the ISO 15924 compatible language script system (4 letter, such as "Hans" as in "zh_Hans")
* optionally the region / country code according to ISO 3166-1 standard in upper camelcase such as "AT" for Austria.
Examples for a locale string are:
* "en" for English
* "pt" for Portuguese
* "da-DK" for Danish as used in Denmark
* "de-CH" for German as used in Switzerland
* "zh-Hans-CN" for Chinese with the simplified script as spoken in China (mainland)
A new PHP object :php:`Locale` automatically separates each tag and subtag into
these parts.
The :php:`\TYPO3\CMS\Core\Localization\Locale` object can now be used to instantiate a new
:php:`\TYPO3\CMS\Core\Localization\LanguageService` object for translating labels.
Previously, TYPO3 used the `default` language key instead of the locale `en` to
identify the English language. Both are supported, but it is encouraged to use
`en-US` or `en-GB` with the region subtag to identify the chosen language more
precisely.
Impact
======
Example for using the :php:`Locale` class for creating a :php:`LanguageService`
object for translations:
.. code-block:: php
$languageService = $languageServiceFactory->create(new Locale('de-AT'));
$myTranslatedString = $languageService->sL(
'LLL:EXT:my_extension/Resources/Private/Language/myfile.xlf:my-label'
);
Using this service is highly recommended, as the wrappers
:php:`$GLOBALS['LANG']->sL()` and :php:`$GLOBALS['TSFE']->sL()` will be
deprecated in the future.
.. index:: PHP-API, ext:core
@@ -0,0 +1,83 @@
.. include:: /Includes.rst.txt
.. _feature-99717-1674654720:
===================================================================
Feature: #99717 - New PSR-14 ModifyBlindedConfigurationOptionsEvent
===================================================================
See :issue:`99717`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Lowlevel\Event\ModifyBlindedConfigurationOptionsEvent`
has been introduced which serves as a direct replacement for the
now deprecated hook
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Lowlevel\Controller\ConfigurationController']['modifyBlindedConfigurationOptions']`.
The new PSR-14 event is fired in the
:php:`\TYPO3\CMS\Lowlevel\ConfigurationModuleProvider\GlobalVariableProvider` and the
:php:`\TYPO3\CMS\Lowlevel\ConfigurationModuleProvider\SitesYamlConfigurationProvider`,
while building the corresponding configuration array, which should be displayed
in the :guilabel:`Configuration` module. The event therefore allows to
blind (hide) any of those configuration options. Usually, such options are
passwords or any other sensitive information.
Using the :php:`ModifyBlindedConfigurationOptionsEvent::getProviderIdentifier()`
method, listeners are able to determine the context, the event got dispatched
in. This is useful to prevent duplicate code execution, since the event is
dispatched for multiple providers. The method returns the identifier of
the configuration provider as registered in the
:ref:`service configuration <feature-92929>`.
Example
=======
Registration of the :php:`ModifyBlindedConfigurationOptionsEvent` in your
extension's :file:`Services.yaml`:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Backend\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/blind-configuration-options'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/Backend/MyEventListener.php
namespace MyVendor\MyExtension\Backend;
use TYPO3\CMS\Lowlevel\ConfigurationModuleProvider\GlobalVariableProvider;
use TYPO3\CMS\Lowlevel\ConfigurationModuleProvider\SitesYamlConfigurationProvider;
use TYPO3\CMS\Lowlevel\Event\ModifyBlindedConfigurationOptionsEvent;
final class MyEventListener {
public function __invoke(ModifyBlindedConfigurationOptionsEvent $event): void
{
$blindedConfigurationOptions = $event->getBlindedConfigurationOptions();
if ($event->getProviderIdentifier() === 'sitesYamlConfiguration') {
$blindedConfigurationOptions['my-site']['settings']['apiKey'] = '***';
} elseif ($event->getProviderIdentifier() === 'confVars') {
$blindedConfigurationOptions['TYPO3_CONF_VARS']['EXTENSIONS']['my_extension']['password'] = '******';
}
$event->setBlindedConfigurationOptions($blindedConfigurationOptions);
}
}
Impact
======
With the new :php:`ModifyBlindedConfigurationOptionsEvent`, it is
now possible to modify global configuration options as well as site
configuration options, displayed in the :guilabel:`Configuration` module.
The event might be triggered by more configuration providers in the future.
.. index:: Backend, LocalConfiguration, PHP-API, ext:lowlevel
@@ -0,0 +1,25 @@
.. include:: /Includes.rst.txt
.. _feature-99733-1675025218:
====================================================================
Feature: #99733 - Drag + Drop between different folders in file list
====================================================================
See :issue:`99733`
Description
===========
When working with files in the :guilabel:`File > Filelist` module, editors can
now select one or multiple files or folders, and move them to a different
location within the folder tree on the navigation area via drag and drop.
Impact
======
TYPO3 editors no longer need to use the clipboard functionality to move files,
as drag and drop support is included natively. It acts similar to
what editors know from their operating system functionality.
.. index:: Backend, ext:filelist
@@ -0,0 +1,121 @@
.. include:: /Includes.rst.txt
.. _feature-99746-1675059434:
===============================================================
Feature: #99746 - New PSR-14 SlugRedirectChangeItemCreatedEvent
===============================================================
See :issue:`99746`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent`
has been added to TYPO3 Core. This event is fired in the
:php:`\TYPO3\CMS\Redirects\RedirectUpdate\SlugRedirectChangeItemFactory` and
allows extension authors to manage the redirect sources for which redirects
should be created.
The event features the following methods:
- :php:`getSlugRedirectChangeItem()`: Returns the current
:php:`\TYPO3\CMS\Redirects\RedirectUpdate\SlugRedirectChangeItem`
- :php:`setSlugRedirectChangeItem()`: Can be used to set a new or changed
:php:`SlugRedirectChangeItem`
TYPO3 already implements the :php:`\TYPO3\CMS\Redirects\EventListener\AddPlainSlugReplacementSource`
listener. It is used to add the plain slug value based source type, which provides the same
behaviour like before. Implementing this as a Core listener gives extension authors the ability to
remove the source added by :php:`AddPlainSlugReplacementSource`, when their listeners are
registered and executed afterwards. See the example below.
It is required for custom source class implementations to implement the
:php:`\TYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceInterface`. Using the
interface allows to detect custom source class implementations automatically.
Additionally, this allows to transport custom information and data.
Registration of the event in your extension's :file:`Services.yaml`:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Redirects\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/redirects/add-redirect-source'
after: 'redirects-add-plain-slug-replacement-source'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/Redirects/MyEventListener.php
namespace MyVendor\MyExtension\Redirects;
use MyVendor\MyExtension\Redirects\CustomSource;
use TYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent;
use TYPO3\CMS\Redirects\RedirectUpdate\PlainSlugReplacementRedirectSource;
use TYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceCollection;
final class MyEventListener {
public function __invoke(SlugRedirectChangeItemCreatedEvent $event): void
{
// Retrieve change item and sources
$changeItem = $event->getSlugRedirectChangeItem();
$sources = $changeItem->getSourcesCollection()->all();
// remove plain slug replacement redirect source from sources
$sources = array_filter(
$sources,
fn ($source) => !($source instanceof PlainSlugReplacementRedirectSource)
);
// add custom source implementation
$sources[] = new CustomSource();
// replace sources collection
$changeItem = $changeItem->withSourcesCollection(
new RedirectSourceCollection(...array_values($sources))
);
// Update changeItem in the event
$event->setSlugRedirectChangeItem($changeItem);
}
}
Custom source implementation (example):
.. code-block:: php
:caption: EXT:my_extension/Classes/Redirects/CustomSource.php
namespace MyVendor\MyExtension\Redirects;
use TYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceInterface;
final class CustomSource implements RedirectSourceInterface
{
public function getHost(): string
{
return '*';
}
public function getPath(): string
{
return '/some-path';
}
public function getTargetLinkParameters(): array
{
return [];
}
}
Impact
======
With the new :php:`SlugRedirectChangeItemCreatedEvent`, it is possible to manage
the redirect sources for which redirects should be created. It furthermore allows
to influence existing Core functionality.
.. index:: PHP-API, ext:redirects
@@ -0,0 +1,32 @@
.. include:: /Includes.rst.txt
.. _feature-99806-1675673144:
===================================================
Feature: #99806 - Introduce GenericButton component
===================================================
See :issue:`99806`
Description
===========
A new component :php:`TYPO3\CMS\Backend\Template\Components\Buttons\GenericButton`
is introduced that allows to render any markup in the module menu bar.
Example:
.. code-block:: php
$buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
$genericButton = GeneralUtility::makeInstance(GenericButton::class)
->setTag('a')
->setHref('#')
->setLabel('Label')
->setTitle('Title')
->setIcon($this->iconFactory->getIcon('actions-heart'))
->setAttributes(['data-value' => '123']);
$buttonBar->addButton($genericButton, ButtonBar::BUTTON_POSITION_RIGHT, 2);
.. index:: Backend, ext:backend
@@ -0,0 +1,51 @@
.. include:: /Includes.rst.txt
.. _important-99490-1673358047:
======================================================================================
Important: #99490 - Provide tag to add JavaScript Modules to importmap in backend form
======================================================================================
See :issue:`99490`
Description
===========
The JavaScript module import map is static and only generated and
loaded in the first request to a document. All possible future
modules requested in later Ajax calls need to be registered already
in the first initial request.
We are adding a new tag `backend.form` that is used to identify
JavaScript modules that can be used within the backend forms. This
will ensure that the import maps are available for these modules
even if the element is not displayed directly.
A typical use case for this is an `InlineRelationRecord` where the
CKEditor is not part of the main record but needs to be loaded for
the child record.
Example Configuration/JavaScriptModules.php
-------------------------------------------
.. code-block:: php
<?php
return [
'dependencies' => [
'backend',
],
'tags' => [
'backend.form',
],
'imports' => [
'@typo3/rte-ckeditor/'
=> 'EXT:rte_ckeditor/Resources/Public/JavaScript/',
'@typo3/ckeditor5-bundle.js'
=> 'EXT:rte_ckeditor/Resources/Public/Contrib/ckeditor5-bundle.js',
],
];
.. index:: Backend, FlexForm, JavaScript, ext:backend
@@ -0,0 +1,49 @@
.. include:: /Includes.rst.txt
.. _important-99609-1674123952:
=========================================
Important: #99609 - Streamline flag icons
=========================================
See :issue:`99609`
Description
===========
We streamlined the flag icons and make them easier to handle.
The Core provides a range of flag icons that are representing countries,
regions, movements, islands, and more. The flags are mostly used in
conjunction with languages.
We agree that a flag does not represent a language, but having a visual
identifier attached to languages makes it easier for editors to
identify the language they want to edit or translate.
New flags added in this patch will express that we understand both,
the issue and the need to differentiate languages. We chose simple
colored flags to achieve this. It still allows differentiation while
variants like de-DE and de-CH can be maintained and identified.
New flags: black, blue, cyan, green, indigo, orange, pink, purple, red,
teal, white, yellow, rainbow.
Flags of historic countries have been removed:
- AN, Netherlands Antilles (until 2010)
- CS, State Union of Serbia and Montenegro (until 2006)
Flags for language codes have been removed:
- kl, Greenlandic
- mi, Māori
Flags for country regions have been aligned:
- Spain, Catalonia: catalonia -> es-ct
- Canada, Quebec: qc -> ca-qc
Please adjust your site configuration if you are using one of
the removed or renamed flag icons.
.. index:: Backend, ext:backend
@@ -0,0 +1,27 @@
.. include:: /Includes.rst.txt
.. _important-99660-1674251294:
==============================================================
Important: #99660 - Remove content area from new record wizard
==============================================================
See :issue:`99660`
Description
===========
The TYPO3 backend comes with a distinction between "content elements" and
other records: While content is managed using the specialized :guilabel:`Page`
module, the :guilabel:`List` module is the main management interface for
other types of records.
Managing content elements from within the :guilabel:`List` module is not
a good choice for editors, the :guilabel:`Page` module should be used.
To foster this separation, the :guilabel:`Create new record` view reachable
from within the :guilabel:`List` module no longer allows to add content
elements. As a side effect, this avoids wrong or invalid default values
of the :guilabel:`Column` (colPos) field.
.. index:: Backend, ext:backend
+54
View File
@@ -0,0 +1,54 @@
:template: changelogOverview.html
.. include:: /Includes.rst.txt
.. _changelog-12-2:
============
12.2 Changes
============
**Table of contents**
.. contents::
:local:
:depth: 1
Breaking Changes
================
None since TYPO3 v12.0 release.
.. attention::
After TYPO3 v12.0, only new functionality with a solid migration path
can be added on top, with aiming for as little as possible breaking changes
after the initial v12.0 release on the way to LTS.
Features
========
.. toctree::
:maxdepth: 1
:titlesonly:
:glob:
Feature-*
Deprecation
===========
.. toctree::
:maxdepth: 1
:titlesonly:
:glob:
Deprecation-*
Important
=========
.. toctree::
:maxdepth: 1
:titlesonly:
:glob:
Important-*