TYPO3 Logo
TYPO3 Explained
Options
Give feedback View source How to edit Edit on GitHub Full documentation (single file)

TYPO3 Explained

  • Introduction
  • API A-Z
    • Assets
    • Authentication
      • CSRF-like request token handling
      • Multi-factor authentication
    • Autoloading
      • ComposerClassLoader
    • Backend APIs
      • Access control
        • Users and groups
        • Password reset functionality
        • Roles
        • Options
        • Other Options
        • File mounts
        • Backend users module
      • Backend modules API
        • Modules.php
          • 3rd level
          • Toplevel
        • Backend GUI
        • DocHeaderComponent
        • ModuleData
        • ModuleInterface
        • ModuleProvider
        • ModuleTemplate
        • ModuleTemplateFactory
        • TypoScript
        • Sudo mode
      • JavaScript
        • ES6 in the TYPO3 Backend
        • RequireJS (Deprecated)
          • Use RequireJS in your own extension
          • Dependency handling
          • Loading your own or other RequireJS modules
          • Shim Library to Use it as Own RequireJS Modules
        • Client-side templating
        • Various JavaScript modules
          • Modals
          • Multi-step wizard
          • DocumentService (jQuery.ready substitute)
          • SessionStorage wrapper
        • Ajax request
        • Event API
        • Navigation via JavaScript
        • JavaScript form helpers
      • Ajax
      • Backend layout
      • Backend routing
      • Backend user object
      • Broadcast channels
      • Button components
      • Clipboard
      • Context menus
      • Custom Permissions
      • LoginProvider
      • UriBuilder
    • Bitsets & Enumerations
      • How to use enumerations
      • How to use bitsets
    • Caching
      • Quick start for integrators
      • Configuration
      • Caching framework architecture
      • Cache frontends
      • Developer information
    • System categories
    • Commands
      • List Core commands
      • Tutorial
    • Content Elements & Plugins
      • Create a custom content element type
      • Custom data processors
      • Create plugins
      • Configure custom backend preview for content element
      • Add content elements to the Content Element Wizard
      • Best practices
    • Content Security Policy
    • Context API and aspects
    • Country API
    • Cropping images
      • General Configuration
      • Crop variants configuration per content element
    • Database
      • Introduction
      • Configuration
      • Database structure
      • Upgrade table and field definitions
      • Basic create, read, update, and delete operations (CRUD)
      • Class overview
      • ConnectionPool
      • Query builder
      • Connection
      • Expression builder
      • Restriction builder
      • Result
      • Driver middlewares
      • Various tips and tricks
    • Database records
    • DataHandler
      • Introduction
      • DataHandler basics
      • Using the DataHandler in scripts
      • The "/record/commit" route
    • Debugging
    • Dependency injection
    • Deprecation
    • Environment
    • Error and exception handling
      • Configuration
      • Error Handler
      • Production exception handler
      • Debug exception handler
      • Examples
      • How to extend the error and exception handling
    • Events and hooks
      • Extending the TYPO3 Core
      • Event dispatcher (PSR-14 events)
      • Event list
        • Backend
          • AfterBackendPageRenderEvent
          • AfterFormEnginePageInitializedEvent
          • AfterHistoryRollbackFinishedEvent
          • AfterPageColumnsSelectedForLocalizationEvent
          • AfterPagePreviewUriGeneratedEvent
          • AfterPageTreeItemsPreparedEvent
          • AfterRecordSummaryForLocalizationEvent
          • BeforeFormEnginePageInitializedEvent
          • BeforeHistoryRollbackStartEvent
          • BeforeModuleCreationEvent
          • BeforePagePreviewUriGeneratedEvent
          • BeforeSearchInDatabaseRecordProviderEvent
          • CustomFileControlsEvent
          • IsContentUsedOnPageLayoutEvent
          • IsFileSelectableEvent
          • ModifyAllowedItemsEvent
          • ModifyButtonBarEvent
          • ModifyClearCacheActionsEvent
          • ModifyDatabaseQueryForContentEvent
          • ModifyDatabaseQueryForRecordListingEvent
          • ModifyEditFormUserAccessEvent
          • ModifyFileReferenceControlsEvent
          • ModifyFileReferenceEnabledControlsEvent
          • ModifyGenericBackendMessagesEvent
          • ModifyImageManipulationPreviewUrlEvent
          • ModifyInlineElementControlsEvent
          • ModifyInlineElementEnabledControlsEvent
          • ModifyLinkExplanationEvent
          • ModifyLinkHandlersEvent
          • ModifyNewContentElementWizardItemsEvent
          • ModifyPageLayoutContentEvent
          • ModifyPageLayoutOnLoginProviderSelectionEvent
          • ModifyQueryForLiveSearchEvent
          • ModifyRecordListHeaderColumnsEvent
          • ModifyRecordListRecordActionsEvent
          • ModifyRecordListTableActionsEvent
          • ModifyResultItemInLiveSearchEvent
          • PageContentPreviewRenderingEvent
          • RenderAdditionalContentToRecordListEvent
          • SwitchUserEvent
          • SystemInformationToolbarCollectorEvent
        • Core
          • Authentication
            • AfterGroupsResolvedEvent
            • AfterUserLoggedInEvent
            • AfterUserLoggedOutEvent
            • BeforeRequestTokenProcessedEvent
            • BeforeUserLogoutEvent
            • LoginAttemptFailedEvent
          • Cache
            • CacheFlushEvent
            • CacheWarmupEvent
          • Configuration
            • AfterFlexFormDataStructureIdentifierInitializedEvent
            • AfterFlexFormDataStructureParsedEvent
            • AfterTcaCompilationEvent
            • BeforeFlexFormDataStructureIdentifierInitializedEvent
            • BeforeFlexFormDataStructureParsedEvent
            • ModifyLoadedPageTsConfigEvent
            • SiteConfigurationBeforeWriteEvent
            • SiteConfigurationLoadedEvent
          • Core
            • BootCompletedEvent
          • Database
            • AlterTableDefinitionStatementsEvent
          • DataHandling
            • AppendLinkHandlerElementsEvent
            • IsTableExcludedFromReferenceIndexEvent
          • Domain
            • AfterRecordLanguageOverlayEvent
            • BeforePageLanguageOverlayEvent
            • BeforeRecordLanguageOverlayEvent
            • RecordAccessGrantedEvent
          • Html
            • BrokenLinkAnalysisEvent
          • Mail
            • AfterMailerInitializationEvent
            • AfterMailerSentMessageEvent
            • BeforeMailerSentMessageEvent
          • Package
            • AfterPackageActivationEvent
            • AfterPackageDeactivationEvent
            • BeforePackageActivationEvent
            • PackagesMayHaveChangedEvent
          • Page
            • BeforeJavaScriptsRenderingEvent
            • BeforeStylesheetsRenderingEvent
          • Password policy
            • EnrichPasswordValidationContextDataEvent
          • Resource
            • AfterDefaultUploadFolderWasResolvedEvent
            • AfterFileAddedEvent
            • AfterFileAddedToIndexEvent
            • AfterFileCommandProcessedEvent
            • AfterFileContentsSetEvent
            • AfterFileCopiedEvent
            • AfterFileCreatedEvent
            • AfterFileDeletedEvent
            • AfterFileMarkedAsMissingEvent
            • AfterFileMetaDataCreatedEvent
            • AfterFileMetaDataDeletedEvent
            • AfterFileMetaDataUpdatedEvent
            • AfterFileMovedEvent
            • AfterFileProcessingEvent
            • AfterFileRemovedFromIndexEvent
            • AfterFileRenamedEvent
            • AfterFileReplacedEvent
            • AfterFileUpdatedInIndexEvent
            • AfterFolderAddedEvent
            • AfterFolderCopiedEvent
            • AfterFolderDeletedEvent
            • AfterFolderMovedEvent
            • AfterFolderRenamedEvent
            • AfterResourceStorageInitializationEvent
            • AfterVideoPreviewFetchedEvent
            • BeforeFileAddedEvent
            • BeforeFileContentsSetEvent
            • BeforeFileCopiedEvent
            • BeforeFileCreatedEvent
            • BeforeFileDeletedEvent
            • BeforeFileMovedEvent
            • BeforeFileProcessingEvent
            • BeforeFileRenamedEvent
            • BeforeFileReplacedEvent
            • BeforeFolderAddedEvent
            • BeforeFolderCopiedEvent
            • BeforeFolderDeletedEvent
            • BeforeFolderMovedEvent
            • BeforeFolderRenamedEvent
            • BeforeResourceStorageInitializationEvent
            • EnrichFileMetaDataEvent
            • GeneratePublicUrlForResourceEvent
            • ModifyFileDumpEvent
            • ModifyIconForResourcePropertiesEvent
            • SanitizeFileNameEvent
          • Security
            • InvestigateMutationsEvent
            • PolicyMutatedEvent
          • Tree
            • ModifyTreeDataEvent
          • TypoScript
            • AfterTemplatesHaveBeenDeterminedEvent
            • EvaluateModifierFunctionEvent
        • Extbase
          • Configuration
            • BeforeFlexFormConfigurationOverrideEvent
          • Mvc
            • AfterRequestDispatchedEvent
            • BeforeActionCallEvent
          • Persistence
            • AfterObjectThawedEvent
            • EntityAddedToPersistenceEvent
            • EntityPersistedEvent
            • EntityRemovedFromPersistenceEvent
            • EntityUpdatedInPersistenceEvent
            • ModifyQueryBeforeFetchingObjectDataEvent
            • ModifyResultAfterFetchingObjectDataEvent
        • ExtensionManager
          • AfterExtensionDatabaseContentHasBeenImportedEvent
          • AfterExtensionFilesHaveBeenImportedEvent
          • AfterExtensionStaticDatabaseContentHasBeenImportedEvent
          • AvailableActionsForExtensionEvent
        • Filelist
          • ModifyEditFileFormDataEvent
          • ProcessFileListActionsEvent
        • Frontend
          • AfterCacheableContentIsGeneratedEvent
          • AfterCachedPageIsPersistedEvent
          • AfterLinkIsGeneratedEvent
          • AfterPageAndLanguageIsResolvedEvent
          • AfterPageWithRootLineIsResolvedEvent
          • BeforePageIsResolvedEvent
          • FilterMenuItemsEvent
          • ModifyCacheLifetimeForPageEvent
          • ModifyHrefLangTagsEvent
          • ModifyPageLinkConfigurationEvent
          • ModifyResolvedFrontendGroupsEvent
          • ShouldUseCachedPageDataIfAvailableEvent
        • FrontendLogin
          • BeforeRedirectEvent
          • LoginConfirmedEvent
          • LoginErrorOccurredEvent
          • LogoutConfirmedEvent
          • ModifyLoginFormViewEvent
          • PasswordChangeEvent
          • SendRecoveryEmailEvent
        • Impexp
          • BeforeImportEvent
        • Info
          • ModifyInfoModuleContentEvent
        • Install
          • ModifyLanguagePackRemoteBaseUrlEvent
          • ModifyLanguagePacksEvent
        • Linkvalidator
          • BeforeRecordIsAnalyzedEvent
          • ModifyValidatorTaskEmailEvent
        • Lowlevel
          • ModifyBlindedConfigurationOptionsEvent
        • Redirects
          • AfterAutoCreateRedirectHasBeenPersistedEvent
          • BeforeRedirectMatchDomainEvent
          • ModifyAutoCreateRedirectRecordBeforePersistingEvent
          • ModifyRedirectManagementControllerViewDataEvent
          • RedirectWasHitEvent
          • SlugRedirectChangeItemCreatedEvent
        • Seo
          • ModifyUrlForCanonicalTagEvent
        • Setup
          • AddJavaScriptModulesEvent
        • Workspaces
          • AfterCompiledCacheableDataForWorkspaceEvent
          • AfterDataGeneratedForWorkspaceEvent
          • AfterRecordPublishedEvent
          • GetVersionedDataEvent
          • ModifyVersionDifferencesEvent
          • SortVersionedDataEvent
      • Hooks
      • JavaScript Event API
        • Regular event
        • Debounce event
        • Throttle event
        • RequestAnimationFrame event
    • File abstraction
      • Basic concepts
      • Architecture
        • Overview
        • Folders
        • Database structure
        • Components
        • PSR-14 events
      • Administration
        • Permissions
        • File storages
        • Maintenance
      • Using FAL
        • Using FAL in the frontend
        • TCA definition
        • The StorageRepository class
        • Working with files, folders and file references
        • Working with collections
        • Searching for files
      • File collections
    • Feature toggle API
    • Custom file processors
    • Flash messages
      • Flash messages API
      • Flash messages in Extbase
      • Flash messages renderer
      • JavaScript-based flash messages (Notification API)
    • FlexForms
      • T3DataStructure
        • Elements
        • Sheet References
        • Parsing a Data Structure
    • Fluid
      • ViewHelper reference
      • Introduction to Fluid
      • Fluid syntax
      • Using Fluid in TYPO3
      • cObject ViewHelper
      • Property additionalAttributes
      • Developing a custom ViewHelper
    • FormEngine
      • Introduction
      • Main rendering workflow
      • Data compiling
      • Rendering
    • Form protection tool
    • Global values
      • Constants
    • Icon API
    • Link handling
      • Link handler configuration
      • LinkBrowser API
      • The LinkHandler API
        • The PageLinkHandler
        • The RecordLinkHandler
        • Implementing a custom LinkHandler
        • Events to modify link handler
      • Core link handler
      • Frontend link builder
      • LinkBrowser Tutorials
        • Browse records of a table
        • Create a custom link browser
    • Localization
      • Introduction
      • Supported languages
      • Managing translations
      • Translation servers
        • Localization with Crowdin
          • Extension integration
          • Online translation with Crowdin
          • Workflow
          • Frequently asked questions (FAQ)
        • Custom translation servers
      • Localization API
        • LanguageService
        • LanguageServiceFactory
        • Locale
        • LocalizationUtility (Extbase)
      • XLIFF Format
      • Working with XLIFF files
    • Locking API
    • Logging
      • Quickstart
      • Logger
      • Configuration of the logging system
      • The LogRecord model
      • Log writers
      • Log processors
    • Mail API
    • Message bus
    • Mount points
    • Namespaces
    • Page types
      • Types of pages
      • Redirect Headers
      • Create new Page Type
    • Pagination
    • Parsing HTML
    • Password hashing
      • Troubleshooting
    • Password policies
    • Requests
      • Bootstrapping
      • Middlewares (Request handling)
      • TYPO3 request object
      • TYPO3 request attributes
        • Application type
        • Current content object
        • Frontend controller
        • Frontend TypoScript
        • Frontend user
        • Language
        • Module
        • ModuleData
        • Nonce
        • Normalized parameters
        • Route
        • Routing
        • Site
        • Target
    • Routing
      • Introduction
      • Page based
      • For extensions
      • Extending
      • Examples
    • RTE
      • CKEditor Rich Text Editor
      • Rendering in the Frontend
      • Rich text editors in the TYPO3 backend
        • Introduction
        • Plugging in a custom RTE
      • Rich Text Editors (RTE) in the TYPO3 frontend
        • Including a Rich Text Editor (RTE) in the frontend
      • RTE Transformations
        • Introduction
        • Transformation overview
      • Historical Perspective on RTE Transformations
        • Properties and Transformations
        • RTE Transformations in Content Elements
    • SEO
      • Canonical API
      • MetaTag API
      • Page title API
      • XML sitemap
    • Services
      • Introduction
      • Using Services
        • Service precedence
        • Simple usage
        • Use with subtypes
        • Calling a chain of services
      • Configuration
        • Override service registration
        • Service configuration
        • Service type configuration
      • Developer's Guide
        • Introducing a new service type
        • Implementing a service
        • Service API
        • Services API
    • Sessions
      • User session management
      • Session storage framework
    • Site handling
      • Basics
      • Creation
      • Base variants
      • Adding Languages
      • Error handling
        • Page-based error handler
        • Fluid-based error handler
        • Writing a custom page error handler
      • Static routes
      • Environment variables
      • Usage in TypoScript + Fluid
      • Usage
      • Usage in TCA
      • Site settings
      • Console tools
      • PHP API
      • Extended configuration
    • Soft references
    • Symfony expression language
    • System Overview
    • System registry
    • TSFE
    • TYPO3 information
    • Webhooks and reactions
    • Versioning and Workspaces
    • XCLASSes
  • Administration
    • Installation
      • System Requirements
      • Composer-based Installation
      • Classic mode installation
        • TYPO3 release integrity
      • Server installations
        • Composer on the server
      • Configuring environments
      • Production Settings
      • Tuning TYPO3
      • Deployment
        • Rsync
        • Deployer
        • TYPO3 Surf
        • Magallanes
      • Installing Extensions - Classic mode
    • Directory structure
      • Classic mode installation
      • Flag files
    • Version Control (Git)
    • Upgrades
      • Patch/Bugfix update
      • Major upgrade
        • Pre-upgrade tasks
        • Upgrade the Core
        • Post-upgrade tasks
      • Upgrading extensions
      • Third-party tools
      • Classic mode upgrade
      • Applying Core patches
      • Migrate a TYPO3 project to Composer
        • Requirements
        • Migration steps
        • Migrating public web assets
        • Version control
      • Migrate content
    • System Settings
      • Maintenance Mode
    • Backend users
      • Adding Backend Users
      • Changing the backend language
      • Backend Privileges
      • Backend Users
      • Groups
      • Setting up User Permissions
      • Page Permissions
      • Setting up a User
    • Troubleshooting
      • TYPO3
      • System Modules
      • PHP
      • Web Server
      • Database
    • Permissions
      • General recommendations
      • Setting up backend user groups
  • Configuration
    • Overview
    • Glossary
    • Configuration module
    • $GLOBALS
    • System configuration
      • BE - backend configuration
      • DB - Database connections
      • EXT - Extension manager configuration
      • FE - frontend configuration
      • GFX - graphics configuration
      • HTTP - tune requests
      • LOG - Logging configuration
      • MAIL settings
      • SYS - System configuration
    • TypoScript
      • Introduction
      • Syntax
      • Frontend TypoScript
      • TSconfig
      • PHP API
      • Myths and FAQ
    • User settings configuration
      • ['columns'] Section
      • ['showitem'] section
      • Extending the user settings
      • View the configuration
    • YAML
      • YAML API
      • YAML syntax
      • Services.yaml
  • Coding guidelines
    • Introduction
    • PHP architecture
      • Services
      • Static Methods, static Classes, Utility Classes
      • Traits
      • Working with exceptions
    • PHP
      • General requirements for PHP files
      • File structure
      • PHP syntax formatting
      • Using phpDoc
    • PHP Best Practice
      • Named arguments
      • Singletons
      • Handling deprecations
      • Namespaces and class names of user files
    • JavaScript
    • TypeScript
    • TypoScript
    • TSconfig
    • XLIFF
    • YAML
    • reStructuredText
  • Extension development
    • Concepts
      • Introduction
      • System, third-party and custom extensions
      • Further reading
    • File structure
      • composer.json
      • ext_conf_template.txt
      • ext_emconf.php
      • ext_localconf.php
      • ext_tables.php
      • ext_tables.sql
      • ext_tables_static+adt.sql
      • ext_typoscript_constants.typoscript
      • ext_typoscript_setup.typoscript
      • Classes
      • Configuration
        • Backend
        • Extbase
          • Persistence
        • TCA
        • TsConfig
        • TypoScript
        • ContentSecurityPolicies.php
        • Icons.php
        • page.tsconfig
        • RequestMiddlewares.php
        • Services.yaml
        • user.tsconfig
      • Documentation
      • Resources
        • Private
          • Language
        • Public
      • Tests
    • Site package
      • Introduction
    • Howto
      • Backend modules
        • Modules.php
        • Plain controller
        • Extbase controller
        • Security Considerations
        • Tutorials
      • Events
      • Extending an Extbase model
      • Extending the TCA array
        • Storing the changes
        • Customization Examples
        • Verifying the TCA
      • Frontend plugin
      • Localization
        • Multi-language Fluid templates
        • Localization in PHP
        • TypoScript
      • Publish your extension
        • Publish your extension in the TER
      • HTTP requests to external sources
      • Update your extension for new TYPO3 versions
        • Extension scanner
        • Upgrade wizards
          • The concept of upgrade wizards
          • Creating upgrade wizards
      • Configuration
      • Creating a new distribution
      • Creating a new extension
      • Custom Extension Repository
      • Adding documentation
    • Extbase
      • Introduction
      • Reference
        • Domain
          • Extbase model - extending AbstractEntity
            • Persistence
            • Relations
            • Hydrating
            • Localization
          • Repository
        • Controller
          • ActionController
          • Error action
          • Property mapping
          • Type converters
        • View
        • URI builder (Extbase)
        • Registration of frontend plugins
        • TypoScript configuration
        • Annotations
        • Validation
          • Custom Validator
        • File upload
        • Caching
        • Localization
        • URI arguments and reserved keywords
      • Examples
    • Best practises and conventions
      • Choosing an extension key
      • Naming conventions
      • Configuration Files (ext_tables.php & ext_localconf.php)
      • Software Design Principles
      • Extension loading order
    • Tutorials
      • Kickstart
        • Make
          • Create a new backend controller
          • Create a new console command
      • Tea
        • Create an extension
        • Create a directory structure
        • Model: a bag of tea
        • Repository
        • Controller
      • Components of a TYPO3 extension
        • Making the extension installable
        • Creating a new database model
        • Making data persistable by Extbase
      • Extbase
  • Security guidelines
    • Introduction
    • The TYPO3 Security Team
    • General Information
    • Types of Security Threats
    • General guidelines
    • Guidelines for System Administrators
      • Role Definition
      • Integrity of TYPO3 Packages
      • File/directory permissions
      • Restrict access to files on a server-level
      • Disable directory indexing
      • File extension handling
      • Content security policy
      • Database access
      • Encrypted Client/server Communication
      • Other Services
      • Further Actions
    • Guidelines for extension development
    • Guidelines for TYPO3 integrators
      • Install tool
      • Global TYPO3 configuration options
      • Security-related warnings after login
      • Reports and logs
      • Users and access privileges
      • TYPO3 extensions
      • TypoScript
      • Content elements
    • Guidelines for editors
    • Backup strategy
    • Detect, analyze and repair a hacked site
      • Detect a hacked website
      • Take the website offline
      • Analyzing a hacked site
      • Repair/restore
      • Further actions
  • Testing
    • Extension testing
    • Project testing
    • Unit tests
      • Introduction
      • Running
    • Functional tests
      • Introduction
    • Acceptance tests
    • Test Runners: Organize and execute tests
    • Testing tutorials
      • Testing enetcache
      • Acceptance testing of site_introduction
  • About This Manual
  • Sitemap
  1. TYPO3 Explained
  2. API A-Z
  3. Link handling
  4. LinkBrowser Tutorials
  5. Create a custom link browser
