Feature: #94499 - Implement AddPageTypeZeroSource event listener¶
See forge#94499
Description¶
A new event listener for \TYPO3\CMS\Redirects\Event\SlugRedirectChangeItemCreatedEvent
is introduced, which creates a \TYPO3\CMS\Redirects\RedirectUpdate\PageTypeSource 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 \TYPO3\CMS\Redirects\RedirectUpdate\PlainSlugReplacementSource
, the
PlainSlugReplacementSource
is replaced with the PageTypeSource
.
It is not possible to configure page types for which sources should be added. If
you need to do so, read additional PageTypeSource auto-create redirect source type
which provides an example of how to implement custom event listeners based on
PageTypeSource
.
If PageTypeSource
for page type 0
results in a different
source, the 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 SlugRedirectChangeItemCreatedEvent
Remove plain slug source if page type 0 differs:¶
Registration of the event in your extension's 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:
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 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
SlugRedirectChangeItemCreatedEvent.
It can check if both variants are in the source collection and remove the
PlainSlugReplacementSource
, as found in the example above.