TYPO3 v9 introduced the
Page Title API
that should be used now.
This blog post is obsolete.
At work I had a web site that showed records on a listing page, and offered more information for each records on a detail page. The task was now to change the page title on the detail page to the record's own title.
The naive solution is to simply set the page title in the central frontend output object:
$GLOBALS['TSFE']->page['title'] = 'foo';
But this does not work on uncached plugins.
- TYPO3 page rendering process
- Solutions
- Disable title, add it with additionalHeaderData
- Content replacement during plugin processing
- Title replacement in post processing hook
- Additional notes
TYPO3 page rendering process
To understand why, we need to look how TYPO3's cache works together with uncached plugins:
-
Page <head> and <body> is generated and combined to a single string of HTML.
Uncacheable plugins are not executed yet; a placeholder is added instead:
some html..<!--INT_SCRIPT.abcdef-->more html
Additional placeholders are added for additionalHeaderData and additionalFooterData.
- This generated HTML is stored in the page cache.
-
In TypoScriptFrontendController::INTincScript(), TYPO3 iterates over all plugin placeholders, executes the respective plugin code and replaces the placeholder with the plugin output
It also replaces additional*Data placeholders with their values from $GLOBALS['TSFE'].
- This final HTML is send to the user.
When the user requests a cached page, only the last two steps 3 and 4 are executed. Thus there is no way to change the page title generated with TypoScript.
Solutions
There are three possible solutions to set the page title from an uncached plugin:
- Disable normal page title and insert it with additionalHeaderData ➘
- Replace already generated <title> tag during plugin processing ➘
- Replace already generated <title> tag in contentPostProc-output hook ➘
I suggest option 1.
Disable title, add it with additionalHeaderData
This is the option I recommend: It works with both cached and uncached plugins, and it keeps your code in one place.
At first, disable the creation of the normal title tag via config.noPageTitle for the pages that contain the plugin:
[globalVar = TSFE:id = 23|42] config.noPageTitle = 2 [global]
In your plugin's logic, add the page title to TSFE's additionalHeaderData:
$GLOBALS['TSFE']->additionalHeaderData['myCustomUserIntTitle'] = '<title>' . $this->getTitle($newTitle) . '</title>';
That's all needed.
Other people recommending this solution:
- Display News Title as Page Title in tt_news detail view
- Seitentitel dynamisch anpassen in TYPO3
- USER_INT manipulating <title> tag
- extbase-specific: Title und Meta-Description in Extbase setzen
Content replacement during plugin processing
When a cached plugin is processed, the cached HTML code is available in $GLOBALS['TSFE']->content. You might be tempted to simply modify it during plugin processing..
This works for uncached plugins only. In cached plugins, $content is not filled and changing it does not do anything since it gets overwritten later.
$GLOBALS['TSFE']->content = preg_replace( '#<title>.*<\/title>#', '<title>' . htmlspecialchars($newTitle) . '</title>', $GLOBALS['TSFE']->content );
Some people recommend this:
- TYPO3 Extension seminars – change pagetitle in singleview
- Seitentitel aus einer Extension heraus verändern
Title replacement in post processing hook
TYPO3 allows you to register a hook that gets executed just before the content is sent to the user. Just as in option #2 you can search and replace on the HTML:
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output']['robots'] = \Vnd\Class::class . '::contentPostProc';
And now you can preg_replace your new title into the HTML:
function contentPostProcOutput(&$params, TypoScriptFrontendController &$pObj) { $pObj->content = preg_replace( '#<title>.*<\/title>#', '<title>' . htmlspecialchars($newTitle) . '</title>', $pObj->content ); }
This does work for cached and uncached plugins.
The downside is that your title creation and title insertion code are in separate places now (plugin rendering vs. postproc-hook).
Additional notes
vhs has a <v:page.header.title> view helper that only works for cached plugins.
indexed_search will still not show the correct page
title in its search results.
$GLOBALS['TSFE']->indexedDocTitle
needs to be set
to the page title, too.