Configuration Concepts

Configuration Overview

The main principles of configuring a Rich Text Editor in TYPO3 apply to editing with any Rich Text Editor (rte_ckeditor, ...).

Some of the functionality (for example the RTE transformations) is embedded in the TYPO3 core and not specific to rte_ckeditor.

There are three main parts relevant for rich text editing with TYPO3:

Editor configuration
This covers how the actual editor (in this case CKEditor) should behave, what buttons should be shown, what options are available.
RTE transformations
This defines how the information is processed when saved from the Rich Text Editor to the database. And when loaded from the database into the Rich Text Editor.
Frontend output configuration
The information fetched from the database may need to be processed for the frontend. The configuration of the frontend output is configured via TypoScript.

This section mainly covers editor configuration and RTE transformations, as for TypoScript the TypoScript reference handles output of HTML content and has everything preset (see parseFunc).

Editor Configuration

YAML

TYPO3 is using a custom YAML API for handling YAML in TYPO3 based on the Symfony YAML package. Therefore environment variables can be used.

YAML Basics

  • YAML is case sensitive
  • Indenting level reflects hierarchy level and indenting must be used consistently (indent with 2 spaces in rte_ckeditor configuration).
  • Comments begin with a #.
  • White space is important, use a space after :.

This is a dictionary (associative array):

key1: value
key2: value
Copied!

A dictionary can be nested, for example:

key1:
  key1-2: value
Copied!

This is a list:

- list item 1
- list item 2
Copied!

A dictionary can be combined with a list:

key:
  key2:
    - item 1
    - item 2

Copied!

Configuration Presets

Presets are the heart of having custom configuration per record type, or page area. A preset consists of a name and a reference to the location of a YAML file.

TYPO3 ships with three RTE presets, “default”, “minimal” and “full”. The "default" configuration is active by default.

It is possible for extensions to ship their own preset like “news”, or “site_xyz”.

Registration of a preset happens within system/config.php, system/additional.php or within ext_localconf.php of an extension:

$GLOBALS['TYPO3_CONF_VARS']['RTE']['Presets']['default'] = 'EXT:rte_ckeditor/Configuration/RTE/Default.yaml';
Copied!

This way, it is possible to override the default preset, for example by using the configuration defined in a custom extension:

$GLOBALS['TYPO3_CONF_VARS']['RTE']['Presets']['default'] = 'EXT:my_extension/Configuration/RTE/Default.yaml';
Copied!

TYPO3 uses the “default” preset for all Rich-Text-Element fields. To use a different preset throughout an installation or a branch of the website, see Overriding Configuration via page TSconfig.

Selecting a specific preset for bullet lists can be done via TCA configuration of a field. The following example shows the TCA configuration for the sys_news database table, which can be found in EXT:core/Configuration/TCA/sys_news.php.

