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,45 @@
.. include:: /Includes.rst.txt
.. _deprecation-100014-1677078784:
==========================================================================================
Deprecation: #100014 - Function `getParameterFromUrl()` of `@typo3/backend/utility` module
==========================================================================================
See :issue:`100014`
Description
===========
The function :js:`getParameterFromUrl()` of the :js:`@typo3/backend/utility`
module was used to obtain a query string argument from an arbitrary URL.
Meanwhile, browsers received the `URLSearchParams API`_ that can be used
instead.
Therefore, :js:`getParameterFromUrl()` has been marked as deprecated.
Impact
======
Calling :js:`getParameterFromUrl()` will trigger a deprecation warning.
Affected installations
======================
All installations using third-party extensions relying on the deprecated code are
affected.
Migration
=========
Migrate to the following snippet to get the same result:
.. code-block:: javascript
const paramValue = new URL(url, window.location.origin).searchParams.get(parameter);
.. _URLSearchParams API: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
.. index:: JavaScript, NotScanned, ext:backend
@@ -0,0 +1,60 @@
.. include:: /Includes.rst.txt
.. _deprecation-100033-1677433329:
============================================================
Deprecation: #100033 - TBE_STYLES stylesheet and stylesheet2
============================================================
See :issue:`100033`
Description
===========
The usage of :php:`$GLOBALS['TBE_STYLES']['stylesheet']` and
:php:`$GLOBALS['TBE_STYLES']['stylesheet2']` to add custom CSS files
to the TYPO3 backend has been marked as deprecated in TYPO3 v12 and will be
removed in TYPO3 v13.
Impact
======
Using any of the following configuration declarations
* :php:`$GLOBALS['TBE_STYLES']['stylesheet']`
* :php:`$GLOBALS['TBE_STYLES']['stylesheet2']`
will trigger a PHP deprecation notice and will throw a fatal PHP error in
TYPO3 v13.
Affected installations
======================
The extension scanner will find extensions using
* :php:`$GLOBALS['TBE_STYLES']['stylesheet']`
* :php:`$GLOBALS['TBE_STYLES']['stylesheet2']`
as "weak" matches.
Migration
=========
Extensions should use :php:`$GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets']['my_extension']`
where :php:`'my_extension'` is the extension key.
Example
-------
.. code-block:: php
:caption: EXT:my_extension/ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets']['my_extension'] = 'EXT:my_extension/Resources/Public/Css';
In the example above, all CSS files in the configured directory will be loaded
in TYPO3 backend.
.. index:: Backend, FullyScanned, ext:backend
@@ -0,0 +1,50 @@
.. include:: /Includes.rst.txt
.. _deprecation-100047-1677607925:
==========================================================
Deprecation: #100047 - Deprecated ConditionMatcher classes
==========================================================
See :issue:`100047`
Description
===========
The following classes have been marked as deprecated in TYPO3 v12 and will
be removed with v13:
* :php:`\TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\ConditionMatcherInterface`
* :php:`\TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher`
* :php:`\TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher`
* :php:`\TYPO3\CMS\Frontend\Configuration\TypoScript\ConditionMatching\ConditionMatcher`
Impact
======
The TYPO3 Core only uses these classes within the old TypoScript parser classes,
which have been :ref:`deprecated <deprecation-99120-1670428555>` as well.
Using the classes will trigger a deprecation level log entry.
Affected installations
======================
There was probably little need to implement new variants of the above classes as
the underlying :php:`ExpressionLanguage` construct has its own API to add new
variables and functions for this TypoScript condition related to Symfony expression
language usage.
Migration
=========
No direct migration possible. These classes have been merged into the new
TypoScript parser approach, specifically for class
:php:`\TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor`.
Adding TypoScript related expression language variables and functions should be
done using :php:`\TYPO3\CMS\Core\ExpressionLanguage\ProviderInterface`.
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,80 @@
.. include:: /Includes.rst.txt
.. _deprecation-100047-1677608959:
===============================================================================
Deprecation: #100047 - Page TSconfig and user TSconfig must not rely on request
===============================================================================
See :issue:`100047`
Description
===========
Using :typoscript:`request` and function :typoscript:`ip()` in page TSconfig or
user TSconfig conditions has been marked as deprecated in TYPO3 v12. Such conditions
will stop working in TYPO3 v13 and will always evaluate to false.
Page TSconfig and user TSconfig should not rely on request related data: They should
not check for given arguments or similar: the main reason is that the Backend
:php:`DataHandler` makes heavy use of page TSconfig, but the DataHandler itself is
not request-aware. The DataHandler (the code logic that updates data in the database
in the backend) can be used and must work in a CLI context, so any page TSconfig that
depends on a given request is flawed by design since it will never act as expected
in a CLI context.
To avoid further issues with the DataHandler in web and CLI contexts,
TSconfig-related conditions must no longer be request-aware.
Impact
======
Using request-related conditions in page TSconfig or user TSconfig will raise a
deprecation level warning in TYPO3 v12 and will always evaluate to false in
TYPO3 v13.
Affected installations
======================
There may be instances of page TSconfig using conditions using
request-related conditions. These need to look for different solutions
that achieve a similar goal.
Migration
=========
Try to get rid of :typoscript:`ip()` or request related information in
page TSconfig conditions.
A typical example is highlighting something when a developer is
using the live domain:
.. code-block:: typoscript
[request.getRequestHost() == 'development.my.site']
mod.foo = bar
[end]
Switch to the application context in such cases:
.. code-block:: typoscript
[applicationContext == "Development"]
mod.foo = bar
[end]
There are similar alternatives for other use cases: You can not rely on given
GET / POST arguments anymore, but it should be possible to switch to
:typoscript:`backend.user.isAdmin` or similar conditions in most cases, or to
handle related switches within controller classes in PHP.
Relying on request arguments for page TSconfig conditions is fiddly,
especially when using this for core related controllers: those are not considered
API and may change at anytime. Instead, needs should be dealt with explicitly using
toggles within controllers.
.. index:: TSConfig, NotScanned, ext:backend
@@ -0,0 +1,67 @@
.. include:: /Includes.rst.txt
.. _deprecation-100053-1677670333:
============================================
Deprecation: #100053 - GeneralUtility::_GP()
============================================
See :issue:`100053`
Description
===========
The method :php:`\TYPO3\CMS\Core\Utility\GeneralUtility::_GP()` 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:`ServerRequestInterface`,
and should avoid accessing superglobals :php:`$_GET` and :php:`$_POST`
directly. This also avoids future side-effects when using sub-requests. Some
:php:`GeneralUtility` related helper methods like :php:`_GP()` violate this,
using them is considered a technical debt. They are being phased out.
Impact
======
Calling the method from PHP code will log a PHP deprecation level entry,
the method will be removed with TYPO3 v13.
Affected installations
======================
TYPO3 installations with third-party extensions using :php:`GeneralUtility::_GP()`
are affected, typically in TYPO3 installations which
have been migrated to the latest TYPO3 Core versions and
haven't been adapted properly yet.
The extension scanner will find usages with a strong match.
Migration
=========
:php:`GeneralUtility::_GP()` is a helper method that retrieves
incoming HTTP `GET` query arguments and `POST` body 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::_GP('tx_scheduler');
// After
$value = $request->getParsedBody()['tx_scheduler'] ?? $request->getQueryParams()['tx_scheduler'] ?? null;
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,88 @@
.. include:: /Includes.rst.txt
.. _deprecation-100071-1677853787:
========================================================
Deprecation: #100071 - Magic repository findBy() methods
========================================================
See :issue:`100071`
Description
===========
Extbase repositories come with a magic :php:`__call()` method to allow calling
the following methods without implementing them:
- :php:`findBy[PropertyName]($propertyValue)`
- :php:`findOneBy[PropertyName]($propertyValue)`
- :php:`countBy[PropertyName]($propertyValue)`
These have now been marked as deprecated, as they are "magic", meaning
that proper IDE support is not possible, and other PHP-related tool
functionality such as PhpStorm.
In addition, it is not possible for Extbase repositories
to build their own magic method functionality as the logic is already
in use.
Impact
======
As these methods are widely used in almost all Extbase-based extensions,
they are marked as deprecated in TYPO3 v12, but will only trigger a deprecation
notice in TYPO3 v13, as they will be removed in TYPO3 v14.
This way, migration towards the new API methods can be made without
pressure.
Affected installations
======================
All installations with third-party extensions that use those magic methods.
Migration
=========
A new set of methods without all the downsides have been added:
- :php:`findBy(array $criteria, ...): QueryResultInterface`
- :php:`findOneBy(array $criteria, ...):object|null`
- :php:`count(array $criteria, ...): int`
The naming of the methods follows those of `doctrine/orm` and only
:php:`count()` differs from the formerly :php:`countBy()`. While all magic
methods only allow for a single comparison (`propertyName` = `propertyValue`),
those methods allow for multiple comparisons, called constraints.
`findBy[PropertyName]($propertyValue)` can be replaced with a call to `findBy`:
.. code-block:: php
$this->blogRepository->findBy(['propertyName' => $propertyValue]);
`findOneBy[PropertyName]($propertyValue)` can be replaced with a call to `findOneBy`:
.. code-block:: php
$this->blogRepository->findOneBy(['propertyName' => $propertyValue]);
`countBy[PropertyName]($propertyValue)` can be replaced with a call to `count`:
.. code-block:: php
$this->blogRepository->count(['propertyName' => $propertyValue]);
.. attention::
Please note that the (not-magic) methods `findByUid()` and `findByIdentifier()` did **not**
get deprecated or removed, and are still valid to be used.
Using these methods will fetch a given domain object by it's UID, ignoring possible storage
page settings - unlike `findBy([...])`, which does respect those settings.
.. index:: PHP-API, NotScanned, ext:extbase
@@ -0,0 +1,60 @@
.. include:: /Includes.rst.txt
.. _deprecation-100232-1679344508:
=========================================================
Deprecation: #100232 - $TBE_STYLES skinning functionality
=========================================================
See :issue:`100232`
Description
===========
The global configuration array :php:`$TBE_STYLES` has been deprecated in favor of a new
setting :php:`$TYPO3_CONF_VARS['BE']['stylesheets']`. Previously, before
TYPO3 v6.0, :php:`$TBE_STYLES` allowed for defining more styles within PHP instead
of using CSS.
However, now that CSS has become been much more powerful than 10 years ago,
it is time to change the logic and also consolidate TYPO3's internal configuration
settings.
This deprecation is in order to be more flexible for styling purposes, as
the registration of custom stylesheets can now be handled on a per-project
basis.
Extensions can use almost the same syntax, however registration is now done
in an extension's :file:`ext_localconf.php` to reduce loading times for
:file:`ext_tables.php` files.
Impact
======
Registration of backend styles via :php:`$GLOBALS['TBE_STYLES']['skins']` in
an extension's :file:`ext_tables.php` file will trigger a PHP
deprecation notice.
Setting :php:`$GLOBALS['TBE_STYLES']['stylesheets']['admPanel']` will also
trigger a deprecation notice every time the Admin Panel is loaded in the
TYPO3 frontend.
Affected installations
======================
TYPO3 installations with custom styling in the TYPO3 backend or the Admin Panel
via :php:`$GLOBALS['TBE_STYLES']`.
Migration
=========
Migrate to the new configuration setting :php:`$GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets']`
which can be set per site or within an extension's :file:`ext_localconf.php`.
For a custom stylesheet in the TYPO3 Admin Panel, it is recommended to use the
new AdminPanel Module API (available since TYPO3 v9 LTS) where custom CSS and
JavaScript files can be registered dynamically.
.. index:: Backend, LocalConfiguration, PHP-API, FullyScanned, ext:backend
@@ -0,0 +1,58 @@
.. include:: /Includes.rst.txt
.. _deprecation-100237-1679393509:
====================================================
Deprecation: #100237 - TypoScript-related exceptions
====================================================
See :issue:`100237`
Description
===========
Two exception classes related to the TypoScript condition matching logic have been
marked as deprecated in TYPO3 v12 and will be removed in v13:
* :php:`\TYPO3\CMS\Core\Exception\MissingTsfeException`
* :php:`\TYPO3\CMS\Core\Configuration\TypoScript\Exception\InvalidTypoScriptConditionException`
Impact
======
Both exceptions should have been marked :php:`@internal` within the core, but
were not.
The exception :php:`\TYPO3\CMS\Core\Exception\MissingTsfeException` was an internal
communication class and was caught internally, the use case was solved in a more
simple way avoiding the exception.
The exception :php:`\TYPO3\CMS\Core\Configuration\TypoScript\Exception\InvalidTypoScriptConditionException`
was related to conditions which triggered a warning within the symfony expression language. Those were
turned into this exception in TYPO3 v11. In TYPO3 v12, the original exception will bubble up, forcing
developers to fix the broken Symfony condition syntax.
Affected installations
======================
Third-party extensions most likely neither throw nor catch these exceptions, the
extension scanner will find possible usages.
Migration
=========
No direct migration available.
.. note::
Using the :typoscript:`getTSFE()` function, developers have to ensure
that "TSFE" is available before accessing its properties. A missing "TSFE",
e.g. in backend context, does no longer automatically evaluate the whole
condition to :php:`FALSE`. Instead, the function returns :php:`NULL`,
which can be checked using either :typoscript:`[getTSFE() && getTSFE().id == 42]`
or the null-safe operator :typoscript:`[getTSFE()?.id == 42]`.
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,78 @@
.. include:: /Includes.rst.txt
.. _deprecation-100247-1679480707:
======================================================================
Deprecation: #100247 - Various interconnected methods in EXT:scheduler
======================================================================
See :issue:`100247`
Description
===========
The scheduler system extension, responsible for executing long-running, timed
or recurring tasks, has been included since TYPO3 v4.3, but never received an
overhaul of its code base.
Back then, the main :php:`\TYPO3\CMS\Scheduler\Scheduler` class and the
:php:`\TYPO3\CMS\Scheduler\Task\AbstractTask` class were the main API classes, all logic being included,
whereas :php:`AbstractTask` is the main class that all custom tasks within
extensions derive from.
However, in the past 15 years TYPO3's code base has undergone a lot of API
design changes related to separation of concerns. In order to achieve this in
the scheduler extension, almost all access to the actual database access around
task retrieving and scheduling has been moved into its own
:php:`\TYPO3\CMS\Scheduler\Domain\Repository\SchedulerTaskRepository` class.
For this reason, the following methods within the original API classes are now
either marked as deprecated or internal - not part of TYPO3's public API
anymore - as they have now been moved into the new repository class.
* :php:`Scheduler->addTask()`
* :php:`Scheduler->log()` - marked as internal
* :php:`Scheduler->removeTask()`
* :php:`Scheduler->saveTask()`
* :php:`Scheduler->fetchTask()`
* :php:`Scheduler->fetchTaskRecord()`
* :php:`Scheduler->fetchTaskWithCondition()`
* :php:`Scheduler->isValidTaskObject()`
* :php:`Scheduler->log()` - marked as internal
* :php:`AbstractTask->isExecutionRunning()`
* :php:`AbstractTask->markExecution()`
* :php:`AbstractTask->unmarkExecution()`
* :php:`AbstractTask->unmarkAllExecutions()`
* :php:`AbstractTask->save()` - marked as internal
* :php:`AbstractTask->remove()`
* :php:`AbstractTask->setScheduler()` - marked as internal
* :php:`AbstractTask->unsetScheduler()` - marked as internal
* :php:`AbstractTask->registerSingleExecution()` - marked as internal
* :php:`AbstractTask->getExecution()` - marked as internal
* :php:`AbstractTask->setExecution()` - marked as internal
* :php:`AbstractTask->getNextDueExecution()` - marked as internal
* :php:`AbstractTask->areMultipleExecutionsAllowed()` - marked as internal
* :php:`AbstractTask->stop()` - marked as internal
Impact
======
Calling any of the deprecated methods will trigger a PHP warning. Using the
internal methods should be avoided and is not covered by the TYPO3 backwards
compatibility promise.
Affected installations
======================
TYPO3 installations with extensions that include custom scheduler tasks accessing
these methods. The Extension Scanner might be helpful to detect these usages.
Migration
=========
Use the :php:`SchedulerTaskRepository` methods instead.
.. index:: PHP-API, PartiallyScanned, ext:scheduler
@@ -0,0 +1,41 @@
.. include:: /Includes.rst.txt
.. _deprecation-100278-1679605129:
======================================================
Deprecation: #100278 - PostLoginFailureProcessing hook
======================================================
See :issue:`100278`
Description
===========
The hook :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['postLoginFailureProcessing']`
which can be used to handle custom notifications that a login in a frontend or
backend context failed, has been marked as deprecated.
Impact
======
If the hook is registered in a TYPO3 installation, a PHP :php:`E_USER_DEPRECATED`
error is triggered.
The extension scanner also detects any usage of the deprecated interface as
a strong match, and the definition of the hook as a weak match.
Affected installations
======================
TYPO3 installations with custom extensions using this hook.
Migration
=========
Migrate to the newly introduced PSR-14 event
:ref:`\\TYPO3\\CMS\\Core\\Authentication\\Event\\LoginAttemptFailedEvent <feature-100278-1679604666>`.
.. index:: Backend, Frontend, PHP-API, FullyScanned, ext:core
@@ -0,0 +1,52 @@
.. include:: /Includes.rst.txt
.. _deprecation-100307-1679924603:
====================================================================
Deprecation: #100307 - Various hooks related to authentication users
====================================================================
See :issue:`100307`
Description
===========
The following hooks have been marked as deprecated:
* :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing']`
* :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_post_processing']`
* :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['backendUserLogin']`
They can be used to add notifications or actions to a TYPO3 installation
after a frontend user or a backend user has actively logged
in or logged out.
Impact
======
If one of the hooks is registered in a TYPO3 installation,
a PHP :php:`E_USER_DEPRECATED` error is triggered when a user logs
in or logs out.
Affected installations
======================
TYPO3 installations with custom extensions using one of these hooks.
The extension scanner detects any usage of the hooks.
Migration
=========
Migrate to the newly introduced PSR-14 events:
* :php:`\TYPO3\CMS\Core\Authentication\Event\BeforeUserLogoutEvent`
* :php:`\TYPO3\CMS\Core\Authentication\Event\AfterUserLoggedOutEvent`
* :php:`\TYPO3\CMS\Core\Authentication\Event\AfterUserLoggedInEvent`
.. seealso::
:ref:`feature-100307-1679924551`
.. index:: Backend, Frontend, PHP-API, FullyScanned, ext:core
@@ -0,0 +1,47 @@
.. include:: /Includes.rst.txt
.. _deprecation-83608-1679521195:
================================================================
Deprecation: #83608 - Backend user's getDefaultUploadFolder hook
================================================================
See :issue:`83608`
Description
===========
The hook :php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['getDefaultUploadFolder']` has been marked
as deprecated in favor of a new PSR-14 event :php:`AfterDefaultUploadFolderWasResolvedEvent`.
Along with the hook, the two methods:
* :php:`BackendUserAuthentication->getDefaultUploadFolder()`
* :php:`BackendUserAuthentication->getDefaultUploadTemporaryFolder()`
have been marked as internal, as they are not considered part of the public TYPO3 API anymore.
Impact
======
Using this hook will trigger a PHP deprecation notice every time the method
:php:`BackendUserAuthentication->getDefaultUploadFolder()` is called,
Affected installations
======================
TYPO3 installations with special functionality in extensions using these methods or the hook.
Migration
=========
Migrate to the PSR-14 event :ref:`AfterDefaultUploadFolderWasResolvedEvent <feature-83608-1669634686>`
in your custom extensions.
It is fired after various page TSconfig settings have been applied and allows for more
fine-grained control.
.. index:: Backend, PHP-API, FullyScanned, ext:backend
@@ -0,0 +1,52 @@
.. include:: /Includes.rst.txt
.. _deprecation-97390-1667657114:
=============================================================================
Deprecation: #97390 - TypoScript validators for password reset in ext:felogin
=============================================================================
See :issue:`97390`
Description
===========
The TypoScript password validation configured through
:typoscript:`plugin.tx_felogin_login.settings.passwordValidators` has been
marked as deprecated.
The TypoScript validators are used when the feature toggle
`security.usePasswordPolicyForFrontendUsers` is set to `false` (default for
existing TYPO3 installations).
An upgrade wizard will ask the user during the TYPO3 upgrade
if `security.usePasswordPolicyForFrontendUsers` should be activated or, if
deprecated, TypoScript validators should be used.
Impact
======
Validators configured in
:typoscript:`plugin.tx_felogin_login.settings.passwordValidators` will
trigger a deprecation log entry when a password reset is performed.
Affected installations
======================
TYPO3 installations using validators configured in
:typoscript:`plugin.tx_felogin_login.settings.passwordValidators`.
Migration
=========
Special password requirements configured using custom validators in TypoScript
must be migrated to a custom password policy validator as described
in :ref:`#97388 <feature-97388>`.
Before creating a custom password policy validator, it is recommended to
check if the :php:`CorePasswordValidator` used in the default password
policy suits current password requirements.
.. index:: Frontend, NotScanned, ext:felogin
@@ -0,0 +1,279 @@
.. include:: /Includes.rst.txt
.. _deprecation-99739-1674869090:
======================================================
Deprecation: #99739 - Indexed array keys for TCA items
======================================================
See :issue:`99739`
Description
===========
Using indexed array keys for the :php:`items` configuration of TCA types
:php:`select`, :php:`radio` and :php:`check` is now deprecated.
Impact
======
Using indexed array keys for the :php:`items` configuration array items of TCA
types :php:`select`, :php:`radio` and :php:`check` will trigger a deprecation
level log entry. A TCA migration is in place.
Affected installations
======================
All installations having custom extensions that make use of TCA types
:php:`select`, :php:`radio` or :php:`check` and define at least one entry in
the :php:`items` array.
itemsProcFunc
_____________
The :php:`items` array handed over to custom :php:`itemsProcFunc` functions
contains the new object type :php:`TYPO3\CMS\Core\Schema\Struct\SelectionItem`
which acts as a compatibility layer for old style indexed keys. Accessing,
writing and reading items still work in the old way. Added items will be
automatically converted. For third-party extensions supporting both TYPO3 v11
(or lower) and v12 it is recommended to keep using indexed keys.
Migration
=========
To migrate your TCA, change all indexed keys according to the following mapping
table:
+--------+-------------+
| Before | After |
+--------+-------------+
| 0 | label |
+--------+-------------+
| 1 | value |
+--------+-------------+
| 2 | icon |
+--------+-------------+
| 3 | group |
+--------+-------------+
| 4 | description |
+--------+-------------+
Examples:
.. code-block:: php
// Before
'select' => [
'label' => 'My select field',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
[
'Selection 1',
'1',
'my-icon-identifier',
'default',
],
[
0 => 'Selection 2',
1 => '2',
],
],
],
],
// After
'select' => [
'label' => 'My select field',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
[
'label' => 'Selection 1',
'value' => '1',
'icon' => 'my-icon-identifier',
'group' => 'default',
],
[
'label' => 'Selection 2',
'value' => '2',
],
],
],
],
// Before
'select_checkbox' => [
'label' => 'My select checkbox field',
'config' => [
'type' => 'select',
'renderType' => 'selectCheckBox',
'items' => [
[
'My select checkbox field',
'1',
'my-icon-identifier',
'default',
'My custom description',
],
[
0 => 'My select checkbox field',
1 => 'value' => '2',
],
],
],
],
// After
'select_checkbox' => [
'label' => 'My select checkbox field',
'config' => [
'type' => 'select',
'renderType' => 'selectCheckBox',
'items' => [
[
'label' => 'My select checkbox field',
'value' => '1',
'icon' => 'my-icon-identifier',
'group' => 'default',
'description' => 'My custom description',
],
[
'label' => 'My select checkbox field',
'value' => '2',
],
],
],
],
// Before
'radio' => [
'label => 'My radio field',
'config' => [
'type' => 'radio',
'items' => [
[
'Radio 1',
'1',
],
[
0 => 'Radio 2',
1 => '2',
],
],
],
],
// After
'radio' => [
'label => 'My radio field',
'config' => [
'type' => 'radio',
'items' => [
[
'label' => 'Radio 1',
'value' => '1',
],
[
'label' => 'Radio 2',
'value' => '2',
],
],
],
],
// Before
'check' => [
'config' => [
'type' => 'check',
'items' => [
['Click on me'],
],
],
],
// After
'check' => [
'config' => [
'type' => 'check',
'items' => [
['label' => 'Click on me'],
],
],
],
// Before
'check' => [
'config' => [
'type' => 'check',
'items' => [
[
'invertStateDisplay' => true,
0 => 'Click on me',
],
],
],
],
// After
'check' => [
'config' => [
'type' => 'check',
'items' => [
[
'invertStateDisplay' => true,
'label' => 'Click on me',
],
],
],
],
Before:
.. code-block:: xml
<select_single_1>
<label>select_single_1 description</label>
<description>field description</description>
<config>
<type>select</type>
<renderType>selectSingle</renderType>
<items>
<numIndex index="0">
<numIndex index="0">foo1</numIndex>
<numIndex index="1">foo1</numIndex>
</numIndex>
<numIndex index="1">
<numIndex index="0">foo2</numIndex>
<numIndex index="1">foo2</numIndex>
</numIndex>
</items>
</config>
</select_single_1>
After:
.. code-block:: xml
<select_single_1>
<label>select_single_1 description</label>
<description>field description</description>
<config>
<type>select</type>
<renderType>selectSingle</renderType>
<items>
<numIndex index="0">
<label>foo1</label>
<value>foo1</value>
</numIndex>
<numIndex index="1">
<label>foo2</label>
<value>foo2</value>
</numIndex>
</items>
</config>
</select_single_1>
.. index:: TCA, FullyScanned, ext:backend
@@ -0,0 +1,59 @@
.. include:: /Includes.rst.txt
.. _deprecation-99810-1675704638:
==================================================================
Deprecation: #99810 - "versionNumberInFilename" option now boolean
==================================================================
See :issue:`99810`
Description
===========
The system-wide setting :php:`$TYPO3_CONF_VARS['FE']['versionNumberInFilename']`
was previously evaluated as a "string" value, having three possible options:
* ""
* "querystring"
* "embed"
Depending on the option, resources used in TYPO3's frontend templates, such as
JavaScript or CSS assets, had their "modification time" in either the
querystring (:samp:`myfile.js?1675703622`), or in the file name itself
:samp:`myfile.1675703622.js` - the "embed" option). The latter option required a
:file:`.htaccess` rule.
This existing feature ("cachebusting") is especially important for proxy / CDN
setups.
For the sake of simplicity, the option is now a boolean option - and behaves
similarly to the backend variant :php:`$TYPO3_CONF_VARS['BE']['versionNumberInFilename']`.
Impact
======
If the option is now set to "false", it behaves as "querystring" did before, setting
it to "true", the feature behaves exactly as "embed". The original empty option
is removed, so all assets within the TYPO3 frontend rendering always include
cachebusting, by default a querystring, which is fully backwards-compatible.
Affected installations
======================
TYPO3 installations that have actively set this option in
:file:`LocalConfiguration.php`, :file:`AdditionalConfiguration.php` or in an
extension :file:`ext_localconf.php`.
Migration
=========
When updating TYPO3 and accessing the maintenance area, an explicitly set option
is automatically migrated. If this is not possible - for example, configuration in
:file:`AdditionalConfiguration.php` is set - the value is always migrated
on-the-fly when the setting is evaluated.
.. index:: LocalConfiguration, PHP-API, NotScanned, ext:core
@@ -0,0 +1,65 @@
.. include:: /Includes.rst.txt
.. _deprecation-99882-1675873624:
===========================================================
Deprecation: #99882 - Site language "typo3Language" setting
===========================================================
See :issue:`99882`
Description
===========
A language configuration defined for a site has had various settings, one of
them being :yaml:`typo3Language`. The setting is used to define the language key which
should be used for fetching the proper XLF file (such as :file:`de_AT.locallang.xlf`).
Since TYPO3 v12 it is unnecessary to set this property in the site configuration
and it is removed from the backend UI. The information is now automatically
derived from the :yaml:`locale` setting of the site configuration.
The previous value "default", which matched "en" as language key is now unnecessary
as "default" is now a synonym for "en".
As a result, the amount of options in the user interface for integrators is
reduced.
Impact
======
An administrator cannot select a value for the :yaml:`typo3Language` setting anymore
via the TYPO3 backend. If a custom value is required, the site configuration
needs to be manually edited and the :yaml:`typo3Language` setting needs to be added.
If this is the case, please file a bug report in order to give the TYPO3
development team feedback on what use case is required.
However, saving a site configuration via the TYPO3 backend will still
keep the :yaml:`typo3Language` setting so no values will be lost.
Affected installations
======================
TYPO3 installations created before TYPO3 v12.3.
Migration
=========
No migration is needed as the explicit option is still evaluated. It is however
recommended to check if the setting is really necessary.
Examples:
#. If :yaml:`typo3Language: "default"` and :yaml:`locale: "en_US.UTF-8"`, the setting can be removed.
#. If :yaml:`typo3Language: "pt_BR"` and :yaml:`locale: "pt_BR.UTF-8"`, the setting can be removed.
#. If :yaml:`typo3Language: "de"` and :yaml:`locale: "de_AT.UTF-8"` , the setting can be removed,
plus the label files check for :file:`de_AT.locallang.xlf` and :file:`de.locallang.xlf`
as fallback when accessing a translated label.
#. If :yaml:`typo3Language: "pt_BR"` and :yaml:`locale: "de_DE.UTF-8"` it is likely
a misconfiguration in the setup, and should be analyzed if the custom value is really needed.
.. index:: YAML, NotScanned, ext:core
@@ -0,0 +1,43 @@
.. include:: /Includes.rst.txt
.. _deprecation-99900-1676292952:
======================================================================
Deprecation: #99900 - $limit parameter of GeneralUtility::intExplode()
======================================================================
See :issue:`99900`
Description
===========
The static method :php:`GeneralUtility::intExplode()` has a lesser known fourth
parameter :php:`$limit`. The reason it was added to the :php:`intExplode()` method
is purely historical, when it used to extend the :php:`trimExplode()` method. The
dependency was resolved, but the parameter stayed. As this method is supposed to
only return :php:`int` values in an array, the :php:`$limit` parameter is now
deprecated.
Impact
======
Calling :php:`GeneralUtility::intExplode()` with the fourth parameter
:php:`$limit` will trigger a deprecation warning and will add an entry to the
deprecation log.
Affected installations
======================
TYPO3 installations that call :php:`GeneralUtility::intExplode()` with the
fourth parameter :php:`$limit`.
Migration
=========
In the rare case that you are using the :php:`$limit` parameter you will need to
switch to PHP's native :php:`explode()` function, and then use
:php:`array_map()` to convert the resulting array to integers. If that's
impractical, you can simply copy the old :php:`intExplode` method to your own
code.
.. index:: PHP-API, FullyScanned, ext:core
@@ -0,0 +1,68 @@
.. include:: /Includes.rst.txt
.. _deprecation-99905-1675963182:
=======================================================
Deprecation: #99905 - Site language "iso-639-1" setting
=======================================================
See :issue:`99905`
Description
===========
A language configuration defined for a site has had various settings, one of
them being :yaml:`iso-639-1` (also known as "twoLetterIsoCode").
This setting was previously introduced to define the current ISO 639-1 code, which
was different from the :yaml:`locale` or the :yaml:`typo3Language` setting. However,
this information is now properly retrieved with the method:
:php:`SiteLanguage->getLocale()->getLanguageCode()`.
Since TYPO3 v12 it is not necessary to set this property in the site configuration
anymore, and it has been removed from the backend UI. The information is now automatically
derived from the :yaml:`locale` setting of the site configuration.
This property originally came from an option in TypoScript called
:typoscript:`config.sys_language_isocode` which in turn was created in favor of
the previous :sql:`sys_language` database table. The TYPO3 Core never evaluated this
setting properly before TYPO3 v9.
As a result, the amount of options in the user interface for integrators is
reduced.
The PHP method :php:`SiteLanguage->getTwoLetterIsoCode()` serves no purpose
anymore and is deprecated.
This also affects the TypoScript :typoscript:`getData` property :typoscript:`siteLanguage:twoLetterIsoCode`,
and the TypoScript condition :typoscript:`[siteLanguage("twoLetterIsoCode")]`.
Impact
======
Using the TypoScript settings or the PHP method will trigger a PHP deprecation notice.
An administrator cannot select a value for the :yaml:`iso-639-1` setting anymore
via the TYPO3 backend. However, saving a site configuration via the
TYPO3 backend will still keep the :yaml:`iso-639-1` setting so no information is lost.
Affected installations
======================
TYPO3 installations actively accessing this property via PHP or TypoScript.
Migration
=========
No migration is needed as the explicit option is still evaluated. It is however
recommended to check if the setting is really necessary, and if the first part of the
:yaml:`locale` setting matches the :yaml:`iso-639-1` setting. If so, the line with
:yaml:`iso-639-1` can be removed.
As for TypoScript, it is recommended to use :typoscript:`siteLanguage:locale:languageCode`
instead of :typoscript:`siteLanguage:twoLetterIsoCode`.
.. index:: PHP-API, TypoScript, YAML, PartiallyScanned, ext:frontend
@@ -0,0 +1,61 @@
.. include:: /Includes.rst.txt
.. _deprecation-99908-1675976983:
======================================================
Deprecation: #99908 - Site language "hreflang" setting
======================================================
See :issue:`99908`
Description
===========
A language configuration defined for a site has had various settings, one of
them being :yaml:`hreflang`. The setting is used to generate hreflang meta tags to
link to alternative language versions of a translated page, and to add the
:html:`lang` attribute to the :html:`<html>` tag of a frontend page in HTML format.
Since TYPO3 v12 it is not necessary to set this property in the site configuration
anymore. The information is now automatically
derived from the :yaml:`locale` setting of the site configuration if not set
in the site configuration.
This also affects the TypoScript :typoscript:`getData` property
:typoscript:`siteLanguage:hrefLang`, and the TypoScript condition
:typoscript:`[siteLanguage("hrefLang")]`.
Impact
======
Using the TypoScript settings or the PHP method will trigger a PHP deprecation
notice.
An administrator cannot select a value for the :yaml:`hreflang` setting anymore
via the TYPO3 backend. However, when saving a site configuration via the
TYPO3 backend it will still keep the :yaml:`hreflang` setting so no information is lost.
Affected installations
======================
TYPO3 installations actively accessing this property via PHP or TypoScript.
Migration
=========
No migration is needed as the explicit option is still evaluated. It is however
recommended to check if the setting is really necessary, and if the locale of
the site language in the :file:`config.yaml` matches the same value - even in a
different format (:yaml:`locale: "de_AT.UTF-8"`, :yaml:`hreflang: "de-AT"`) - the setting
:yaml:`hreflang` can be removed.
Any calls to :php:`SiteLanguage->getHrefLang()` can be replaced by
:php:`SiteLanguage->getLocale()->getName()`.
As for TypoScript, it is recommended to use :typoscript:`siteLanguage:locale:full`
instead of :typoscript:`siteLanguage:hrefLang`.
.. index:: Frontend, PHP-API, TypoScript, YAML, PartiallyScanned, ext:core
@@ -0,0 +1,66 @@
.. include:: /Includes.rst.txt
.. _deprecation-99916-1676027922:
=======================================================
Deprecation: #99916 - Site language "direction" setting
=======================================================
See :issue:`99916`
Description
===========
A language configuration defined for a site has had various settings, one of
them being :yaml:`direction`. The setting is used to add the :html:`dir` attribute to the
:html:`<html>` tag of a frontend page in HTML format, defining the direction of the
language.
However, according to https://meta.wikimedia.org/wiki/Template:List_of_language_names_ordered_by_code
the list of languages that have a directionality of "right-to-left"
is fixed and does not need to be configured anymore.
Since TYPO3 v12 it is not necessary to set this property in the site configuration
anymore, and has been removed from the backend UI. The information is now automatically
derived from the :yaml:`locale` setting of the site configuration.
As a result, the amount of options in the user interface for integrators is
reduced.
The PHP method :php:`SiteLanguage->getDirection()` serves no purpose anymore and
is deprecated.
Impact
======
Using the PHP method will trigger a PHP deprecation notice.
An administrator can not select a value for the :yaml:`direction` setting anymore
via the TYPO3 backend. However, when saving a site configuration via the
TYPO3 backend it will still keep the :yaml:`direction` setting so no information is lost.
Affected installations
======================
TYPO3 installations actively accessing this property via PHP or TypoScript, and
mainly related to TYPO3 installations with languages that have a "right-to-left"
reading direction.
Migration
=========
No migration is needed as the explicit option is still evaluated. It is however
not necessary in 99.99% of the use cases. If the locale of the site language in the
site's :file:`config.yaml` matches the natural direction of the language
(Arabic and direction = rtl), the setting :yaml:`direction` can be removed.
Any calls to :php:`SiteLanguage->getDirection()` can be replaced by
:php:`SiteLanguage->getLocale()->isRightToLeftLanguageDirection() ? 'rtl' : 'ltr'`.
The frontend output does not set :html:`ltr` in the :html:`<html>` tag anymore, as this is the default
for HTML documents (see https://www.w3.org/International/questions/qa-html-dir).
.. index:: PHP-API, YAML, FullyScanned, ext:core
@@ -0,0 +1,43 @@
.. include:: /Includes.rst.txt
.. _deprecation-99932-1676186779:
================================================================
Deprecation: #99932 - PageRenderer::removeLineBreaksFromTemplate
================================================================
See :issue:`99932`
Description
===========
The following method has been marked as deprecated and will be removed
in TYPO3 v13:
* :php:`\TYPO3\CMS\Core\Page\PageRenderer::enableDebugMode()`
The method acts as as shortcut to quickly disable some functions in the backend
context to ease output inspection. However, the properties set by the
method are ignored in the backend context anyway, the method is obsolete.
Impact
======
Using the method will raise a deprecation level log entry and will stop
working in TYPO3 v13.
Affected installations
======================
Instances with extensions that call the method are affected.
The extension scanner reports usages as a weak match.
Migration
=========
All calls to the deprecated messages should be removed from the codebase.
.. index:: Backend, TCA, FullyScanned, ext:core
@@ -0,0 +1,29 @@
.. include:: /Includes.rst.txt
.. _feature-100027-1677251094:
=======================================================================
Feature: #100027 - Copy files and folders within the File > List module
=======================================================================
See :issue:`100027`
Description
===========
With TYPO3 v12.2, the feature to
:ref:`drag+drop files and folders <feature-99733-1675025218>` between the tree
structure was added. Now it is also possible to copy or move resources within
the actual file listing (tile view or list view), for example, into a different subfolder
by selecting them, and using the mouse to drop them on to a target folder.
Impact
======
The :guilabel:`File > List` module is now fully usable with drag+drop between
the tree and within the listing itself.
All features make it easier for editors to manage and organize the digital
assets used within TYPO3.
.. index:: Backend, ext:filelist
@@ -0,0 +1,51 @@
.. include:: /Includes.rst.txt
.. _feature-100071-1677853567:
==============================================================
Feature: #100071 - Introduce non-magic repository find methods
==============================================================
See :issue:`100071`
Description
===========
Extbase repositories come with a magic :php:`__call()` method to allow calling
the following methods without implementing:
- :php:`findBy[PropertyName]($propertyValue)`
- :php:`findOneBy[PropertyName]($propertyValue)`
- :php:`countBy[PropertyName]($propertyValue)`
Magic methods are quite handy but they have a huge disadvantage. There is no
proper IDE support i.e. most IDEs show an error or at least a warning,
saying method :php:`findByAuthor()` does not exist. Also, type declarations are
impossible to use because with :php:`__call()` everything is :php:`mixed`. And
last but not least, static code analysis - like PHPStan - cannot properly
analyze those and give meaningful errors.
Therefore, there is a new set of methods without all those downsides:
- :php:`findBy(array $criteria, ...): QueryResultInterface`
- :php:`findOneBy(array $criteria, ...): object|null`
- :php:`count(array $criteria, ...): int`
The naming of those methods follows those of `doctrine/orm` and only
:php:`count()` differs from the formerly :php:`countBy()`. While all magic
methods only allow for a single comparison (`propertyName` = `propertyValue`),
those methods allow for multiple comparisons, called constraints.
Example:
.. code-block:: php
$this->blogRepository->findBy(['author' => 1, 'published' => true]);
Impact
======
The new methods support a broader feature set, support IDEs, static code
analyzers and type declarations.
.. index:: PHP-API, NotScanned, ext:extbase
@@ -0,0 +1,58 @@
.. include:: /Includes.rst.txt
.. _feature-100088-1677965005:
======================================
Feature: #100088 - New TCA type "json"
======================================
See :issue:`100088`
Description
===========
In our effort of introducing dedicated TCA types for special use cases,
a new TCA field type called :php:`json` has been added to TYPO3 Core.
Its main purpose is to simplify the TCA configuration when working with
fields, containing JSON data. It therefore :ref:`replaces <important-100088-1677950866>`
the previously introduced :php:`dbtype=json` of TCA type :php:`user`.
Using the new type, TYPO3 automatically takes care of adding the corresponding
database column.
The TCA type :php:`json` features the following column configuration:
- :php:`behaviour`: :php:`allowLanguageSynchronization`
- :php:`cols`
- :php:`default`
- :php:`enableCodeEditor`
- :php:`fieldControl`
- :php:`fieldInformation`
- :php:`fieldWizard`
- :php:`placeholder`
- :php:`readOnly`
- :php:`required`
- :php:`rows`
.. note::
In case :php:`enableCodeEditor` is set to :php:`true`, which is the default
and the system extension `t3editor` is installed and active, the JSON value
is rendered in the corresponding code editor. Otherwise it is rendered in a
standard `textarea` HTML element.
The following column configuration can be overwritten by page TSconfig:
- :typoscript:`cols`
- :typoscript:`rows`
- :typoscript:`readOnly`
Impact
======
It is now possible to use a dedicated TCA type for rendering of JSON fields.
Using the new TCA type, corresponding database columns are added automatically.
.. index:: Backend, PHP-API, TCA, ext:backend
@@ -0,0 +1,41 @@
.. include:: /Includes.rst.txt
.. _feature-100089-1677961107:
================================================================
Feature: #100089 - Introduce Doctrine DBAL v3 driver middlewares
================================================================
See :issue:`100089`
Description
===========
Since v3, Doctrine DBAL supports adding custom driver middlewares. These
middlewares act as a decorator around the actual `Driver` component.
Subsequently, the `Connection`, `Statement` and `Result` components can be
decorated as well. These middlewares must implement the
:php:`\Doctrine\DBAL\Driver\Middleware` interface.
A common use case would be a middleware for implementing SQL logging capabilities.
For more information on driver middlewares,
see https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/architecture.html.
Furthermore, you can look up the implementation of the
:php:`\TYPO3\CMS\Adminpanel\Log\DoctrineSqlLoggingMiddleware` in ext:adminpanel
as an example.
Registering a new driver middleware
===================================
.. code-block:: php
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default']['driverMiddlewares']['adminpanel_loggingmiddleware']
= \TYPO3\CMS\Adminpanel\Log\DoctrineSqlLoggingMiddleware::class;
Impact
======
Using custom middlewares allows to enhance the functionality of Doctrine
components.
.. index:: Database, ext:core
@@ -0,0 +1,25 @@
.. include:: /Includes.rst.txt
.. _feature-100093-1678091347:
=================================================================
Feature: #100093 - Show path to record location in group elements
=================================================================
See :issue:`100093`
Description
===========
To ease the usage of `group` fields in the FormEngine, for example, like in the
"Insert records" content element, the record overview now shows the path to the
location where each assigned record is stored, respectively.
Impact
======
Elements of type `group` now show the path to the page where any assigned record
is stored in.
.. index:: Backend, ext:backend
@@ -0,0 +1,43 @@
.. include:: /Includes.rst.txt
.. _feature-100116-1678299307:
============================================================================
Feature: #100116 - Make PSR-7 request accessible for authentication services
============================================================================
See :issue:`100116`
Description
===========
Authentication services can now access the PSR-7 request object via the
:php:`$authInfo` array. Previously, custom TYPO3 authentication services
did not have direct access to the object and therefore had to either
use PHP super globals or TYPO3's `GeneralUtility::getIndpEnv()` method.
The following example shows how to retrieve the PSR-7 request in the
`initAuth()` method of a custom authentication service:
.. code-block:: php
public function initAuth($mode, $loginData, $authInfo, $pObj)
{
/** @var ServerRequestInterface $request */
$request = $authInfo['request'];
/** @var NormalizedParams $normalizedParams */
$normalizedParams = $request->getAttribute('normalizedParams');
$isHttps = $normalizedParams->isHttps();
}
Impact
======
Custom TYPO3 authentication services can now directly access the PSR-7
request object from the authentication process. It is available via the
:php:`request` key of the :php:`$authInfo` array, which is handed over
to the :php:`initAuth()` method.
.. index:: ext:core
@@ -0,0 +1,59 @@
.. include:: /Includes.rst.txt
.. _feature-100143-1678575248:
==================================================================
Feature: #100143 - Add scheduler command to execute and list tasks
==================================================================
See :issue:`100143`
Description
===========
The CLI command :bash:`scheduler:run` of EXT:scheduler offers a way to run a
task using a cronjob. It also allows to run tasks if the UID of the task
is known.
To make it more convenient to use the command, :bash:`scheduler:list` and
:bash:`scheduler:execute` were introduced.
The :bash:`scheduler:list` command shows an overview of all available tasks or
a given group with an option to watch and reload the list every X seconds
(default every 1 second).
Example:
.. code-block:: bash
# List all tasks in group 1 and group 2 and watch for changes every second.
vendor/bin/typo3 scheduler:list --group 1 --group 2 --watch
# List all tasks without a group and watch for changes every 2 seconds.
vendor/bin/typo3 scheduler:list --group 0 --watch 2
# Same as above with shortcut parameter
vendor/bin/typo3 scheduler:list -g 0 -w 2
The :bash:`scheduler:execute` command displays a list of groups and available
tasks for the selection. If a group is selected all tasks within this group are
executed.
Example:
.. code-block:: bash
# Run alls tasks without a group and task 8
vendor/bin/typo3 scheduler:execute --task g:0 --task 8
# Same as above with shortcut parameter
vendor/bin/typo3 scheduler:execute -t g:0 -t 8
Impact
======
The new commands :bash:`scheduler:list` and :bash:`scheduler:execute` enable
the user to manage and run tasks without leaving the terminal.
.. index:: Backend, ext:scheduler
@@ -0,0 +1,26 @@
.. include:: /Includes.rst.txt
.. _feature-100167-1679005733:
====================================================================
Feature: #100167 - AdminPanel: Add SQL and memory metrics to toolbar
====================================================================
See :issue:`100167`
Description
===========
This extends the AdminPanel toolbar with more metrics:
* Peak memory usage
* Amount of SQL queries
* Time spent processing SQL queries
Impact
======
The AdminPanel toolbar now shows more information.
.. index:: Frontend, ext:adminpanel
@@ -0,0 +1,65 @@
.. include:: /Includes.rst.txt
.. _feature-100171-1678869689:
==========================================
Feature: #100171 - Introduce TCA type uuid
==========================================
See :issue:`100171`
Description
===========
In our effort of introducing dedicated TCA types for special use cases,
a new TCA field type called :php:`uuid` has been added to TYPO3 Core.
Its main purpose is to simplify the TCA configuration when working with
fields, containing a UUID.
The TCA type :php:`uuid` features the following column configuration:
- :php:`enableCopyToClipboard`
- :php:`fieldInformation`
- :php:`required`: Defaults to :php:`true`
- :php:`size`
- :php:`version`
.. note::
In case :php:`enableCopyToClipboard` is set to :php:`true`, which is the
default, a button is rendered next to the input field, which allows to copy
the UUID to the clipboard of the operating system.
.. note::
The :php:`version` option defines the UUID version to be used. Allowed
values are `4`, `6` or `7`. The default is `4`. For more information
about the different versions, have a look at the corresponding
`symfony documentation`_.
The following column configuration can be overwritten by page TSconfig:
- :typoscript:`size`
- :typoscript:`enableCopyToClipboard`
An example configuration looks like the following:
.. code-block:: php
'identifier' => [
'label' => 'My record identifier',
'config' => [
'type' => 'uuid',
'version' => 6,
],
],
Impact
======
It is now possible to use a dedicated TCA type for rendering of a UUID field.
Using the new TCA type, corresponding database columns are added automatically.
.. _symfony documentation: https://symfony.com/doc/current/components/uid.html#uuids
.. index:: Backend, TCA, ext:backend
@@ -0,0 +1,97 @@
.. include:: /Includes.rst.txt
.. _feature-100187-1679001588:
=====================================================
Feature: #100187 - ICU-based date and time formatting
=====================================================
See :issue:`100187`
Description
===========
TYPO3 now supports rendering date and time based on formats/patterns defined by
the International Components for Unicode standard (ICU).
TYPO3 previously only supported rendering of dates based on the PHP-native
functions :php:`date()` and :php:`strftime()`.
However, :php:`date()` can only format dates with English texts, such as
"December" as non-localized values, the C-based :php:`strftime()` function works
only with the locale defined in PHP and availability in the underlying operating
system.
In addition, ICU-based date and time formatting is much more flexible in
rendering, as it ships with default patterns for date and time (namely
`FULL`, `LONG`, `MEDIUM` and `SHORT`) which are based on the given locale.
This means, that when the locale `en-US` is given, the short date is rendered
as `mm/dd/yyyy` whereas `de-AT` uses the `dd.mm.yyyy` syntax automatically,
without having to define a custom pattern just by using the SHORT default
pattern.
In addition, the patterns can be adjusted more fine-grained, and can easily
deal with time zones for output when DateTime objects are handed in.
TYPO3 also adds prepared custom patterns:
* `FULLDATE` (like `FULL`, but only the date information)
* `FULLTIME` (like `FULL`, but only the time information)
* `LONGDATE` (like `LONG`, but only the date information)
* `LONGTIME` (like `LONG`, but only the time information)
* `MEDIUMDATE` (like `MEDIUM`, but only the date information)
* `MEDIUMTIME` (like `MEDIUM`, but only the time information)
* `SHORTDATE` (like `SHORT`, but only the date information)
* `SHORTTIME` (like `SHORT`, but only the time information)
See https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax
for more information on the patterns.
Impact
======
A new stdWrap feature called `formattedDate` is added, and the new formatting
can also be used in Fluid's :html:`<f:format.date>` ViewHelper.
The locale is typically fetched from the locale of the site language (stdWrap or
ViewHelper), or the backend user's language (in backend context) for the
ViewHelper usages.
Examples for stdWrap:
.. code-block:: typoscript
page.10 = TEXT
page.10.value = 1998-02-20 3:00:00
# see all available options https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax
page.10.formattedDate = FULL
# optional, if a different locale is wanted other than the Site Language's locale
page.10.formattedDate.locale = de-DE
will result in "Freitag, 20. Februar 1998 um 03:00:00 Koordinierte Weltzeit".
.. code-block:: typoscript
page.10 = TEXT
page.10.value = -5 days
page.10.formattedDate = FULL
page.10.formattedDate.locale = fr-FR
will result in "jeudi 9 mars 2023 à 21:40:49 temps universel coordonné".
Examples for Fluid `<f:format.date>` ViewHelper:
.. code-block:: html
<f:format.date pattern="dd. MMMM yyyy" locale="de-DE">{date}</f:format.date>
will result in "20. Februar 1998".
As soon as the :html:`pattern` attribute is used, the :html:`format` attribute
is disregarded.
Both new ViewHelper arguments are optional.
.. index:: Fluid, PHP-API, TypoScript, ext:core
@@ -0,0 +1,38 @@
.. include:: /Includes.rst.txt
.. _feature-100206-1679299435:
======================================================================
Feature: #100206 - Enable list/tile view for resources in link browser
======================================================================
See :issue:`100206`
Description
===========
With this change, we are rolling out the universal file-list
rendering for files and folders to the link browser. The link
browser implementation for files and folders is now part of the
filelist extension.
The link browser now allows the user to choose the display type
of resources to match the personal preference between list and
tile rendering.
When the user now edits a link for a folder, the entry point is
the parent folder of the selected element folder instead of
showing the contents of the selected resource. The user sees
the selected folder in the presented list, this behavior mimics
the handling of selected files.
Impact
======
The user is now presented a unified experience when handling
resources. The modern filelist rendering is now rolled out to
the link browser and now covers, the filelist module, element
browser and link browser.
.. index:: Backend, FAL, RTE, ext:filelist
@@ -0,0 +1,78 @@
.. include:: /Includes.rst.txt
.. _feature-100218-1679312518:
================================================================
Feature: #100218 - Improved TypoScript and page TSconfig modules
================================================================
See :issue:`100218`
Description
===========
TYPO3 v12 comes with a rewritten TypoScript syntax parser.
See :ref:`breaking-97816-1656350406` and :ref:`feature-97816-1656350667`
for more details on this.
The new parser allowed us to refactor the related backend modules along the way:
While many of these have been done with earlier v12 releases already, v12.3 now
finishes the basic feature set of these new and refactored modules.
This is a summary of these UI changes:
Frontend TypoScript
-------------------
* The well-known main module :guilabel:`Web > Template` has been renamed and moved,
and can be found as :guilabel:`Site Management > TypoScript`.
* "TypoScript records overview": This submodule was more hidden in previous versions.
It gives an overview which page records have TypoScript template records.
* "Constant Editor": This submodule is mainly kept as-is from previous versions.
* "Edit TypoScript Record": This submodule was known as "Info / Modify" from previous
versions. Its main functionality is kept.
* "Active TypoScript": This submodule was known as "TypoScript Object Browser" in
previous versions. The UI of this module received a major streamlining and gives
a better overview of the compiled TypoScript on a page: The module now shows
both "constants" and "setup" at the same time, gives more detail information,
and the tree is quicker to navigate.
* "Included TypoScript": This submodule was known as "Template Analyzer" in
previous versions. Similar to "Active TypoScript", it shows "constants" and
"setup" at the same time. It allows to simulate the effect of conditions
to the include tree, and shows sub-includes from :typoscript:`@import` and
similar as nodes within the tree. A basic syntax scanner finds broken TypoScript
syntax snippets.
Page TSconfig
-------------
* The previous submodule :guilabel:`Web > Info > Page TSconfig` has been heavily refactored
and can be found as new main module :guilabel:`Site Management > Page TSconfig`.
* The new page TSconfig module is similar in its look and feel to the TypoScript
module.
* "Page TSconfig Records": This submodule did not exist as such in previous versions
and gives an overview which page records in the system contain page TSconfig settings.
* "Active Page TSconfig": This is similar to "Active TypoScript" from the "TypoScript"
module. It allows browsing current page TSconfig and allows simulating the effect
of conditions.
* "Included page TSconfig": This is similar to the "Included TypoScript" from the
"TypoScript" module. It shows all source files and records that create the final
page TSconfig of a page. A basic syntax scanner finds broken syntax snippets.
Impact
======
The refactored modules allow more fine grained analysis
of page TSconfig and TypoScript.
.. index:: Backend, TSConfig, TypoScript, ext:backend
@@ -0,0 +1,42 @@
.. include:: /Includes.rst.txt
.. _feature-100232-1679344020:
===============================================================
Feature: #100232 - Load additional stylesheets in TYPO3 backend
===============================================================
See :issue:`100232`
Description
===========
It is now possible to load additional CSS files for the TYPO3
backend interface via regular :php:`$TYPO3_CONF_VARS` settings in a
:file:`settings.php` file of a project (previously known as :file:`LocalConfiguration.php`)
file or in an extension's :file:`ext_localconf.php`.
Previously this was done via the outdated :php:`$TBE_STYLES`
global array which has been deprecated.
Impact
======
By defining a specific stylesheet, a single CSS file or all CSS files
of a folder, extension authors can now modify the styling via:
.. code-block:: php
:caption: EXT:my_extension/ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets'][my_extension]
= 'EXT:myextension/Resources/Public/Css/myfile.css';
$GLOBALS['TYPO3_CONF_VARS']['BE']['stylesheets'][my_extension]
= 'EXT:myextension/Resources/Public/Css/';
in their extension's :file:`ext_localconf.php` file.
Site administrators can handle this in their :php:`settings.php` or :php:`additional.php` file.
.. index:: LocalConfiguration, ext:backend
@@ -0,0 +1,61 @@
.. include:: /Includes.rst.txt
.. _feature-100278-1679604666:
================================================================================
Feature: #100278 - PSR-14 Event after failed logins in backend or frontend users
================================================================================
See :issue:`100278`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Core\Authentication\Event\LoginAttemptFailedEvent`
has been introduced. The event allows to notify remote systems about failed logins.
The event features the following methods:
- :php:`isFrontendAttempt()`: Whether this was a login attempt from a frontend login form
- :php:`isBackendAttempt()`: Whether this was a login attempt in the backend
- :php:`getUser()`: Returns the :php:`\TYPO3\CMS\Core\Authentication\AbstractUserAuthentication` derivative in question
- :php:`getRequest()`: Returns the current PSR-7 request object
- :php:`getLoginData()`: The attempted login data without sensitive information
Registration of the event in your extension's :file:`Services.yaml`:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Authentication\EventListener\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/login-attempt-failed'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/Authentication/EventListener/MyEventListener.php
namespace MyVendor\MyExtension\Authentication\EventListener;
use TYPO3\CMS\Core\Authentication\Event\LoginAttemptFailedEvent;
final class MyEventListener
{
public function __invoke(LoginAttemptFailedEvent $event): void
{
if ($event->getRequest()->getAttribute('normalizedParams')->getRemoteAddress() !== '198.51.100.42') {
// send an email because an external user login attempt failed
}
}
}
Impact
======
It is now possible to notify external loggers about failed login attempts
while having the full request.
.. index:: Backend, Frontend, PHP-API, ext:core
@@ -0,0 +1,46 @@
.. include:: /Includes.rst.txt
.. _feature-100284-1679681558:
===============================================================
Feature: #100284 - Add CKEditor Inspector for backend RTE forms
===============================================================
See :issue:`100284`
Description
===========
This feature introduces the ability to show the CKEditor Inspector for backend RTE forms.
With CKEditor 5 and the introduction of the intermediate CKEditor model, knowing
the internals is a requirement to build plugins. The best way to debug during the plugin
development is the `CKEditor Inspector <https://ckeditor.com/docs/ckeditor5/latest/framework/development-tools.html#ckeditor-5-inspector>`_.
For regular pages, there is a simple bookmarklet that can be included to show
the Inspector, but in the TYPO3 backend the usage of frames does not allow this
option. Giving developers a config option in the RTE simplifies this process.
The Inspector can be activated in two different ways:
* By enabling :php:`$GLOBALS['TYPO3_CONF_VARS']['BE']['debug']` and
being in the `Development` context
* By setting the option :yaml:`editor.config.debug` to :yaml:`true` in your
CKEditor configuration
Example for setting the CKEditor configuration:
.. code-block:: yaml
editor:
config:
debug: true
Impact
======
Being in the right context or enabling the given option, it is now possible
to debug CKEditor instances for plugin development in an easier way.
.. index:: Backend, RTE, YAML, ext:rte_ckeditor
@@ -0,0 +1,55 @@
.. include:: /Includes.rst.txt
.. _feature-100293-1679673289:
================================================================
Feature: #100293 - New ContentObject EXTBASEPLUGIN in TypoScript
================================================================
See :issue:`100293`
Description
===========
In order to lower the barrier for newcomers in the TYPO3 world, TYPO3 now has
a custom ContentObject in TypoScript called :typoscript:`EXTBASEPLUGIN`.
Previously, TypoScript code for Extbase plugins looked like this:
.. code-block:: typoscript
page.10 = USER
page.10 {
userFunc = TYPO3\\CMS\\Extbase\\Core\\Bootstrap->run
extensionName = shop
pluginName = cart
}
The new way, which Extbase plugin registration uses under the hood now, looks
like this:
.. code-block:: typoscript
page.10 = EXTBASEPLUGIN
page.10.extensionName = shop
page.10.pluginName = cart
The old way still works, but it is recommended to use the :typoscript:`EXTBASEPLUGIN`
ContentObject, as the direct reference to a PHP class (Bootstrap) might be
optimized in future versions.
Impact
======
This change is an effort to distinguish between plugins and regular other
more static content.
Extbase is the de-facto standard for plugins, which serve dynamic content by
custom PHP code divided in controllers and actions by extension developers.
Regular other content can be written in pure TypoScript, such as ContentObjects
like FLUIDTEMPLATE, HMENU, COA or TEXT is used for other kind of renderings
in the frontend.
.. index:: TypoScript, ext:extbase
@@ -0,0 +1,80 @@
.. include:: /Includes.rst.txt
.. _feature-100294-1679766730:
=============================================================================
Feature: #100294 - Add PSR-14 event to enrich password validation ContextData
=============================================================================
See :issue:`100294`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Core\PasswordPolicy\Event\EnrichPasswordValidationContextDataEvent`
has been added, which allows extension authors to enrich the
:php:`\TYPO3\CMS\Core\PasswordPolicy\Validator\Dto\ContextData`
DTO used in password policy validation.
The PSR-14 event is dispatched in all classes, where a user password is
validated against the globally configured password policy.
The event features the following methods:
- :php:`getContextData()` returns the current :php:`ContextData` DTO
- :php:`getUserData()` returns an array with user data available from the
initiating class
- :php:`getInitiatingClass()` returns the class name, where the
:php:`ContextData` DTO is created
The event can be used to enrich the :php:`ContextData` DTO with additional data
used in custom password policy validators.
.. note::
The user data returned by :php:`getUserData()` will include user data
available from the initiating class only. Therefore, event listeners should
always consider the initiating class name when accessing data from
:php:`getUserData()`. If required user data is not available via
:php:`getUserData()`, it can possibly be retrieved by a custom database
query (e.g. data from user table in the password reset process by fetching
the user with the :php:`uid` given in :php:`getUserData()` array).
Registration of the event in your extension's :file:`Services.yaml`:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\PasswordPolicy\EventListener\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/enrich-context-data'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/PasswordPolicy/EventListener/MyEventListener.php
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\PasswordPolicy\Event\EnrichPasswordValidationContextDataEvent;
final class MyEventListener
{
public function __invoke(EnrichPasswordValidationContextDataEvent $event): void
{
if ($event->getInitiatingClass() === DataHandler::class) {
$event->getContextData()->setData('currentMiddleName', $event->getUserData()['middle_name'] ?? '');
$event->getContextData()->setData('currentEmail', $event->getUserData()['email'] ?? '');
}
}
}
Impact
======
With the new :php:`EnrichPasswordValidationContextDataEvent`, it is now
possible to enrich the :php:`ContextData` DTO used in password policy
validation with additional data.
.. index:: ext:core
@@ -0,0 +1,78 @@
.. include:: /Includes.rst.txt
.. _feature-100307-1679924551:
========================================================
Feature: #100307 - PSR-14 events for user login & logout
========================================================
See :issue:`100307`
Description
===========
Three new PSR-14 events have been added:
- :php:`\TYPO3\CMS\Core\Authentication\Event\BeforeUserLogoutEvent`
- :php:`\TYPO3\CMS\Core\Authentication\Event\AfterUserLoggedOutEvent`
- :php:`\TYPO3\CMS\Core\Authentication\Event\AfterUserLoggedInEvent`
The purpose of these events is to trigger any kind of action when a user
has been successfully logged in or logged out.
TYPO3 Core itself uses :php:`AfterUserLoggedInEvent` in the TYPO3 backend
to send an email to a user, if the login was successful.
The event features the following methods:
- :php:`getUser()`: Returns the :php:`\TYPO3\CMS\Core\Authentication\AbstractUserAuthentication` derivative in question
The PSR-14 event :php:`BeforeUserLogoutEvent` on top has the possibility
to bypass the regular logout process by TYPO3 (removing the cookie and
the user session) by calling :php:`$event->disableRegularLogoutProcess()`
in an event listener.
The PSR-14 event :php:`AfterUserLoggedInEvent` contains the method
:php:`getRequest()` to return PSR-7 request object of the current request.
Registration of the event in your extension's :file:`Services.yaml`:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Authentication\EventListener\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/after-user-logged-in'
The corresponding event listener class for :php:`AfterUserLoggedInEvent`:
.. code-block:: php
:caption: EXT:my_extension/Classes/Authentication/EventListener/MyEventListener.php
namespace MyVendor\MyExtension\Authentication\EventListener;
use TYPO3\CMS\Core\Authentication\Event\AfterUserLoggedInEvent;
final class MyEventListener
{
public function __invoke(AfterUserLoggedInEvent $event): void
{
if (
$event->getUser() instanceof BackendUserAuthentication
&& $event->getUser()->isAdmin()
)
{
// Do something like: Clear all caches after login
}
}
}
Impact
======
It is now possible to modify and adapt user functionality based on successful
login or active logout.
.. index:: Backend, Frontend, PHP-API, ext:core
@@ -0,0 +1,55 @@
.. include:: /Includes.rst.txt
.. _feature-19856-1679091117:
=============================================================================
Feature: #19856 - Set special ATagParams for links to access restricted pages
=============================================================================
See :issue:`19856`
Description
===========
A new TypoScript option is introduced which allows additional tag attributes to be set
to links of pages which are access restricted by frontend user group
restriction. Usually these links will not be generated, but it is possible to
link them to another page, for example, a special login page:
.. code-block:: typoscript
config.typolinkLinkAccessRestrictedPages = 13
config.typolinkLinkAccessRestrictedPages_addParams = &originalPage=###PAGE_ID###
The resulting link to an access-restricted page (e.g. `22`) looks like this:
:html:`<a href="/login?originalPage=22">My page</a>`
The newly introduced option
:typoscript:`config.typolinkLinkAccessRestrictedPages.ATagParams` allows
custom attributes to be added to the current anchor tag.
.. code-block:: typoscript
config.typolinkLinkAccessRestrictedPages.ATagParams = class="restricted"
This will result in
:html:`<a href="/login?originalPage=22" class="restricted">My page</a>`.
When generating menus via HMENU, the new :typoscript:`ATagParams` option is
also available for custom settings:
.. code-block:: typoscript
page.10 = HMENU
page.10.showAccessRestrictedPages = 13
page.10.showAccessRestrictedPages.ATagParams = class="access-restricted"
Impact
======
Allowing integrators to set custom :typoscript:`ATagParams` such as class attributes or
arbitrary data attributes to use client-side styling via CSS or JavaScript event
listeners to handle such links differently.
.. index:: TypoScript, ext:frontend
@@ -0,0 +1,49 @@
.. include:: /Includes.rst.txt
.. _feature-45039-1674297405:
===========================================================
Feature: #45039 - Command to clean up local processed files
===========================================================
See :issue:`45039`
Description
===========
It is now possible to set up a recurring scheduler task or execute a CLI command
to clean up locally processed files and their database records.
Impact
======
The command will delete :sql:`sys_file_processedfile` records with references to
non-existing files. Also, files in the configured temporary directory
(typically :file:`_processed_`) will be deleted if there are no references to them.
Example
=======
Delete files and records with confirmation:
.. code-block:: bash
./bin/typo3 cleanup:localprocessedfiles
Delete files and records:
.. code-block:: bash
./bin/typo3 cleanup:localprocessedfiles -f
Only show which files and records would be deleted:
.. code-block:: bash
./bin/typo3 cleanup:localprocessedfiles --dry-run -v
Please note that the command currently only works for local drivers.
.. index:: CLI, PHP-API, ext:lowlevel
@@ -0,0 +1,37 @@
.. include:: /Includes.rst.txt
.. _feature-65020-1679498591:
===========================================================
Feature: #65020 - Change button labels within TCA type=file
===========================================================
See :issue:`65020`
Description
===========
When working with file references (:sql:`sys_file_reference` records) within FormEngine,
there are up to three buttons available:
* "Create new relation"
* "Select & upload files"
* "Add media by URL"
Whereas the first button text can be changed via TCA on a per-field basis via
:php:`[config][appearance][createNewRelationLinkTitle] = 'LLL:my_extension/...';`
the two other label fields are hard-coded. It is especially useful to override such a label
when only a certain type of media is required (for example, just images) or online media of type YouTube.
It is now possible to do so by using two new TCA configuration settings for TCA type=file
* :php:`[config][appearance][uploadFilesLinkTitle]`
* :php:`[config][appearance][addMediaLinkTitle]`
Impact
======
An extension author can now completely modify the label texts of all buttons.
.. index:: TCA, ext:backend
@@ -0,0 +1,65 @@
.. include:: /Includes.rst.txt
.. _feature-83608-1669634686:
=======================================================================
Feature: #83608 - PSR-14 event to modify resolved default upload folder
=======================================================================
See :issue:`83608`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Core\Resource\Event\AfterDefaultUploadFolderWasResolvedEvent`
has been added, which allows the default upload folder to be modified after it has
been resolved for the current page or user.
The new event can be used as a better alternative to the
:php:`$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['getDefaultUploadFolder']`
hook, serving the same purpose.
The event features the following methods:
- :php:`getUploadFolder()` returns the currently resolved :php:`$uploadFolder`
- :php:`setUploadFolder()` sets a new upload folder
- :php:`getPid()` returns the PID of the record we fetch the upload folder for
- :php:`getTable()` returns the table name of the record we fetch the upload folder for
- :php:`getFieldName()` returns the field name of the record we fetch the upload folder for
Registration of the event in your extension's :file:`Services.yaml`:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Resource\EventListener\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/after-default-upload-folder-was-resolved-event-listener'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/Resources/EventListener/MyEventListener.php
namespace MyVendor\MyExtension\Resource\EventListener;
use TYPO3\CMS\Core\Resource\Event\AfterDefaultUploadFolderWasResolvedEvent;
final class MyEventListener
{
public function __invoke(AfterDefaultUploadFolderWasResolvedEvent $event): void
{
$event->setUploadFolder($event->getUploadFolder()->getStorage()->getFolder('/'));
}
}
Impact
======
As resolving the event was moved from :php:`BackendUserAuthentication` to its own
:php:`DefaultUploadFolderResolver` class, this event is now the preferred way
of modifying the default upload folder.
.. index:: Backend, PHP-API, ext:core
@@ -0,0 +1,36 @@
.. include:: /Includes.rst.txt
.. _feature-83608-1668162306:
===========================================================================
Feature: #83608 - Page TSconfig setting "options.defaultUploadFolder" added
===========================================================================
See :issue:`83608`
Description
===========
A new page TSconfig option :typoscript:`options.defaultUploadFolder` is added.
Impact
======
Identical to the user TSconfig setting :typoscript:`options.defaultUploadFolder`,
this allows default upload folder per page to be set.
If specified and the given folder exists, this setting will override the value
defined in user TSconfig.
Example
-------
.. code-block:: typoscript
# Set default upload folder to "fileadmin/page_upload" on PID 1
[page["uid"] == 1]
options.defaultUploadFolder = 1:/page_upload/
[end]
.. index:: TSConfig, ext:core
@@ -0,0 +1,68 @@
.. include:: /Includes.rst.txt
.. _feature-84594-1674211080:
======================================================
Feature: #84594 - Additional parameters to email links
======================================================
See :issue:`84594`
Description
===========
Editors in TYPO3 now have more possibilities to set options when
creating a link to a specific email address, in accordance with the "mailto:"
protocol.
This way, editors can now pre-fill the fields "subject", "CC", "BCC"
and "body" in the TYPO3 backend when creating a link to an email
address, which are then percent-encoded to the actual email link.
In addition, the `<f:link.email>` ViewHelper has the same additional
attributes as well:
.. code-block:: html
<f:link.email
email="foo@bar.tld"
subject="Check out this website"
cc="foo@example.com"
bcc="bar@example.com"
>
some custom content
</f:link.email>
All of the properties and the link fields are optional.
For custom email links, it is now also possible to restrict the additional
options via TCA:
Example configuration
---------------------
.. code-block:: php
'header_link' => [
'label' => 'Link',
'config' => [
'type' => 'link',
'allowedTypes' => ['email'],
'size' => 50,
'appearance' => [
// new options are "body", "cc", "bcc" and "subject"
'allowedOptions' => ['body', 'cc'],
],
],
],
Impact
======
Editors now have more flexibility when creating links to emails in the
TYPO3 backend.
Integrators have more flexibility when creating links within Fluid
templates.
.. index:: Backend
@@ -0,0 +1,29 @@
.. include:: /Includes.rst.txt
.. _feature-86880-1659742357:
=======================================================
Feature: #86880 - Enable password view at backend login
=======================================================
See :issue:`86880`
Description
===========
On clicking, the TYPO3 backend login now displays an additional button to reveal the user's
password, once something has been typed in the password field.
Impact
======
A user who is about to log in to the backend is now able to reveal the typed
password. Once the password field is cleared, the visibility mode automatically
switches back to its default to avoid revealing sensitive data by accident.
.. warning::
Revealing login credentials is always a security risk. Please use this
feature with caution when nobody can watch your input, either remotely or by
looking over your shoulders!
.. index:: Backend, ext:backend
@@ -0,0 +1,136 @@
.. include:: /Includes.rst.txt
.. _feature-94499-1675615684:
================================================================
Feature: #94499 - Implement AddPageTypeZeroSource event listener
================================================================
See :issue:`94499`
Description
===========
A new event listener for :ref:`\\TYPO3\\CMS\\Redirects\\Event\\SlugRedirectChangeItemCreatedEvent <feature-99746-1675059434>`
is introduced, which creates a :ref:`\\TYPO3\\CMS\\Redirects\\RedirectUpdate\\PageTypeSource <feature-94499-1675615570>` for a page
before the slug has been changed. The full URI is built to fill the `source_host`
and `source_path`, which takes configured `RouteEnhancers` and `RouteDecorators`
into account, for example, the `PageType route decorator`.
.. note::
If `source_host` and `source_path` lead to the same outcome for page type 0
using full URI building, like the :php:`\TYPO3\CMS\Redirects\RedirectUpdate\PlainSlugReplacementSource`, the
:php:`PlainSlugReplacementSource` is replaced with the :php:`PageTypeSource`.
It is not possible to configure page types for which sources should be added. If
you need to do so, read :ref:`additional PageTypeSource auto-create redirect source type <feature-94499-1675615570>`
which provides an example of how to implement custom event listeners based on
:php:`PageTypeSource`.
If :php:`PageTypeSource` for page type `0` results in a different
source, the :php:`PlainSlugReplacementSource` is not removed to keep the original
behaviour, which some instances may rely on.
This behaviour can be modified by adding an event listener for
:ref:`SlugRedirectChangeItemCreatedEvent <feature-99746-1675059434>`
Remove plain slug source if page type 0 differs:
------------------------------------------------
Registration of the event in your extension's :file:`Services.yaml`:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyExtension\MyPackage\Redirects\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/custom-page-type-redirect'
# Registering after core listener is important, otherwise we would
# not know if there is a PageType source for page type 0
after: 'redirects-add-page-type-zero-source'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_package/Classes/Redirects/MyEventListener.php
namespace MyVendor\MyExtension\Redirects;
use TYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent;
use TYPO3\CMS\Redirects\RedirectUpdate\PageTypeSource;
use TYPO3\CMS\Redirects\RedirectUpdate\PlainSlugReplacementRedirectSource;
use TYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceCollection;
use TYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceInterface;
final class MyEventListener
{
public function __invoke(
SlugRedirectChangeItemCreatedEvent $event
): void {
$changeItem = $event->getSlugRedirectChangeItem();
$sources = $changeItem->getSourcesCollection()->all();
$pageTypeZeroSource = $this->getPageTypeZeroSource(
...array_values($sources)
);
if ($pageTypeZeroSource === null) {
// nothing we can do - no page type 0 source found
return;
}
// Remove plain slug replacement redirect source from sources. We
// already know, that if it is there it differs from the page type
// 0 source, therefor it is safe to simply remove it by class check.
$sources = array_filter(
$sources,
static fn ($source) => !($source instanceof PlainSlugReplacementRedirectSource)
);
// update sources
$changeItem = $changeItem->withSourcesCollection(
new RedirectSourceCollection(
...array_values($sources)
)
);
// update change item with updated sources
$event->setSlugRedirectChangeItem($changeItem);
}
private function getPageTypeZeroSource(
RedirectSourceInterface ...$sources
): ?PageTypeSource {
foreach ($sources as $source) {
if ($source instanceof PageTypeSource
&& $source->getPageType() === 0
) {
return $source;
}
}
return null;
}
}
Impact
======
An additional redirect source is automatically added if a `PageType suffix`
is configured in the :php:`SiteConfiguration` for page type `0`. In that case
two redirects are created, one for the plain slug change and one with the suffix
in the `source_path`. That way it does not break instances relying on the
fact that plain slug based redirects are created.
.. note::
This behaviour can be modified by adding an event listener for
:ref:`SlugRedirectChangeItemCreatedEvent <feature-99746-1675059434>`.
It can check if both variants are in the source collection and remove the
:php:`PlainSlugReplacementSource`, as found in the example above.
.. todo:
Add link to main documentation or EXT:redirects once this contains more examples for the new events.
The documentation will later be modified to include more examples.
.. index:: PHP-API, ext:redirects
@@ -0,0 +1,214 @@
.. include:: /Includes.rst.txt
.. _feature-94499-1675615570:
======================================================================================
Feature: #94499 - Provide additional `PageTypeSource` auto-create redirect source type
======================================================================================
See :issue:`94499`
Description
===========
A new source type implementation based on :php:`\TYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceInterface`
is added, providing the page type number as an additional value. The main use case
for this source type is to provide additional source types where the source host
and path are taken from a fully built URI before the page slug change occurred for
a specific page type. That avoids the need for extension authors to implement a
custom source type for the same task, and instead provides a custom event
listener to build sources for non-zero page types. Sources can be added by
implementing an event listener for
:ref:`\\TYPO3\\CMS\\Redirects\\Event\\SlugRedirectChangeItemCreatedEvent <feature-99746-1675059434>`.
.. note::
TYPO3 Core implements a listener to add a :php:`PageTypeSource` for page
type `0` with :ref:`AddPageTypeZeroSource Event Listener <feature-94499-1675615684>`.
This source class can be re-used, if page type related sources should be added
for non-zero page types.
This class features the following methods:
- :php:`getHost()`: Returns the source host for the redirect
- :php:`getPath()`: Returns the source path for the redirect
- :php:`getPageType()`: Returns the page type used to provide the host/path
- :php:`getTargetLinkParameters()`: Returns the link parameters which should
be used to create the target based on `t3://` syntax
Values can be set only by the constructor.
Example:
--------
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/custom-page-type-redirect'
after: 'redirects-add-page-type-zero-source'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/Redirects/MyEventListener.php
namespace MyVendor\MyExtension\Redirects;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Routing\InvalidRouteArgumentsException;
use TYPO3\CMS\Core\Routing\RouterInterface;
use TYPO3\CMS\Core\Routing\UnableToLinkToPageException;
use TYPO3\CMS\Core\Site\Entity\Site;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent;
use TYPO3\CMS\Redirects\RedirectUpdate\PageTypeSource;
use TYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceCollection;
use TYPO3\CMS\Redirects\RedirectUpdate\RedirectSourceInterface;
final class MyEventListener
{
protected array $customPageTypes = [ 1234, 169999 ];
public function __invoke(
SlugRedirectChangeItemCreatedEvent $event
): void {
$changeItem = $event->getSlugRedirectChangeItem();
$sources = $changeItem->getSourcesCollection()->all();
foreach ($this->customPageTypes as $pageType) {
try {
$pageTypeSource = $this->createPageTypeSource(
$changeItem->getPageId(),
$pageType,
$changeItem->getSite(),
$changeItem->getSiteLanguage(),
);
if ($pageTypeSource === null) {
continue;
}
} catch (UnableToLinkToPageException) {
// Could not properly link to page. Continue to next page type
continue;
}
if ($this->isDuplicate($pageTypeSource, ...$sources)) {
// not adding duplicate,
continue;
}
$sources[] = $pageTypeSource;
}
// update sources
$changeItem = $changeItem->withSourcesCollection(
new RedirectSourceCollection(
...array_values($sources)
)
);
// update change item with updated sources
$event->setSlugRedirectChangeItem($changeItem);
}
private function isDuplicate(
PageTypeSource $pageTypeSource,
RedirectSourceInterface ...$sources
): bool {
foreach ($sources as $existingSource) {
$existingHost = $existingSource->getHost();
$pageTypeSourceHost = $pageTypeSource->getHost();
$existingPath = rtrim($existingSource->getPath(), '/');
$pageTypeSourcePath = rtrim($pageTypeSource->getPath(), '/');
if ($existingSource instanceof PageTypeSource
&& $existingHost === $pageTypeSourceHost
&& $existingPath === $pageTypeSourcePath
) {
// we do not check for the type, as that is irrelevant. Same
// host+path tuple would lead to duplicated redirects if
// type differs.
return true;
}
}
return false;
}
private function createPageTypeSource(
int $pageUid,
int $pageType,
Site $site,
SiteLanguage $siteLanguage
): ?PageTypeSource {
if ($pageType === 0) {
// pageType 0 is handled by \TYPO3\CMS\Redirects\EventListener\AddPageTypeZeroSource
return null;
}
try {
$context = $this->getAdjustedContext();
$uri = $site->getRouter($context)->generateUri(
$pageUid,
[
'_language' => $siteLanguage,
'type' => $pageType,
],
'',
RouterInterface::ABSOLUTE_URL
);
return new PageTypeSource(
$uri->getHost() ?: '*',
$uri->getPath(),
$pageType,
[
'type' => $pageType,
],
);
} catch (\InvalidArgumentException | InvalidRouteArgumentsException $e) {
throw new UnableToLinkToPageException(
sprintf(
'The link to the page with ID "%d" and type "%d" could not be generated: %s',
$pageUid,
$pageType,
$e->getMessage()
),
1675618235,
$e
);
}
}
/**
* Returns the adjusted current context with modified visibility settings
* to build source url for hidden or scheduled pages.
*/
private function getAdjustedContext(): Context
{
$adjustedVisibility = new VisibilityAspect(
true,
true,
false,
true,
);
$originalContext = GeneralUtility::makeInstance(Context::class);
$context = clone $originalContext;
$context->setAspect('visibility', $adjustedVisibility);
return $context;
}
}
Impact
======
The new :php:`PageTypeSource` can be used to provide additional sources, for example,
based on custom page types using full URI building, which would take
configured PageTypeSuffix decorators into account. For page type `0` (default), the Core
implements an event listener which adds the source based on this source class for
page type `0` with :ref:`AddPageTypeZeroSource event listener <feature-94499-1675615684>`.
.. index:: PHP-API, ext:redirects
@@ -0,0 +1,48 @@
.. include:: /Includes.rst.txt
.. _feature-97389-1673972552:
======================================================================
Feature: #97389 - Add password policy validation for TCA type=password
======================================================================
See :issue:`97389`
Description
===========
It is now possible to assign a password policy to TCA fields of type
`password`. For configured fields, the password policy validator will be used
in `DataHandler` to ensure that the new password complies with the configured
password policy.
Password policy requirements are shown below the password field when the focus
is changed to the password field.
The TCA field `password` for tables :sql:`be_users` and :sql:`fe_users` uses
now by default the password policy configured in
:php:`$GLOBALS['TYPO3_CONF_VARS']['FE']['passwordPolicy']` (fe_users) or
:php:`$GLOBALS['TYPO3_CONF_VARS']['BE']['passwordPolicy']` (be_users).
Example configuration
---------------------
.. code-block:: php
'password_field' => [
'label' => 'Password',
'config' => [
'type' => 'password',
'passwordPolicy' => 'default',
],
],
This example will use the password policy `default` for the field.
Impact
======
For TYPO3 frontend and backend users, the global password policy is used. A
new password is not saved if it does not comply with the password policy.
.. index:: Backend, ext:core
@@ -0,0 +1,39 @@
.. include:: /Includes.rst.txt
.. _feature-97390-1667653394:
=======================================================================
Feature: #97390 - Use password policy for password reset in ext:felogin
=======================================================================
See :issue:`97390`
Description
===========
The password reset feature for TYPO3 frontend users now takes into account the
configurable password policy introduced in :ref:`#97388 <feature-97388>`,
if the feature toggle `security.usePasswordPolicyForFrontendUsers` is
set to `true` (default for new TYPO3 websites).
Impact
======
Password validation configured through
:typoscript:`plugin.tx_felogin_login.settings.passwordValidators` has been
marked as deprecated, but will still be used for password validation, if
the feature toggle `security.usePasswordPolicyForFrontendUsers` is set
to `false`.
TYPO3 websites, which have the feature toggle
`security.usePasswordPolicyForFrontendUsers` set to `true`, will use the globally
configured password policy when a TYPO3 frontend user resets their password.
The TYPO3 default password policy contains the following password requirements:
* At least 8 chars
* At least one number
* At least one upper case char
* At least one special char
* Must be different than current password (if available)
.. index:: Frontend, ext:felogin
@@ -0,0 +1,40 @@
.. include:: /Includes.rst.txt
.. _feature-97667-1678967840:
======================================================
Feature: #97667 - Add keyboard support for Multiselect
======================================================
See :issue:`97667`
Description
===========
You are able to use the keyboard for selecting and deselecting options in
Multiselect.
- :kbd:`Enter` adds options, either from right to left or left to right
- :kbd:`Delete` or :kbd:`Backspace` removes an option for windows/mac users
- :kbd:`Alt` + :kbd:`ArrowUp` moves the option one up
- :kbd:`Alt` + :kbd:`ArrowDown` moves the option one down
- :kbd:`Alt` + :kbd:`Shift` + :kbd:`ArrowUp` moves it to the top
- :kbd:`Alt` + :kbd:`Shift` + :kbd:`ArrowDown` moves it to the bottom
More combinations are possible by default:
- :kbd:`Shift` + :kbd:`ArrowUp` includes the upper option
- :kbd:`Shift` + :kbd:`ArrowDown` includes the lower option
- :kbd:`Home` moves the cursor to the top
- :kbd:`End` move the cursor to the bottom
Impact
======
This currently affects the following TCA configurations:
- :php:`'type' => 'select', 'renderType' => 'selectMultipleSideBySide'`
- :php:`'type' => 'group'`
- :php:`'type' => 'folder'`
.. index:: TCA, ext:backend
@@ -0,0 +1,97 @@
.. include:: /Includes.rst.txt
.. _feature-98132-1677928250:
===============================================================
Feature: #98132 - Extbase entity properties support union types
===============================================================
See :issue:`98132`
Description
===========
Extbase reflection now supports the detection of union types in entity properties.
Previously, whenever a union type was needed, union type declarations led to Extbase
not detecting any type at all, resulting in the property not being mapped. Union
types could be resolved via doc blocks however:
.. code-block:: php
class Entity extends AbstractEntity
{
/**
* @var ChildEntity|LazyLoadingProxy
*/
private $property;
}
Now this is possible:
.. code-block:: php
class Entity extends AbstractEntity
{
private ChildEntity|LazyLoadingProxy $property;
}
This is especially useful for lazy loaded relations where the property type is `LazyLoadingProxy|ChildEntity`.
There is something important to understand about how Extbase detects unions when
it comes to property mapping, i.e. when a database row is mapped onto an object.
In this case, Extbase needs to know the desired target type - no union, no
intersection, just one type. In order to achieve this, Extbase uses the first
declared type as a so-called primary type.
.. code-block:: php
class Entity extends AbstractEntity
{
private string|int $property;
}
In this case, `string` is the primary type. `int|string` would result in `int` as primary type.
There is one important thing to note and one exception to this rule. First of
all, `null` is not considered a type. `null|string` results in primary type
`string`, which is nullable. `null|string|int` also results in primary type
`string`. In fact, `null` means that all other types are nullable.
`null|string|int` boils down to `?string` or `?int`.
Secondly, `LazyLoadingProxy` is never detected as primary type because it is
just a proxy and not the actual target type, once loaded.
.. code-block:: php
class Entity extends AbstractEntity
{
private LazyLoadingProxy|ChildEntity $property;
}
Extbase supports this and detects `ChildEntity` as primary type, although
`LazyLoadingProxy` is the first item in the list. However, it is recommended to
place the actual type first, for consistency reasons: `ChildEntity|LazyLoadingProxy`.
A final word on `LazyObjectStorage`: `LazyObjectStorage` is a subclass of
`ObjectStorage`, therefore the following code works and has always worked:
.. code-block:: php
class Entity extends AbstractEntity
{
/**
* @var ObjectStorage<ChildEntity>
* @TYPO3\CMS\Extbase\Annotation\ORM\Lazy
*/
private ObjectStorage $property;
}
Impact
======
As described above, the main impact is Extbase being able to detect and support
union type declarations for entity properties.
.. index:: PHP-API, ext:extbase
@@ -0,0 +1,40 @@
.. include:: /Includes.rst.txt
.. _feature-98517-1675861888:
=========================================================
Feature: #98517 - Username in backend password reset mail
=========================================================
See :issue:`98517`
Description
===========
Many users forget their login username and try to login with their email address.
The username of the backend user is now displayed in the password recovery email
alongside the reset link.
Impact
======
The username of the backend user is displayed in the password recovery email
alongside the reset link.
.. note::
Be aware, this feature comes with security risks:
Previously, a third-party that gained access to the email account could only
reset the password of the TYPO3 backend user, but not login if the username
was different to the email address.
Now it has all the information needed to login into the TYPO3 backend and
potentially could cause damage to the website.
We highly recommend protecting backend accounts using :doc:`MFA <../11.1/Feature-93526-MultiFactorAuthentication>`.
It is also possible to override the ResetPassword email template to remove
the username and customize the result.
.. index:: LocalConfiguration, ext:backend
@@ -0,0 +1,29 @@
.. include:: /Includes.rst.txt
.. _feature-99258-1670017157:
=======================================================================================
Feature: #99258 - Add minimum age option to EXT:lowlevel cleanup:deletedrecords command
=======================================================================================
See :issue:`99258`
Description
===========
Using the CLI command `cleanup:deletedrecords` to clean up the database
periodically is not really possible with EXT:recycler, because all
records marked for deletion are deleted immediately and thus the recycler seems
less useful.
The new option `--min-age` added to the `cleanup:deletedrecords` CLI command
allows a minimum age of the X days that a record needs to be marked as deleted
before it really gets deleted to be defined.
Impact
======
Executing `bin/typo3 cleanup:deletedrecords --min-age 30` will only delete
records that have been marked for more than 30 days for deletion.
.. index:: CLI, ext:lowlevel
@@ -0,0 +1,31 @@
.. include:: /Includes.rst.txt
.. _feature-99321-1670525282:
================================================
Feature: #99321 - Add presets for site languages
================================================
See :issue:`99321`
Description
===========
When adding a new language to a site, an integrator can now
choose
a) to create a new language by defining all values themselves
b) from a list of default language settings ("presets")
c) to use an existing language if it is already used in a different site
Although c) is always recommended when working with multi-site setups,
to keep language IDs between sites in sync, b) is now a quick start
to setup a new site.
Impact
======
Integrators spend less time adding new site languages.
.. index:: Backend, ext:core
@@ -0,0 +1,28 @@
.. include:: /Includes.rst.txt
.. _feature-99436-1672410981:
===================================================
Feature: #99436 - List commands in scheduler module
===================================================
See :issue:`99436`
Description
===========
Commands based on Symfony commands are the successor of regular tasks since TYPO3 v8.
The scheduler submodule :guilabel:`Available scheduler commands & tasks` has been extended
to list not only available scheduler tasks, but CLI commands that can be added
as scheduler tasks.
Impact
======
The submodule :guilabel:`Available scheduler commands & tasks` has been improved to
list schedulable commands as well. This improves the overview and makes it easier
to set up commands.
.. index:: Backend, ext:scheduler
@@ -0,0 +1,198 @@
.. include:: /Includes.rst.txt
.. _feature-99499-1677703100:
============================================================
Feature: #99499 - Introduce Content-Security-Policy handling
============================================================
See :issue:`99499`
Description
===========
A corresponding representation of the W3C standard of
`Content-Security-Policy (CSP) <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy>`__
has been introduced to TYPO3. Content-Security-Policy declarations can either be provided by using
the general builder pattern of :php:`\TYPO3\CMS\Core\Security\ContentSecurityPolicy\Policy`, extension-specific
mutations (changes to the general policy) via :file:`Configuration/ContentSecurityPolicies.php`
located in corresponding extension directories, or YAML path :yaml:`contentSecurityPolicies.mutations` for
site-specific declarations in the website frontend.
The PSR-15 middlewares :php:`ContentSecurityPolicyHeaders` apply `Content-Security-Policy` HTTP headers
to each response in the frontend and backend scope. In the case that other components have already added either the
header `Content-Security-Policy` or `Content-Security-Policy-Report-Only`, those existing headers will be
kept without any modification - these events will be logged with an `info` severity.
To delegate CSP handling to TYPO3, the scope-specific feature flags need to be enabled:
* :php:`$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['security.backend.enforceContentSecurityPolicy']`
* :php:`$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['security.frontend.enforceContentSecurityPolicy']`
For new installations `security.backend.enforceContentSecurityPolicy` is enabled via factory default settings.
Potential CSP violations are reported back to the TYPO3 system and persisted internally in the database table
:sql:`sys_http_report`. A corresponding Content-Security-Policy backend module supports users to keep track of
recent violations and - if applicable - to select potential resolutions (stored in database table
:sql:`sys_csp_resolution`) which extends the Content-Security-Policy for the given scope during runtime.
As an alternative, the reporting URL can be configured to use third-party services as well:
.. code-block:: php
$GLOBALS['TYPO3_CONF_VARS']['BE']['contentSecurityPolicyReportingUrl']
= 'https://csp-violation.example.org/';
$GLOBALS['TYPO3_CONF_VARS']['FE']['contentSecurityPolicyReportingUrl']
= 'https://csp-violation.example.org/';
Impact
======
Introducing CSP to TYPO3 aims to reduce the risk of being affected by Cross-Site-Scripting
due to the lack of proper encoding of user-submitted content in corresponding outputs.
Configuration
=============
`Policy` builder approach
-------------------------
.. code-block:: php
<?php
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Directive;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Policy;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\SourceKeyword;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\SourceScheme;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\UriValue;
use TYPO3\CMS\Core\Security\Nonce;
$nonce = Nonce::create();
$policy = (new Policy())
// results in `default-src 'self'`
->default(SourceKeyword::self)
// extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources
// results in `img-src 'self' data: https://*.typo3.org`
->extend(Directive::ImgSrc, SourceScheme::data, new UriValue('https://*.typo3.org'))
// extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources
// results in `script-src 'self' 'nonce-[random]'` ('nonce-proxy' is substituted when compiling the policy)
->extend(Directive::ScriptSrc, SourceKeyword::nonceProxy)
// sets (overrides) the directive, thus ignores 'self' of the 'default-src' directive
// results in `worker-src blob:`
->set(Directive::WorkerSrc, SourceScheme::blob);
header('Content-Security-Policy: ' . $policy->compile($nonce));
The result of the compiled and serialized result as HTTP header would look similar to this
(the following sections are using the same example, but utilize different techniques for the declarations).
.. code-block:: text
Content-Security-Policy: default-src 'self';
img-src 'self' data: https://*.typo3.org; script-src 'self' 'nonce-[random]';
worker-src blob:
Extension-specific
------------------
A file :file:`Configuration/ContentSecurityPolicies.php` in the base directory
of any extension will automatically provide and apply corresponding settings.
.. code-block:: php
:caption: EXT:my_extension/Configuration/ContentSecurityPolicies.php
<?php
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Directive;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Mutation;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationCollection;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationMode;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Scope;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\SourceKeyword;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\SourceScheme;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\UriValue;
use TYPO3\CMS\Core\Type\Map;
return Map::fromEntries([
// provide declarations for the backend
Scope::backend(),
// NOTICE: When using `MutationMode::Set` existing declarations will be overridden
new MutationCollection(
// results in `default-src 'self'`
new Mutation(MutationMode::Set, Directive::DefaultSrc, SourceKeyword::self),
// extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources
// results in `img-src 'self' data: https://*.typo3.org`
new Mutation(MutationMode::Extend, Directive::ImgSrc, SourceScheme::data, new UriValue('https://*.typo3.org')),
// NOTICE: the following two instructions for `Directive::ImgSrc` are identical to the previous instruction,
// `MutationMode::Extend` is a shortcut for `MutationMode::InheritOnce` and `MutationMode::Append`
// new Mutation(MutationMode::InheritOnce, Directive::ImgSrc, SourceScheme::data),
// new Mutation(MutationMode::Append, Directive::ImgSrc, SourceScheme::data, new UriValue('https://*.typo3.org')),
// extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources
// results in `script-src 'self' 'nonce-[random]'` ('nonce-proxy' is substituted when compiling the policy)
new Mutation(MutationMode::Extend, Directive::ScriptSrc, SourceKeyword::nonceProxy),
// sets (overrides) the directive, thus ignores 'self' of the 'default-src' directive
// results in `worker-src blob:`
new Mutation(MutationMode::Set, Directive::WorkerSrc, SourceScheme::blob),
),
]);
Site-specific (frontend)
------------------------
In the frontend, the dedicated :file:`sites/<my-site>/csp.yaml` can be used to declare CSP for a specific site as well.
.. code-block:: yaml
:caption: config/sites/<my-site>/csp.yaml
# inherits default site-unspecific frontend policy mutations (enabled per default)
inheritDefault: true
mutations:
# results in `default-src 'self'`
- mode: set
directive: 'default-src'
sources:
- "'self'"
# extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources
# results in `img-src 'self' data: https://*.typo3.org`
- mode: extend
directive: 'img-src'
sources:
- 'data:'
- 'https://*.typo3.org'
# extends the ancestor directive ('default-src'), thus reuses 'self' and adds additional sources
# results in `script-src 'self' 'nonce-[random]'` ('nonce-proxy' is substituted when compiling the policy)
- mode: extend
directive: 'script-src'
sources:
- "'nonce-proxy'"
# results in `worker-src blob:`
- mode: set
directive: 'worker-src'
sources:
- 'blob:'
PSR-14 events
=============
PolicyMutatedEvent
------------------
The :php:`\TYPO3\CMS\Core\Security\ContentSecurityPolicy\Event\PolicyMutatedEvent` will
be dispatched once all mutations have been applied to the current policy object, just
before the corresponding HTTP header is added to the HTTP response object.
This allows individual changes for custom implementations. Next to the :php:`Scope`, the
:php:`Policy`'s and the :php:`MutationCollection`'s might the Event also provide
the current PSR-7 :php:`ServerRequestInterface` for additional context.
InvestigateMutationsEvent
-------------------------
The :php:`\TYPO3\CMS\Core\Security\ContentSecurityPolicy\Event\InvestigateMutationsEvent` will
be dispatched when the Content-Security-Policy backend module searches for potential resolutions
to a specific CSP violation report. This way, third-party integrations that rely on external resources
(for example, maps, file storage, content processing/translation, ...) can provide the necessary mutations.
.. index:: Backend, Fluid, Frontend, LocalConfiguration, PHP-API, ext:core
@@ -0,0 +1,28 @@
.. include:: /Includes.rst.txt
.. _feature-99608-1674053552:
=============================================================================
Feature: #99608 - Add password policy action to exclude validators in SU mode
=============================================================================
See :issue:`99608`
Description
===========
The new password policy action `UPDATE_USER_PASSWORD_SWITCH_USER_MODE` has been
added in order to allow administrators to exclude a password policy validator,
if the current user is in switch user mode.
The new password policy action is used in the global default password policy for
the `NotCurrentPasswordValidator`.
Impact
======
When the current backend user is in switch user mode, it is not validated,
if the new password equals the current user password in ext:setup.
.. index:: Backend, ext:core
@@ -0,0 +1,232 @@
.. include:: /Includes.rst.txt
.. _feature-99629-1674550092:
========================================================
Feature: #99629 - Webhooks - Outgoing webhooks for TYPO3
========================================================
See :issue:`99629`
Description
===========
A webhook is an automated message sent from one application to another via HTTP.
This feature adds the possibility to configure webhooks in TYPO3.
A new backend module :guilabel:`System > Webhooks` provides the possibility to
configure webhooks. The module is available in the TYPO3 backend for users with
administrative rights.
A webhook is defined as an authorized POST or GET request to a defined URL.
For example, a webhook can be used to send a notification to a Slack channel
when a new page is created in TYPO3.
Any webhook record is defined by a universally unique identifier (UUID), a speaking name, an optional
description, a trigger, the target URL and a signing-secret.
Both the unique identifier and the signing-secret are generated in the backend
when a new webhook is created.
Triggers provided by the TYPO3 Core
-----------------------------------
The TYPO3 Core currently provides the following triggers for webhooks:
* Page Modification: Triggers when a page is created, updated or deleted
* File Added: Triggers when a file is added
* File Updated: Triggers when a file is updated
* File Removed: Triggers when a file is removed
* Login Error Occurred: Triggers when a login error occurred
* Redirect Was Hit: Triggers when a redirect has been hit
These triggers are meant as a first set of triggers that can be used to send webhooks,
further triggers will be added in the future. In most projects however, it is likely
that custom triggers are required.
Custom triggers
---------------
Trigger by PSR-14 events
~~~~~~~~~~~~~~~~~~~~~~~~
Custom triggers can be added by creating a `Message` for an specific PSR-14 event and
tagging that message as a webhook message.
The following example shows how to create a simple webhook message for the
:php:`\TYPO3\CMS\Core\Resource\Event\AfterFolderAddedEvent`:
.. code-block:: php
namespace TYPO3\CMS\Webhooks\Message;
use TYPO3\CMS\Core\Attribute\WebhookMessage;
use TYPO3\CMS\Core\Messaging\WebhookMessageInterface;
use TYPO3\CMS\Core\Resource\Event\AfterFolderAddedEvent;
#[WebhookMessage(
identifier: 'typo3/folder-added',
description: 'LLL:EXT:webhooks/Resources/Private/Language/locallang_db.xlf:sys_webhook.webhook_type.typo3-folder-added'
)]
final class FolderAddedMessage implements WebhookMessageInterface
{
public function __construct(
private readonly int $storageUid,
private readonly string $identifier,
private readonly string $publicUrl
) {
}
public static function createFromEvent(AfterFolderAddedEvent $event): self
{
$file = $event->getFile();
return new self($file->getStorage()->getUid(), $file->getIdentifier(), $file->getPublicUrl());
}
public function jsonSerialize(): array
{
return [
'storage' => $this->storageUid,
'identifier' => $this->identifier,
'url' => $this->publicUrl,
];
}
}
#. Create a final class implementing `\TYPO3\CMS\Core\Messaging\WebhookMessageInterface`.
#. Add the :php:`\TYPO3\CMS\Core\Attribute\WebhookMessage` attribute to the class.
The attribute requires the following information:
* `identifier`: The identifier of the webhook message.
* `description`: The description of the webhook message. This description
is used to describe the trigger in the TYPO3 backend.
#. Add a static method `createFromEvent()` that creates a new instance of the
message from the event you want to use as a trigger.
#. Add a method `jsonSerialize()` that returns an array with the data that
should be sent with the webhook.
Trigger by hooks or custom code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In case a trigger is not provided by the TYPO3 Core or a PSR-14 event is not available,
it is possible to create a custom trigger - for example by using a TYPO3 hook.
The message itself should look similar to the example above, but does not need the
:php:`createFromEvent()` method.
Instead, the custom code (hook implementation) will create the message
and dispatch it.
Example hook implementation for a DataHandler hook (see :php:`\TYPO3\CMS\Webhooks\Listener\PageModificationListener`):
.. code-block:: php
public function __construct(
protected readonly \Symfony\Component\Messenger\MessageBusInterface $bus
) {
}
public function processDatamap_afterDatabaseOperations($status, $table, $id, $fieldArray, DataHandler $dataHandler)
{
if ($table !== 'pages') {
return;
}
// ...
$message = new PageModificationMessage(
'new',
$id,
$fieldArray,
$site->getIdentifier(),
(string)$site->getRouter()->generateUri($id),
$dataHandler->BE_USER,
);
// ...
$this->bus->dispatch($message);
}
Use :file:`Services.yaml` instead of the PHP attribute
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Instead of the PHP attribute the :file:`Services.yaml` can be used to define the
webhook message. The following example shows how to define the webhook message
from the example above in the :file:`Services.yaml`:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
TYPO3\CMS\Webhooks\Message\FolderAddedMessage:
tags:
- name: 'core.webhook_message'
identifier: 'typo3/folder-added'
description: 'LLL:EXT:webhooks/Resources/Private/Language/locallang_db.xlf:sys_webhook.webhook_type.typo3-folder-added'
HTTP headers of every webhook
-----------------------------
With every webhook request, the following HTTP headers are sent:
* Content-Type: application/json
* Webhook-Signature-Algo: sha256
* Webhook-Signature: <hash>
The hash is calculated with the secret of the webhook and the JSON encoded data
of the request. The hash is created with the PHP function :php:`hash_hmac`.
See the following section about the hash calculation.
Hash calculation
----------------
The hash is calculated with the following PHP code:
.. code-block:: php
$hash = hash_hmac('sha256', sprintf(
'%s:%s',
$identifier, // The identifier of the webhook (uuid)
$body // The JSON encoded body of the request
), $secret); // The secret of the webhook
The hash is sent as HTTP header `Webhook-Signature` and should be used to
validate that the request was sent from the TYPO3 instance and has not been
manipulated.
To verify this on the receiving end, build the hash with the same algorithm and
secret and compare it with the hash that was sent with the request.
The hash is not meant to be used as a security mechanism, but as a way to verify
that the request was sent from the TYPO3 instance.
Technical background and advanced usage
---------------------------------------
The webhook system is based on the Symfony Messenger component. The messages
are simple PHP objects that implement an interface that denotes
them as webhook messages.
That message is then dispatched to the Symfony Messenger bus. The TYPO3 Core
provides a :php:`\TYPO3\CMS\Webhooks\MessageHandler\WebhookMessageHandler`
that is responsible for sending the webhook
requests to the third-party system, if configured to do so. The handler looks up
the webhook configuration and sends the request to the configured URL.
Messages are sent to the bus in any case. The handler is then responsible for checking
whether or not an external request (webhook) should be sent.
If advanced request handling is necessary or a custom implementation should be used,
a custom handler can be created that handles :php:`WebhookMessageInterface`
messages.
.. seealso::
:ref:`More information on messages and their handlers <t3coreapi:message-bus>`
Impact
======
The TYPO3 Core now provides a convenient GUI to create and send webhooks to
third-party systems.
In combination with the system extension :doc:`reactions <ext_reactions:Index>`
TYPO3 can now be used as a
low-code/no-code integration platform between multiple systems.
.. index:: Backend, Frontend, PHP-API, ext:webhooks
@@ -0,0 +1,38 @@
.. include:: /Includes.rst.txt
.. _feature-99735-1678701694:
=================================================
Feature: #99735 - New Country Select form element
=================================================
See :issue:`99735`
Description
===========
Since :ref:`feature-99618-1674063182`, TYPO3 provides a list of countries, together with an API
and a Fluid form ViewHelper. A new "Country select" form element has now been
added to the TYPO3 Form Framework for creating a country select in a form
easily. The new form element features a couple of configuration options, which
can either be configured via the :guilabel:`Forms` module or directly in the
corresponding YAML file.
Available options
-----------------
- `First option` (:yaml:`prependOptionLabel`): Define the "empty option", i.e. the first element of the select. You can use this to provide additional guidance for the user.
- `Prioritized countries` (:yaml:`prioritizedCountries`): Define a list of countries which should be listed as first options in the form element.
- `Only countries` (:yaml:`onlyCountries`): Restrict the countries to be rendered in the list.
- `Exclude countries` (:yaml:`excludeCountries`): Define which countries should not be shown in the list.
The new element will be rendered as single select (:html:`<select>`) HTML
element in the frontend.
Impact
======
The new "Country select" form element is now available in the Form
Framework with a couple of specific configuration options.
.. index:: ext:form
@@ -0,0 +1,101 @@
.. include:: /Includes.rst.txt
.. _feature-99739-1674867455:
======================================================
Feature: #99739 - Associative array keys for TCA items
======================================================
See :issue:`99739`
Description
===========
It is now possible to define associative array keys for the :php:`items`
configuration of TCA types :php:`select`, :php:`radio` and :php:`check`. The
new keys are called: :php:`label`, :php:`value`, :php:`icon`, :php:`group` and
:php:`description`.
Examples:
.. code-block:: php
'columns' => [
'select' => [
'label' => 'My select field',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
[
'label' => 'Selection 1',
'value' => '1',
'icon' => 'my-icon-identifier',
'group' => 'default',
],
[
'label' => 'Selection 2',
'value' => '2',
],
],
],
],
'select_checkbox' => [
'label' => 'My select checkbox field',
'config' => [
'type' => 'select',
'renderType' => 'selectCheckBox',
'items' => [
[
'label' => 'My select checkbox field',
'value' => '1',
'icon' => 'my-icon-identifier',
'group' => 'default',
'description' => 'My custom description',
],
[
'label' => 'My select checkbox field',
'value' => '2',
],
],
],
],
'radio' => [
'label' => 'My radio field',
'config' => [
'type' => 'radio',
'items' => [
[
'label' => 'Radio 1',
'value' => '1',
],
[
'label' => 'Radio 2',
'value' => '2',
],
],
],
],
'check' => [
'config' => [
'type' => 'check',
'items' => [
[
'invertStateDisplay' => true,
'label' => 'Click on me',
],
],
],
],
],
Impact
======
It is now much easier and clearer to define the TCA :php:`items` configuration
with associative array keys. The struggle to remember which option is first,
label or value, is now over. In addition, optional keys like :php:`icon` and
:php:`group` can be omitted, for example, when one desires to set the
:php:`description` option.
.. index:: TCA, ext:backend
@@ -0,0 +1,92 @@
.. include:: /Includes.rst.txt
.. _feature-99802-1675370033:
============================================================================
Feature: #99802 - New PSR-14 ModifyRedirectManagementControllerViewDataEvent
============================================================================
See :issue:`99802`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Redirects\Event\ModifyRedirectManagementControllerViewDataEvent`
is introduced, allowing extension authors to modify or enrich view data for the
:php:`\TYPO3\CMS\Redirects\Controller\ManagementController`. This allows to
display more or other information along the way.
This event features the following methods:
- :php:`getDemand()`: Return the demand object used to retrieve the redirects
- :php:`getRedirects()`: Return the retrieved redirects
- :php:`setRedirects()`: Can be used to set the redirects, for example, after enriching redirect fields
- :php:`getRequest()`: Return the current request
- :php:`getHosts()`: Returns the hosts to be used for the host filter select-box
- :php:`setHosts()`: Can be used to update which hosts are available in the filter select-box
- :php:`getStatusCodes()`: Returns the status codes for the filter select box
- :php:`setStatusCodes()`: Can be used to update which status codes are available in the filter select-box
- :php:`getCreationTypes()`: Returns creation types for the filter select box
- :php:`setCreationTypes()`: Can be used to update which creation types are available in the filter select-box
- :php:`getShowHitCounter()`: Returns if hit counter should be displayed
- :php:`setShowHitCounter()`: Can be used to manage if the hit counter should be displayed
- :php:`getView()`: Returns the current view object, without controller data assigned yet
- :php:`setView()`: Can be used to assign additional data to the view
For example, this event can be used to add additional information to current page records.
Therefore, it can be used to generate custom data, directly assigning to the view.
With overriding the backend view template via page TSconfig this custom data can
be displayed where it is needed, and rendered the way it is wanted.
Example:
--------
Registration of the event listener:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Redirects\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/modify-redirect-management-controller-view-data'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/Redirects/MyEventListener.php
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Redirects;
use TYPO3\CMS\Redirects\Event\ModifyRedirectManagementControllerViewDataEvent;
final class MyEventListener {
public function __invoke(
ModifyRedirectManagementControllerViewDataEvent $event
): void {
$hosts = $event->getHosts();
// remove wildcard host from list
$hosts = array_filter($hosts, static fn ($host) => $host['name'] !== '*');
// update changed hosts list
$event->setHosts($hosts);
}
}
Impact
======
With the new :php:`ModifyRedirectManagementControllerViewDataEvent`, it is
now possible to modify view data or inject further data to the view for the
management view of redirects.
.. index:: PHP-API, ext:redirects
@@ -0,0 +1,108 @@
.. include:: /Includes.rst.txt
.. _feature-99803-1675373908:
===========================================================
Feature: #99803 - New PSR-14 BeforeRedirectMatchDomainEvent
===========================================================
See :issue:`99803`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Redirects\Event\BeforeRedirectMatchDomainEvent`
is introduced to the :php:`\TYPO3\CMS\Redirects\Service\RedirectService`, allowing extension authors to implement a
custom redirect matching upon the loaded redirects or return matched redirect
record from other sources.
This event features following methods:
- :php:`getDomain()`: Returns the domain for which redirects should be
checked for, "*" for all domains.
- :php:`getPath()`: Returns the path which should be checked.
- :php:`getQuery()`: Returns the query part which should be checked.
- :php:`getMatchDomainName()`: Returns current check domain name.
- :php:`getMatchedRedirect()`: Returns the matched :sql:`sys_redirect` record,
set by another event listener or null.
- :php:`setMatchedRedirect()`: Can be used to clear prior matched redirect
by setting it to :php:`null` or set a matched :sql:`sys_redirect` record.
.. note::
Full :sql:`sys_redirect` record must be set using `setMatchedRedirect()` method.
Otherwise later Core code would fail, as it expects, for example, the uid of the record
to set the `X-Redirect-By` response header. Therefore, the `getMatchedRedirect()`
method returns null or a full :sql:`sys_redirect` record.
.. note::
The :php:`BeforeRedirectMatchDomainEvent` is dispatched before cached redirects
are retrieved. That means, that the event does not contain any :sql:`sys_redirect`
records. Internal redirect cache may vanish eventually if possible. Therefore,
it is left out to avoid a longer bound state to the event by properly deprecate it.
Example:
--------
Registration of the event listener:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Redirects\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/before-redirect-match-domain'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/Redirects/MyEventListener.php
namespace MyVendor\MyExtension\Redirects;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Redirects\Event\BeforeRedirectMatchDomainEvent;
final class MyEventListener
{
public function __invoke(BeforeRedirectMatchDomainEvent $event): void
{
$matchedRedirectRecord = $this->customRedirectMatching($event);
if ($matchedRedirectRecord !== null) {
$event->setMatchedRedirect($matchedRedirectRecord);
}
}
private function customRedirectMatching(
BeforeRedirectMatchDomainEvent $event
): ?array {
// @todo Implement custom redirect record loading and matching. If
// a redirect based on custom logic is determined, return the
// :sql:`sys_redirect` tables conform redirect record.
// Note: Below is simplified example code with no real value.
$record = BackendUtility::getRecord('sys_redirect', 123);
// Do custom matching logic against the record and return matched
// record - if there is one.
if ($record
&& /* custom condition against the record */
) {
return $record;
}
// return null to indicate that no matched redirect could be found
return null;
}
}
Impact
======
With the new :php:`BeforeRedirectMatchDomainEvent` it is now possible to
implement custom redirect matching methods before core matching is processed.
.. index:: PHP-API, ext:redirects
@@ -0,0 +1,74 @@
.. include:: /Includes.rst.txt
.. _feature-99834-1675612921:
=========================================================================
Feature: #99834 - New PSR-14 AfterAutoCreateRedirectHasBeenPersistedEvent
=========================================================================
See :issue:`99834`
Description
===========
A new PSR-14 event :php:`\TYPO3\CMS\Redirects\Event\AfterAutoCreateRedirectHasBeenPersistedEvent`
is introduced, allowing extension authors to react on persisted auto-created redirects. This
can be used to call external API or do other tasks based on the real persisted redirects.
.. note::
To handle later updates or react on manual created redirects in the backend
module, available hooks of :php:`\TYPO3\CMS\Core\DataHandling\DataHandler`
can be used.
Example:
--------
Registration of the event listener:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Redirects\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/after-auto-create-redirect-has-been-persisted'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/Redirects/MyEventListener.php
namespace MyVendor\MyExtension\Redirects;
use TYPO3\CMS\Redirects\Event\AfterAutoCreateRedirectHasBeenPersistedEvent;
use TYPO3\CMS\Redirects\RedirectUpdate\PlainSlugReplacementRedirectSource;
class MyEventListener {
public function __invoke(
AfterAutoCreateRedirectHasBeenPersistedEvent $event
): void {
$redirectUid = $event->getRedirectRecord()['uid'] ?? null;
if ($redirectUid === null
&& !($event->getSource() instanceof PlainSlugReplacementRedirectSource)
) {
return;
}
// Implement code what should be done with this information. E.g.
// write to another table, call a rest api or similar. Find your
// use-case.
}
}
Impact
======
With the new :php:`AfterAutoCreateRedirectHasBeenPersistedEvent`, it is now possible
to react on persisted auto-created redirects. Manually created redirects can be handled
by using one of the available :php:`\TYPO3\CMS\Core\DataHandling\DataHandler` hooks,
not suitable for auto-created redirects.
.. index:: PHP-API, ext:redirects
@@ -0,0 +1,85 @@
.. include:: /Includes.rst.txt
.. _feature-99834-1675612872:
================================================================================
Feature: #99834 - New PSR-14 ModifyAutoCreateRedirectRecordBeforePersistingEvent
================================================================================
See :issue:`99834`
Description
===========
A new PSR-14 :php:`\TYPO3\CMS\Redirects\Event\ModifyAutoCreateRedirectRecordBeforePersistingEvent`
is introduced, allowing extension authors to modify the redirect record before it is persisted to
the database. This can be used to change values based on circumstances, for example, like
different sub tree settings, not covered by the Core site configuration. Another use-case
could be to write data to additional :sql:`sys_redirect` columns added by a custom
extension for later use.
.. note::
To handle later updates or react on manually created redirects in the backend
module, available hooks of :php:`\TYPO3\CMS\Core\DataHandling\DataHandler`
can be used.
Example:
--------
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\Redirects\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/modify-auto-create-redirect-record-before-persisting'
The corresponding event listener class:
.. code-block:: php
:caption: EXT:my_extension/Classes/Redirects/MyEventListener.php
namespace MyVendor\MyExtension\Redirects;
use TYPO3\CMS\Redirects\Event\ModifyAutoCreateRedirectRecordBeforePersistingEvent;
use TYPO3\CMS\Redirects\RedirectUpdate\PlainSlugReplacementRedirectSource;
final class MyEventListener {
public function __invoke(
ModifyAutoCreateRedirectRecordBeforePersistingEvent $event
): void {
// only work on plain slug replacement redirect sources.
if (!($event->getSource() instanceof PlainSlugReplacementRedirectSource)) {
return;
}
// Get prepared redirect record and change some values
$record = $event->getRedirectRecord();
// override the status code, eventually to another value than
// configured in the site configuration
$record['status_code'] = 307;
// Set value to a field extended by a custom extension, to persist
// additional data to the redirect record.
$record['custom_field_added_by_a_extension']
= 'page_' . $event->getSlugRedirectChangeItem()->getPageId();
// Update changed record in event to ensure changed values are saved.
$event->setRedirectRecord($record);
}
}
Impact
======
With the new :php:`ModifyAutoCreateRedirectRecordBeforePersistingEvent`, it is now
possible to modify the auto-create redirect record before it is persisted to the database.
Manually created redirects or updated redirects can be handled by using the well-known
:php:`\TYPO3\CMS\Core\DataHandling\DataHandler` and the available hooks.
.. index:: PHP-API, ext:redirects
@@ -0,0 +1,36 @@
.. include:: /Includes.rst.txt
.. _feature-99861-1675757796:
==================================================
Feature: #99861 - Add tile view to element browser
==================================================
See :issue:`99861`
Description
===========
The file list is the default implementation for TYPO3 to navigate and
manage assets. This patch extends the usage of the file list to the
element browser, the build-in component to select the assets for file
fields and folder fields in the backend.
Impact
======
The rendering of files and folder now deliver a unified experience and
allow the user to use the tile view to select assets.
The search within the file browser now respects the selected folder and
searches all subfolders for the provided search term.
To have an even more reliable experience, the user will now always start
the selection process in the root folder of the default storage.
Resource tiles are now adapting to the surrounding container instead of
the viewport, to make better use of the available space.
The file list now holds all related code to the file and folder browser.
.. index:: Backend, FAL, ext:filelist
@@ -0,0 +1,29 @@
.. include:: /Includes.rst.txt
.. _feature-99874-1678720364:
==============================================================
Feature: #99874 - Edit task groups within the Scheduler module
==============================================================
See :issue:`99874`
Description
===========
Task groups can be managed in the backend module itself. Users can create, update and
delete task groups within the :guilabel:`Scheduler` module. Sorting is done via drag&drop (drag the panel header)
and inline-style editing is used to change the title name. Only empty groups may be deleted.
Impact
======
Users may edit groups in the :guilabel:`Scheduler` module.
.. note::
The group's description has never been displayed in the :guilabel:`Scheduler` module and has been
deprecated. Editing the description is and has always been only possible via the :guilabel:`List` module.
.. index:: ext:scheduler
@@ -0,0 +1,114 @@
.. include:: /Includes.rst.txt
.. _feature-99976-1676660028:
===============================================================================
Feature: #99976 - Introduce ignoreFlexFormSettingsIfEmpty Extbase configuration
===============================================================================
See :issue:`99976`
Description
===========
It is now possible to exclude empty FlexForm settings from being merged into
Extbase extension settings. Extension authors and integrators can use the new
Extbase TypoScript configuration :typoscript:`ignoreFlexFormSettingsIfEmpty`
to define FlexForm settings, which will be ignored in the merge process of the
extension settings, if their value is considered empty (either an empty string or a
string containing `0`).
In the following example, :xml:`settings.showForgotPassword` and
:xml:`settings.showPermaLogin` from FlexForm will not be merged into extension
settings, if the individual value is empty:
.. code-block:: typoscript
plugin.tx_felogin_login.ignoreFlexFormSettingsIfEmpty = showForgotPassword,showPermaLogin
If an extension already defined :typoscript:`ignoreFlexFormSettingsIfEmpty`,
integrators are advised to use :typoscript:`addToList` or
:typoscript:`removeFromList` to modify existing settings as shown in the
following example:
.. code-block:: typoscript
plugin.tx_felogin_login.ignoreFlexFormSettingsIfEmpty := removeFromList(showForgotPassword)
plugin.tx_felogin_login.ignoreFlexFormSettingsIfEmpty := addToList(domains)
It is possible to define the :typoscript:`ignoreFlexFormSettingsIfEmpty`
configuration globally for an extension using the
:typoscript:`plugin.tx_extension` TypoScript configuration or for an individual
plugin using the :typoscript:`plugin.tx_extension_plugin` TypoScript
configuration.
Extension authors can use the new PSR-14 event
:php:`\TYPO3\CMS\Extbase\Event\Configuration\BeforeFlexFormConfigurationOverrideEvent`
to implement a FlexForm override process in a custom extension based on the original
FlexForm configuration and the framework configuration.
Additionally, the new Extbase TypoScript configuration is used in EXT:felogin to
ensure that empty FlexForm settings are not merged into extension settings.
Event example
-------------
Register an event listener in your :file:`Services.yaml` file:
.. code-block:: yaml
:caption: EXT:my_extension/Configuration/Services.yaml
MyVendor\MyExtension\FlexForm\EventListener\MyEventListener:
tags:
- name: event.listener
identifier: 'my-extension/custom-absolute-path'
Implement the event listener:
.. code-block:: php
:caption: EXT:my_extension/Classes/FlexForm/EventListener/MyEventListener.php
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\FlexForm\EventListener;
use TYPO3\CMS\Extbase\Event\Configuration\BeforeFlexFormConfigurationOverrideEvent;
final class MyEventListener
{
public function __invoke(BeforeFlexFormConfigurationOverrideEvent $event): void
{
// Configuration from TypoScript
$frameworkConfiguration = $event->getFrameworkConfiguration();
// Configuration from FlexForm
$originalFlexFormConfiguration = $event->getOriginalFlexFormConfiguration();
// Currently merged configuration
$flexFormConfiguration = $event->getFlexFormConfiguration();
// Implement custom logic
$flexFormConfiguration['settings']['foo'] = 'set from event listener';
$event->setFlexFormConfiguration($flexFormConfiguration);
}
}
Impact
======
Empty FlexForm extension settings can now conditionally be excluded from the
FlexForm configuration merge process.
Also, it is now possible again to use global TypoScript extension settings
in EXT:felogin, which previously might have been overridden by empty FlexForm
settings.
In addition, with the new :php:`BeforeFlexFormConfigurationOverrideEvent` it is
now possible to further manipulate the merged configuration after standard
override logic is applied.
.. index:: ext:extbase
@@ -0,0 +1,33 @@
.. include:: /Includes.rst.txt
.. _important-100032-1677331239:
=====================================================================
Important: #100032 - Add HTTP security headers for backend by default
=====================================================================
See :issue:`100032`
Description
===========
The following HTTP security headers are now added by default for the TYPO3
backend:
* `Strict-Transport-Security: max-age=31536000` (only if
:php:`$GLOBALS[TYPO3_CONF_VARS][BE][lockSSL]` is active)
* `X-Content-Type-Options: nosniff`
* `Referrer-Policy: strict-origin-when-cross-origin`
The default HTTP security headers are configured globally in
`$GLOBALS['TYPO3_CONF_VARS']['BE']['HTTP']['Response']['Headers']` and include
a unique array key, so it is possible to individually unset/remove unwanted
headers.
.. important::
TYPO3 websites, which already use custom HTTP headers for the TYPO3 backend,
must ensure that individual HTTP security headers are not sent multiple
times.
.. index:: Backend, ext:backend
@@ -0,0 +1,48 @@
.. include:: /Includes.rst.txt
.. _important-100088-1677950866:
=========================================================
Important: #100088 - Remove dbType json for TCA type user
=========================================================
See :issue:`100088`
Description
===========
With :issue:`99226` the `dbType=json` option has been added for
TCA type `user`. After some reconsideration, it has been decided
to drop this option again in favor of the dedicated TCA type `json`.
Have a look to the according :ref:`changelog <feature-100088-1677965005>`
for further information.
Since the `dbType` option has not been released in any LTS version yet,
the option is dropped without further deprecation. Also no TCA migration
is applied.
In case you make already use of this `dbType` in your custom extension,
you need to migrate to the new TCA type.
Example:
.. code-block:: php
// Before
'myField' => [
'config' => [
'type' => 'user',
'renderType' => 'myRenderType',
'dbType' => 'json',
],
],
// After
'myField' => [
'config' => [
'type' => 'json',
'renderType' => 'myRenderType',
],
],
.. index:: Backend, PHP-API, TCA, ext:backend
@@ -0,0 +1,23 @@
.. include:: /Includes.rst.txt
.. _important-100135-1678453394:
=========================================================
Important: #100135 - Remove cookie warning in ext:felogin
=========================================================
See :issue:`100135`
Description
===========
The cookie warning message in ext:felogin is never shown, since it depends on
conditions, which will never be met. The cookie warning message can also be
considered superfluous, since a similar message is already shown, if
authentication was not successful.
Code affecting the non-working cookie warning message has therefore been
removed from ext:felogin. TYPO3 users should remove code from custom templates,
which depend on the `{cookieWarning}` variable.
.. index:: ext:felogin
+54
View File
@@ -0,0 +1,54 @@
:template: changelogOverview.html
.. include:: /Includes.rst.txt
.. _changelog-12-3:
============
12.3 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-*