Give feedback Edit on GitHub

Create a custom link browser

In this tutorial we create a custom link browser and the associated backend link handler.

We create a new tab in the link browser window in the TYPO3 backend:

A custom link browser to link to GitHub issues

Tip

If you want to link to a record in a custom table, configure the RecordLinkBrowser. You do not need a custom link browser in that scenario.

We introduce a custom link format to store the links in this format: t3://github?issue=123.

This enables us to edit an existing link in the link browser or to change parts of the GitHub URI programmatically later.

And we render the new link in the frontend automatically.

Step by step to a custom link browser

  • 1. Register the custom link browser tab in page TSconfig
  • 2. Create a link browser tab
    • Initialization and dependencies
    • Enable dependency injection
    • Render the link browser tab
    • Set the link via JavaScript
    • Can we handle this link?
    • Format current URL
  • 3. Introduce the custom link format
  • 4. Render the custom link format in the frontend

1. Register the custom link browser tab in page TSconfig

EXT:examples/Configuration/TsConfig/Page/LinkBrowser/GitHubLinkhandler.tsconfig
TCEMAIN.linkHandler {
   github {
      handler = T3docs\Examples\LinkHandler\GitHubLinkHandler
      label = LLL:EXT:examples/Resources/Private/Language/locallang_browse_links.xlf:github
      displayAfter = haiku
      scanBefore = url
      configuration {
         project = TYPO3-Documentation/TYPO3CMS-Reference-CoreApi
         action = issues
      }
   }
}
Copied!

