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.
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.
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'].
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.
There are three possible solutions to set the page title from an uncached plugin:
I suggest option 1.
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:
additionalHeaderData['myCustomUserIntTitle']
= '' . $this->getTitle($newTitle) . ' ';]]>
That's all needed.
Other people recommending this solution:
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.
content = preg_replace(
'#.*<\/title>#',
'' . htmlspecialchars($newTitle) . ' ',
$GLOBALS['TSFE']->content
);]]>
Some people recommend this:
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:
content = preg_replace(
'#.*<\/title>#',
'' . htmlspecialchars($newTitle) . ' ',
$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).
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.
I'm moving to a new server, and my avatar image generation script did not work anymore:
$ php surrogator.php processing mm.svg PHP Fatal error: Uncaught ImagickException: unable to open file `/tmp/magick-bcfNKPgxfBoOcZ5_de_xB9LzxZLhN2Dq': No such file or directory @ error/constitute.c/ReadImage/614 in /home/cweiske/www/avatar.cweiske.de/surrogator.php:236 Stack trace: #0 /home/cweiske/www/avatar.cweiske.de/surrogator.php(236): Imagick->readImage() #1 /home/cweiske/www/avatar.cweiske.de/surrogator.php(155): surrogator\createSquare() #2 {main} thrown in /home/cweiske/www/avatar.cweiske.de/surrogator.php on line 236
The mm.svg file clearly exists, and my user is able to create files in /tmp/ - which I tested with touch /tmp/foo.
Using strace helped me to find the issue:
$ strace php surrogator.php [...] lstat("/usr/lib/x86_64-linux-gnu/ImageMagick-6.9.11/modules-Q16/coders/svg.la", 0x7ffd264c61c0) = -1 ENOENT (Datei oder Verzeichnis nicht gefunden) stat("/usr/lib/x86_64-linux-gnu/ImageMagick-6.9.11//modules-Q16/coders/svg.la", 0x7ffd264c61f0) = -1 ENOENT (Datei oder Verzeichnis nicht gefunden) stat("/tmp/magick-Uoh--TjgMhCveOq8LHbHQyVLXA87cpvx", 0x7ffd264ca2b0) = -1 ENOENT (Datei oder Verzeichnis nicht gefunden) stat("/home/cweiske/www/avatar.cweiske.de/raw/mm.svg", {st_mode=S_IFREG|0644, st_size=3013, ...}) = 0 write(2, "PHP Fatal error: Uncaught Imagi"..., 497PHP Fatal error: Uncaught ImagickException: unable to open file `/tmp/magick-Uoh--TjgMhCveOq8LHbHQyVLXA87cpvx': No such file or directory @ error/constitute.c/ReadImage/614 in /home/cweiske/www/avatar.cweiske.de/surrogator.php:236 [...]
PHP's Imagick extension wants to load the svg.la module that is responsible for loading .svg images, and that fails.
It turned out that I had to install the imagemagick package - php-imagick alone was not enough.
Process mails from web applications like e-mail address verification and password reset mails should be tagged as "automatically submitted" so that mail servers do not respond with "Out of office" or vacation notification mails.
The official standard for that is RFC 3834: Recommendations for Automatic Responses to Electronic Mail, which defines an e-mail header Auto-Submitted: auto-generated for our use case.
E-mails automatically built from Laravel notifications can be modified to contain that header: Inside the toMail() method, register a modification callback for the MailMessage class:
withSwiftMessage([$this, 'addCustomHeaders'])
->subject(_('Reset your password'));
}
/**
* Add our own headers to the e-mail
*/
public function addCustomHeaders(\Swift_Message $message)
{
$message->getHeaders()->addTextHeader('Auto-Submitted', 'auto-generated');
}
}
]]>
In 2014 I wrote grauphel, a owncloud/Nextcloud extension that allows you to synchronize notes between Tomboy (Linux, Windows), Tomdroid (Android) and Conboy (Nokia N900 - Maemo).
I personally do not use grauphel anymore and thus have no reason to maintain it any longer. For each Nextcloud release it must be tested, updated and re-released. Big changes are necessary to make it compatible with Nextcloud 21 as well.
The last real changes to grauphel were done in 2018 (version 0.7.0), and since then the changes were only to make it compatible with Nextcloud 15...20. The application itself is complete since 4 years, but unfortunately the foundations are constantly moving.
The original grauphel was a standalone application, but I converted it to a owncloud/nextcloud extension so that I can rely on its login and user management. From today's perspective this was a mistake; a standalone version would still work today and not require unnecessary maintenance.
I'd like to hand grauphel over to a new maintainer that keeps it compatible with the latest Nextcloud versions.
Alternatively, I could make a standalone version of grauphel that works without Nextcloud if I get money to work on this task - 1000€.
Please write a comment in the issue on github if you'd like to take over the project, or how much you're willing to contribute to the standalone version's fund.
All my blog posts are XHTML, because I can load and manipulate them with an XML parser. I do that with scripts when adding IDs for better referencing, and when compiling the blog posts by adding navigation, header and footer.
The pages have no XML declaration because the W3C validator complains that
Saw <?. Probable cause: Attempt to use an XML processing instruction in HTML. (XML processing instructions are not supported in HTML.)
But when loading such a XHTML page with PHP's SimpleXML library and generating the XML to save it, entities get encoded:
ÄÖÜ