Skip to content

Just before Christmas, I completed the upgrade of this blog to TYPO3 v12. Right in time to switch off the computer until the new year.

Today I will outline some selected tasks that were necessary for the upgrade.


When upgrading to TYPO3 v12, everyone will have to deal with two major changes to their TYPO3 installation:

  1. The new structure of Composer installations (Changelog #98484), in which the familiar typo3/ext/ directory is no longer used.
  2. The new CKEditor 5 (Changelog #96874), which will require a different configuration and is incompatible with old plugins.

Switch to typo3/cms-composer-installers v4+

In the future, for Composer installations, the TYPO3 core and every TYPO3 extension will be stored in the vendor directory – just like all other PHP packages have already been before.

This change was already announced in February 2022. You can find a detailed description of the background on these two articles:

To make the final upgrade to TYPO3 v12 easier, you can already change the directory structure in TYPO3 v11. I decided to take this approach and can only recommend it to you.

These two commands are required:

composer req typo3/cms-composer-installers:^4.0@rc
composer install

4.0@rc is the only available version that provides the new structure in TYPO3 v11. By executing the two commands, TYPO3 and all TYPO3 extensions are installed in vendor/ and symlinks for public extension files are created in public/_assets/.
You will have to remove the old directories in the public directory (typo3/sysext/ and typo3conf/ext/) manually.

Very helpful is the blog post by Chris Müller, in which he describes the necessary migrations in TypoScript, CSS, Fluid & Co:

Middleware for the Web App Manifest

My blog also contained some paths that had to be adapted. With Chris' instructions, they were easy to migrate.

Only the web manifest was a little more complicated: this file contains paths to favicons. However, I didn't want to store the hashed part of the file paths in hard-coded form.

  "background_color": "#ffffff",
  "display": "browser",
  "icons": [
      "src": "/_assets/6c1b7cf48a271482dd95e90ed93afd24/Images/Favicons/android-chrome-192x192.png",
      "type": "image/png",
      "sizes": "192x192"
      "src": "/_assets/6c1b7cf48a271482dd95e90ed93afd24/Images/Favicons/android-chrome-512x512.png",
      "type": "image/png",
      "sizes": "512x512"
  "name": " - Sebastian Klein",
  "short_name": "",
  "theme_color": "#eb4a47"

Kevin Appelt kindly shared a middleware solution in TYPO3 Slack that provides a web manifest in TYPO3 v12. The dynamic values (theme color, favicon paths, ...) can be set via Site Configuration, which supports multi-domain installations.

I have slightly adapted the middleware for my intended use:
You can simply add it to the sitepackage of your project.

Upgrade to CKEditor 5

CKEditor 4 reached its EOL in June 2023. Accordingly, TYPO3 v12 relies on its successor CKEditor 5.

Problematic for upgrades is that the software architecture in this RTE has changed fundamentally. All of the old plugins are no longer compatible. Some of them have to be rewritten at great expense.

Obstacles and teething problems

Assigning multiple CSS classes

Editors can apply design styles to text content in the RTE. In some cases, an HTML element should receive multiple CSS classes. In CKEditor 4, this was possible as follows:

      - { name: 'Large button', element: 'a', attributes: { 'class': 'c-btn c-btn--large c-btn--primary' } }

The YAML configuration has also changed in TYPO3 v12. This is documented in the changelog. However, it is not obvious that several classes must now be noted as a comma-separated list.

        - { name: 'Large button', element: 'a', classes: ['c-btn', 'c-btn--large', 'c-btn--primary'] }

List styles

With CKEditor 5, it was no longer possible to set CSS classes for lists (<ul>, <ol>) in TYPO3 v12 – an often used solution to customize list styling in text.

CKEditor 5 actually provides two list plugins: List and DocumentList. While TYPO3 v12 initially included the List plugin, only DocumentList supports the styling of list elements.

As of version 12.4.6, TYPO3 therefore switched to the DocumentList plugin. List styling is now possible:

        - { name: 'Checkmark list', element: 'ul', classes: ['list--checkmark'] }

The problem did not only affect TYPO3. Missing list styling in CKEditor 5 is also an issue in Drupal.

The CKEditor project has also addressed the subject and just made a modification: List was renamed to LegacyList; DocumentList becomes the new List plugin.

New CKEditor plugin for wordbreak elements

I use the <wbr> element to set conditional line breaks in URLs and directory paths. For CKEditor 5, I had to replace my linebreak plugin with a new solution.

Adding a single HTML element to the CKEditor was at least a rewarding and straightforward task to familiarize myself with its architecture. It eventually resulted in a new TYPO3 extension that provides this element in CKEditor 5 in a user-friendly way.

While maintaining this article, I noticed that the <wbr> element was splitting the surrounding inline elements in the RTE. I therefore released a new version of the extension that fixes the problem.

CKEditor plugin for code snippets

To maintain my code snippets, I partly use the extension "beautyofcode" (thanks to Felix Nagel!) and secondly the "Code Snippets" plugin of CKEditor 4.

For CKEditor 5, the TYPO3 core includes the "Code blocks" feature. But: it is not loaded by default! If you simply add codeBlock to the toolbar in the YAML configuration, you will receive an error message in the browser console:

toolbarview-item-unavailable {item: 'codeBlock'}

The code blocks (and other CKEditor features) are only available once you import the corresponding module. The configuration is as follows:

      - { 'module': '@ckeditor/ckeditor5-code-block', 'exports': ['CodeBlock'] }

        - codeBlock
        # etc.

        - { language: 'html', label: 'HTML' }
        - { language: 'css', label: 'CSS' }
        - { language: 'yaml', label: 'YAML' }
        - { language: 'javascript', label: 'JavaScript' }
        - { language: 'json', label: 'JSON' }
        - { language: 'php', label: 'PHP' }
        - { language: 'sql', label: 'SQL' }
        # etc.

With the defined languages, you can then set up syntax highlighting in the frontend, for example with Prism.

I found this solution via TYPO3 Slack in an older patch.

div wrappers in CKEditor 5

Particularly in the tutorials, I use alert boxes to highlight some content. The classes are often given directly to a single paragraph. However, I occasionally use a wrapping <div> container, which allows adding a short list to the information box.

CKEditor 5 supports both paragraphs and <div> elements as block format. However, the two HTML elements can only be interchanged. Nesting is not provided by default – paragraphs cannot be positioned within divs.

To enable this for my website, I had to write another small plugin. This is not yet editor-friendly, but at least it allows me to use the alerts as before, and to carry on with the upgrade to TYPO3 v12.

For those who need the solution:

When time permits, I'll have a go at a better version of the plugin, with which a div wrapper can be inserted in a user-friendly way and in which the available CSS classes can be defined via YAML.

Further necessary tasks

Use of certain ViewHelpers outside of Extbase context

Since TYPO3 v12, ViewHelpers no longer automatically have an Extbase request (Changelog #98377). This can cause various problems in existing installations.

In my case, the FLUIDTEMPLATE object for my website templates was affected. The extension name was missing in the translate and uri.resource ViewHelpers:

<a class="c-nav-social__link" href=""
    <svg class="c-nav-social__icon">
        <use xlink:href="{f:uri.resource(path: 'Images/Icons/icon-sprite.svg#icon--github')}"></use>
    <span class="c-nav-social__title">/sebkln</span>

A RuntimeException then occurs in the frontend, in which the solution is already mentioned:

ViewHelper f:uri.resource needs an Extbase Request object to resolve
extension name for given path "Images/Icons/icon-sprite.svg#icon--github".
If not in Extbase context, either set argument "extensionName",
or (better) use the standard EXT: syntax for path attribute like

This would be a possible adjustment:

<a class="c-nav-social__link" href=""
    <svg class="c-nav-social__icon">
        <use xlink:href="{f:uri.resource(path: 'Images/Icons/icon-sprite.svg#icon--github', extensionName: 'sitepackage')}"></use>
    <span class="c-nav-social__title">/sebkln</span>


The effort involved in migrating to CKEditor 5 should not be underestimated. You will have to find new solutions for some features, which may have to be developed by yourself. I like that the new editor also improves things – for example, the separation between the editor view and the data stored in the database. However, getting to grips with the architecture and API will take some time.


With TYPO3 v12, I can use my blog again as a test object for new features. At the top of my list: the Content-Security-Policy handling (Changelog #99499).

This HTTP security header has been set via TypoScript on my website since 2019. At the same time, I wrote a tutorial about it. The fact that TYPO3 now provides this as a prominent core functionality emphasizes the benefits and relevance of this header.

I can now migrate the existing directives to the new Policy Builder and test further functionality using a practical example.
And in the end, I'm sure I'll end up with another tutorial.

Back to news list