The following options are of note here:

handler
The backend link handler that we create in step 2.
configuration
Some configuration, available to the backend link handler. This information is not available in the frontend. Therefore in the frontend rendering of the link the information must be stored in another way. In this example we hardcoded it. But you could also make it available by TypoScript Setup or as part of the link that is saved.

For a complete list of available option see Link handler configuration.

2. Create a link browser tab

To create a link browser tab we implement the interface \TYPO3\CMS\Backend\LinkHandler\LinkHandlerInterface .

All backend link handlers provided by the Core extend the abstract class \TYPO3\CMS\Backend\LinkHandler\AbstractLinkHandler . However, this class is marked as @internal and therefore can be changed by the Core Team at any time.

You have the choice of implementing the LinkHandlerInterface yourself by having a look at the AbstractLinkHandler for best practices or to extend the AbstractLinkHandler. In the latter case your code might break on updates though.

In this tutorial, we implement the LinkHandlerInterface directly, as it is best practice not to rely on internal classes.

You can find the complete class in the extension EXT:examples on GitHub: GitHubLinkHandler.

We will explain some of the important methods below:

Initialization and dependencies

Class T3docs\Examples\LinkHandler\GitHubLinkHandler
use TYPO3\CMS\Backend\Controller\AbstractLinkBrowserController;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\View\ViewInterface;

