---
title: "Validate links of a custom link handler (t3://...)"
manual: "Link Validator"
version: "main"
permalink: "https://docs.typo3.org/permalink/typo3/cms-linkvalidator:linktype-custom-linkhandler@main"
source: "Development/CustomLinkHandler.rst"
rendered: "2026-10-23T14:05:16+00:00"
---

# Validate links of a custom link handler (`t3://...`) {#linktype-custom-linkhandler}

The link validator does not scan the content itself. It evaluates the result of
the soft reference parsers configured in the TCA of a field, for example
`typolink_tag` for `tt_content.bodytext` and `typolink` for link
fields like `tt_content.header_link`.

Both parsers know the core link types such as pages, files, URLs and records.
For all other link types, for example a custom link handler providing links like
`t3://shop?identifier=123`, they dispatch the PSR-14 event
`\TYPO3\CMS\Core\DataHandling\Event\AppendLinkHandlerElementsEvent`.

To validate such links, two parts are needed:

1.  An event listener which turns the link into an entry for the link validator.
1.  A [linktype](https://docs.typo3.org/permalink/typo3/cms-linkvalidator:linktype-implementation@main) which checks the entry.

No custom soft reference parser and no change of the TCA are required, as long
as the field already uses `typolink_tag` or `typolink`.

## Event listener {#linktype-custom-linkhandler-listener}

The listener returns an element whose `subst` array describes the link. The
`type` is matched by the linktype, the `tokenValue` is passed to
`LinktypeInterface->checkLink()` as the URL to check.

**packages/my_extension/Classes/EventListener/AppendShopLinkElements.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\EventListener;

use TYPO3\CMS\Core\Attribute\AsEventListener;
use TYPO3\CMS\Core\DataHandling\Event\AppendLinkHandlerElementsEvent;

#[AsEventListener]
final class AppendShopLinkElements
{
    public function __invoke(AppendLinkHandlerElementsEvent $event): void
    {
        $linkParts = $event->getLinkParts();
        // Link details of "t3://shop?..." as built by the link handler
        if (($linkParts['type'] ?? '') !== 'shop') {
            return;
        }

        $tokenId = $event->getTokenId();
        $event->addElements([
            $tokenId . ':' . $event->getIdx() => [
                'matchString' => $event->getContent(),
                'subst' => [
                    'type' => 'shop',
                    'tokenID' => $tokenId,
                    'tokenValue' => (string)($linkParts['identifier'] ?? ''),
                ],
            ],
        ]);
    }
}

```

Calling `addElements()` marks the event as resolved. Links without a
resolved event are skipped by `typolink_tag` and reported as
"Couldn't decide typolink mode." by `typolink`.

## Linktype {#linktype-custom-linkhandler-linktype}

**packages/my_extension/Classes/Linktype/ShopLinktype.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Linktype;

use TYPO3\CMS\Linkvalidator\LinkAnalyzer;
use TYPO3\CMS\Linkvalidator\Linktype\AbstractLinktype;

final class ShopLinktype extends AbstractLinktype
{
    protected string $identifier = 'shop';

    public function checkLink(string $url, array $softRefEntry, LinkAnalyzer $reference): bool
    {
        // $url is the "tokenValue" set in the event listener
        return $this->productExists($url);
    }

    private function productExists(string $identifier): bool
    {
        // Ask your shop API or database
        return true;
    }
}

```

The default `AbstractLinktype->fetchType()` selects the linktype if the
`type` of the entry equals the identifier of the linktype, here `shop`.
Register and activate the linktype as described in
[Implementation of a custom linktype for the link validator](https://docs.typo3.org/permalink/typo3/cms-linkvalidator:linktype-implementation@main):

**packages/my_extension/Configuration/page.tsconfig**

```typoscript
mod.linkvalidator.linktypes = db,file,external,shop
```

## Fields without the typolink soft reference parsers {#linktype-custom-linkhandler-other-fields}

If a field does not use `typolink_tag` or `typolink`, add one of them
to the `softref` option of the field in the TCA, for example:

**packages/my_extension/Configuration/TCA/Overrides/tt_content.php**

```php
$GLOBALS['TCA']['tt_content']['columns']['my_field']['config']['softref'] = 'typolink';
```