'content' => [
   'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.text',
   'config' => [
      'type' => 'text',
      'cols' => 48,
      'rows' => 5,
      'enableRichtext' => true,
      'richtextConfiguration' => 'default',
   ],
Copied!

Enabling Rich Text Parsing itself is done via -, and a specific configuration can be set via -, setting it to for example “news”.

Overriding Configuration via page TSconfig

Instead of overriding all TCA fields to use a custom preset, it is possible to override this information via page TSconfig.

The option RTE.default.preset = news can also be set on a per-field and per-type basis:

EXT:my_sitepackage/Configuration/page.tsconfig
# per-field
RTE.config.tt_content.bodytext.preset = minimal

# per-type
RTE.config.tt_content.bodytext.types.bullets.preset = bullets
Copied!
line #2
This sets the "minimal" preset for all bodytext fields of content elements.
line #4
This sets the "bullets" preset for all bodytext fields of content elements, with Content Type “Bullet list” (CType=bullets).

Of course, any other specific option set via YAML can be overridden via Page TSconfig as well:

Specific options set via YAML can be overridden via page TSconfig as well - but be aware that boolean values can not be set, and arrays are not merged but overridden.

EXT:my_sitepackage/Configuration/page.tsconfig
# Restrict format_tags to h2 in bodytext field of content elements
RTE.config.tt_content.bodytext.editor.config.format_tags = h2
Copied!

The loading order for configuration is:

  1. preset defined for a specific field via PageTS
  2. richtextConfiguration defined for a specific field via TCA
  3. general preset defined via page TSconfig
  4. default

For more examples, see RTE in "TSconfig Reference".

RTE Transformations

Transformations are directives for parsing HTML markup. They are executed by the TYPO3 Core every time a RTE-based field is saved to the TYPO3 database or fetched from the database for the Rich Text Editor to render. This way, there are always two ways / two transformations applied.

There are several advantages for transformations, the most prominent reason is to not inject bad HTML code into the database which in turn would be used for output. Transformations from the RTE towards the database can filter out HTML tags or attributes.

You can read more about RTE Transformations in TYPO3 Explained.

A Brief Dive Into History

Back in the very old days of TYPO3, there was an RTE which only worked inside Microsoft Internet Explorer 4 (within the system extension “rte”). All other editors of TYPO3 had to write HTML by hand, which was very complicated with all the table-based layouts available. Links were not set with a <a> tag, but with a so-called <typolink 23,13 _blank> tag. Further tags were <typolist> and <typohead>, which were stored in the database 1:1. Since RTEs did not understand these special tags, they had to transform these special tags into valid HTML tags. Additionally, TYPO3 did not store regular <p> or <div> tags but treated every line without a surrounding HTML block element as <p> tag. The frontend rendering then added <p> tags for each line when parsing (see below).

Transformations were later used to allow <em>/<strong> tags instead of <b>/<i> tags, while staying backwards-compatible.

A lot of transformation options have been dropped for TYPO3 v8, and the default configuration for these transformations acts as a solid base. CKEditor itself includes features that work as another security layer for disallowing injecting of certain HTML tags in the database.

For TYPO3 v8, the <typolink> tag was migrated to proper <a> tags with a special <a href="t3://page?id=23"> syntax when linking to pages to ensure HTML valid output. Additionally, all records that are edited and stored to the database now contain proper <p> tags, and transformations for paragraph tags are only applied when not set yet.

Transformations for invalid links and images (still available in HtmlArea) are still in place.

Most logic related to transformations can be found within \TYPO3\CMS\Core\Html\RteHtmlParser .

Transformations vs. CKEditor’s Advanced Content Filter

TYPO3’s HtmlParser transformations were used to transform readable semi-HTML code to a full-blown HTML rendering ready for the RTE and vice versa. Since TYPO3 v8, magically adding <p> tags or transforming <typolink> tags is not necessary anymore, which leaves transformations almost obsolete.

However, they can act as an extra fallback layer of security to filter out disallowed tags when saving. TYPO3 v8 configuration ships with a generic transformation configuration, which is mainly based on legacy functionality shipped with TYPO3 nowadays.

However, CKEditor comes with a separate strategy of allowing which HTML tags and attributes are allowed, and can be configured on an editor-level. This configuration option is called “allowedContent”, the feature itself is named Advanced Content Filter (ACF).

Activating CKEditor’s table plugin allows to add <table>, <tr> tags etc. Enabling the link picker enables the usage of <a> tags. CKEditor cleans content right away which was e.g. copy-pasted from MS Word and does not match the allowed tags.

Frontend Output Configuration

Mostly due to historical reasons, the frontend output added <p> tags to each line which is not wrapped in HTML. Additionally the <typolink> tag was replaced by <a> tags and checked if e.g. if a link was set to a specific page within TYPO3 is actually accessible for this specific visitor.

The latter part is still necessary, so the <a href="t3://page?id23"> HTML snippet is replaced by a speaking URL which the power of typolink will still take care of. There are, of course, more options to it, like default “target” attributes for external links or spam-protecting links to email addresses, which all happens within the typolink logic, the master for generating a link in the TYPO3 Frontend rendering process.

TypoScript

As with every content that is rendered via TYPO3, this processing for the frontend output of Rich-Text-Editing fields is done via TypoScript, more specifically within the stdWrap property parseFunc. With Fluid Styled Content and CSS Styled Content comes lib.parseFunc and lib.parseFunc_RTE which add support for parsing <a> and <link> tags and dumping them into the typolink functionality. The shipped TypoScript code looks like this:

lib.parseFunc.tags {
   a = TEXT
   a {
      current = 1
      typolink {
         parameter.data = parameters:href
         title.data = parameters:title
         ATagParams.data = parameters:allParams
         target.data = parameters:target
         extTarget = {$styles.content.links.extTarget}
         extTarget.override.data = parameters:target
      }
   }
}
Copied!

If you already use Fluid Styled Content and CSS Styled Content and you haven’t touched that area of TypoScript yet, you’re good to go by including the TypoScript file.

Fluid

Outputting the contents of a RTE-enabled database field within Fluid can be achieved by adding {record.myfield -> f:format.html()} which in turn calls stdWrap.parseFunc with lib.parseFunc_RTE thus applying the same logic. Just ensure that the lib.parseFunc_RTE functionality is available.

You can check if this TypoScript snippet is loaded by using Web > TypoScript and use the TypoScript Tree (Setup) to see if lib.parseFunc_RTE is filled.