class GitHubLinkHandler implements LinkHandlerInterface
{
    protected array $linkAttributes = ['target', 'title', 'class', 'params', 'rel'];

    protected array $linkParts = [];

    protected ViewInterface $view;

    protected array $configuration;

    public function __construct(
        // The page renderer is needed to register the JavaScript
        private readonly PageRenderer $pageRenderer,
    ) {}

    public function initialize(AbstractLinkBrowserController $linkBrowser, $identifier, array $configuration)
    {
        $this->configuration = $configuration;
    }

    public function setView(ViewInterface $view): void
    {
        $this->view = $view;
    }
}
Copied!

For technical reasons, not all dependencies needed by the backend link handler can be acquired by Dependency injection. Therefore the following two methods are called by Core classes once the dependencies are available:

LinkHandlerInterface::initialize() takes care of setting the \TYPO3\CMS\Backend\Controller\AbstractLinkBrowserController , the identifier and the configuration information. In this example we only need the configuration, the other parameters might be needed in different scenarios.

AbstractLinkBrowserController $linkBrowser
Is the surrounding class calling the link handler. This class stores configuration information of the complete link browser window.
string $identifier
Contains the key of the page TSconfig configuration of the link browser tab this instance renders.
array $configuration
Contains the page TSconfig configuration as array of the link browser tab this instance renders.

The method setView() is called by the AbstractLinkBrowserController once the view is available and contains the necessary information to render the link browser window.

Note

setView() is not part of the LinkHandlerInterface and its call is an implementation detail that might be changed in the future.

Enable dependency injection

Backend link handlers are called internally in the TYPO3 Core by GeneralUtility::makeInstance(). Therefore dependency injection needs to be enabled by marking the class as public in the extension's Configuration/Services.yaml. As we keep internal states in the link handler class (for example $linkParts) it cannot be a singleton and must be marked as shared: false:

EXT:examples/Configuration/Services.yaml
services:
  _defaults:
    autowire: true
    autoconfigure: true
    public: false

  T3docs\Examples\LinkHandler\GitHubLinkHandler:
    public: true
    # The link handler keeps a state and can therefore be no singleton
    shared: false
Copied!

Render the link browser tab

The method LinkHandlerInterface::render() is called when the tab should be rendered. It registers the required JavaScript in the page renderer, assigns variables to the view and returns the rendered HTML.

Class T3docs\Examples\LinkHandler\GitHubLinkHandler
use Psr\Http\Message\ServerRequestInterface;

class GitHubLinkHandler implements LinkHandlerInterface
{
    public function render(ServerRequestInterface $request): string
    {
        $this->pageRenderer->loadJavaScriptModule('@t3docs/examples/github_link_handler.js');
        $this->view->assign('project', $this->configuration['project']);
        $this->view->assign('action', $this->configuration['action']);
        $this->view->assign('linkParts', $this->linkParts);
        $this->view->assign('issue', $this->linkParts['issue'] ?? '');

        return $this->view->render('LinkBrowser/GitHub');
    }
}
Copied!

Set the link via JavaScript

When the button in the rendered form is clicked to set a link, a custom JavaScript class interprets the form data and creates the link to be stored:

EXT:examples/Resources/Public/JavaScript/github_link_handler.js
/*
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

import LinkBrowser
	from "@typo3/backend/link-browser.js";

/**
 * Module: @t3docs/examples/github_link_handler.js
 * Github issue link interaction
 */

class GitHubLinkHandler {
	constructor() {
		var form_el = document.getElementById("lgithubform");
		form_el.addEventListener("submit", function(event) {
			event.preventDefault();
			var value = document.getElementById('lgithub').value;
			if (value === 't3://github?issue=') {
				return;
			}
			if (value.indexOf('t3://github?issue=') === 0) {
				value = value.substring(18);
			}
			LinkBrowser.finalizeFunction('t3://github?issue=' + value);
		});
	}
}

export default new GitHubLinkHandler();
Copied!

It is important that the JavaScript function calls LinkBrowser.finalizeFunction(). Otherwise no link will be set.

If not done yet, the JavaScript has to be registered in the file EXT:my_extension/Configuration/JavaScriptModules.php. Otherwise it will not be found by $pageRenderer->loadJavaScriptModule().

EXT:examples/Configuration/JavaScriptModules.php
<?php

return [
    'dependencies' => ['backend'],
    'imports' => [
        '@t3docs/examples/' => 'EXT:examples/Resources/Public/JavaScript/',
    ],
];
Copied!

As our JavaScript class depends on classes provided by the backend system extension, backend has to be added as dependency. See also Loading ES6.

Can we handle this link?

The method LinkHandlerInterface::canHandleLink() is called when the user edits an existing link in the link browser. All backend link handlers will be called and can decide if they can handle that link. If so, they should store the provided information to be used in rendering (for example, to fill an input field with the old value).

Class T3docs\Examples\LinkHandler\GitHubLinkHandler
class GitHubLinkHandler implements LinkHandlerInterface
{
    public function canHandleLink(array $linkParts): bool
    {
        if ($linkParts['type'] !== 'github') {
            return false;
        }
        $this->linkParts = $linkParts['url'] ?? [];
        return true;
    }
}
Copied!

Format current URL

The function LinkHandlerInterface::formatCurrentUrl() is used to preview what the link will look like in the backend, for example, in the upper part of the link browser window.

Attention

LinkHandlerInterface::formatCurrentUrl() is not used to render the link in the frontend.

3. Introduce the custom link format

You can find the complete class in the extension EXT:examples on GitHub: GitHubLinkHandling.

Our backend link handler implementation from step 1 saves the link in the custom format t3://github?issue=123 via JavaScript.

This format is only an arbitrary string until we tell TYPO3 how to handle links of the new format by a second class which implements the \TYPO3\CMS\Core\LinkHandling\LinkHandlingInterface .

Note

There are two interfaces with very similar names and very different functionality involved here. The \TYPO3\CMS\Backend\LinkHandler\LinkHandlerInterface renders a tab in the link browser window in the backend. Its implementing class is commonly called a "(backend) link handler". Classes implementing the interface \TYPO3\CMS\Core\LinkHandling\LinkHandlingInterface handle the introduced link format. Such a class is called a "(core) link handler".

Class T3docs\Examples\LinkHandler\GitHubLinkHandling
/**
 * Resolves GitHub Links
 */
class GitHubLinkHandling implements LinkHandlingInterface
{
    protected $baseUrn = 't3://github';

    public function asString(array $parameters): string
    {
        $githubIssue = (int)$parameters['issue'];
        return $this->baseUrn . '?issue=' . $githubIssue;
    }

    public function resolveHandlerData(array $data): array
    {
        return [
            'issue' => (int)$data['issue'],
        ];
    }
}
Copied!

The method LinkHandlingInterface::asString() creates a string representation from the parameter array.

LinkHandlingInterface::resolveHandlerData() receives the string representation of the link and creates the parameter array from it. For convenience the parameters are already parsed and stored as key-value pairs in an array for you. You can perform further processing here if needed.

4. Render the custom link format in the frontend

The link builder, a class extending the abstract class \TYPO3\CMS\Frontend\Typolink\AbstractTypolinkBuilder is called whenever a link is rendered in the frontend, for example via TypoScript .typolink, by the \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::typoLink function or by the \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder .

Class T3docs\Examples\LinkHandler\GithubLinkBuilder
use TYPO3\CMS\Frontend\Typolink\LinkResult;
use TYPO3\CMS\Frontend\Typolink\LinkResultInterface;
use TYPO3\CMS\Frontend\Typolink\UnableToLinkException;

/**
 * Builds a TypoLink to a Github issue
 */
class GithubLinkBuilder extends AbstractTypolinkBuilder
{
    private const TYPE_GITHUB = 'github';

    public function build(
        array &$linkDetails,
        string $linkText,
        string $target,
        array $conf
    ): LinkResultInterface {
        $issueId = (int)$linkDetails['issue'];
        if ($issueId < 1) {
            throw new UnableToLinkException(
                '"' . $issueId . '" is not a valid GitHub issue number.',
                // Use the Unix timestamp of the time of creation of this message
                1665304602,
                null,
                $linkText
            );
        }
        $url = 'https://github.com/TYPO3-Documentation/TYPO3CMS-Reference-CoreApi/issues/' . $issueId;

        return (new LinkResult(self::TYPE_GITHUB, $url))
            ->withTarget($target)
            ->withLinkConfiguration($conf)
            ->withLinkText($linkText);
    }
}
Copied!

The link builder must be registered in ext_localconf.php, so that the correct link builder for the new type can be determined by the calling API:

EXT:examples/ext_localconf.php (Excerpt)
$GLOBALS['TYPO3_CONF_VARS']['FE']['typolinkBuilder']['github'] =
    \T3docs\Examples\LinkHandler\GithubLinkBuilder::class;
Copied!

The function AbstractTypolinkBuilder::build() is called with the link configuration and data from the typolink function. If the link can be rendered, it returns a new \TYPO3\CMS\Frontend\Typolink\LinkResultInterface . The actual rendering of the link depends on the context the link is rendered in (for example HTML or JSON).

If the link cannot be built it should throw a \TYPO3\CMS\Frontend\Typolink\UnableToLinkException .

Attention

The configuration from the :ref:`page TSconfig

configuration <tutorial_backend_link_handler-tsconfig>` (step 1) is not available in the frontend. Therefore the information which repository to use must be stored in another way. In this example we hardcoded it. But you could also make it available by TypoScript setup or as part of the link format that is saved.

  • Previous
  • Next
Reference to the headline

Copy and freely share the link

This link target has no permanent anchor assigned. You can make a pull request on GitHub to suggest an anchor. The link below can be used, but is prone to change if the page gets moved.

Copy this link into your TYPO3 manual.

  • Home
  • Contact
  • Issues
  • Repository

Last rendered: May 09, 2025 09:12

© since 2012 by the TYPO3 contributors
  • Legal Notice
  • Privacy Policy