TYPO3

Site set settings: settings.definitions.yaml in practice

6 min read

Typed settings for every site

For years the place for “small things an integrator may change” in TYPO3 was the constant editor. A colour here, a page uid there, a logo path. In theory editors could change them. In practice nobody found them, the comment syntax for categories was a mystery, and in a multi-site installation you needed a sys_template record per site just to change one value.

Since TYPO3 v13 the better place is the site set. A set can describe its settings in settings.definitions.yaml, with a type, a default, a label and a category. Each site stores its own values in config/sites/<identifier>/settings.yaml. This post shows how I use it, with a small sitepackage example.

Problems I faced with constants

  • No types. A constant is a string. If somebody writes #29292 instead of #292929, TypoScript does not care.
  • Values live in database records, so they are not in git and not reviewable.
  • Per-site values need per-site template records, which drift apart over the years.
  • The comment-based category syntax of the constant editor was hard to remember even for me, after many years of TYPO3.

Step 1: describe the settings

A site set is a folder with config.yaml under Configuration/Sets/<Name>/. Next to it you put settings.definitions.yaml. The hoja.in sitepackage still has its meta description and theme colour hard-coded in setup.typoscript, so they are perfect candidates. Here is how the definitions would look:

# EXT:sitepackage/Configuration/Sets/Sitepackage/settings.definitions.yaml
categories:
  sitepackage:
    label: 'Portfolio theme'
  sitepackage.meta:
    label: 'Meta data'
    parent: sitepackage
  sitepackage.layout:
    label: 'Layout'
    parent: sitepackage

settings:
  sitepackage.meta.description:
    label: 'Default meta description'
    description: 'Used when a page has no own description.'
    category: sitepackage.meta
    type: text
    default: ''

  sitepackage.meta.themeColor:
    label: 'Browser theme colour'
    category: sitepackage.meta
    type: color
    default: '#292929'

  sitepackage.layout.contactPage:
    label: 'Page with the contact form'
    category: sitepackage.layout
    type: page
    default: 0

  sitepackage.layout.showBadges:
    label: 'Show certification badges in the footer'
    category: sitepackage.layout
    type: bool
    default: true

  sitepackage.layout.heroStyle:
    label: 'Hero style'
    category: sitepackage.layout
    type: string
    default: dark
    enum:
      dark: 'Dark background'
      light: 'Light background'

Some notes from practice:

  • The keys are flat, dotted identifiers. Prefix them with something unique (here sitepackage.) so they do not clash with core sets like styles.content.* or seo.*.
  • In TYPO3 14.3 the core registers these types: bool, color, int, number, page, string, stringlist, text and url. You can see them as classes in EXT:core/Classes/Settings/Type/. An invalid value is not accepted silently: the type validates it and falls back to the default, with a log entry.
  • A setting can be readonly: true. The editor then shows it but does not let you change it; only a developer can, in the YAML file.
  • enum turns a string setting into a select box. Since v14.2 the enum labels can be localized as well (Feature #106640).
  • Instead of writing labels into the YAML file, you can put a labels.xlf next to config.yaml, with ids like settings.sitepackage.meta.themeColor and categories.sitepackage.meta. The core sets do it this way.

Step 2: set values per site

The defaults belong to the set. The values of one site belong to the site, in config/sites/main/settings.yaml. Since v13.4 the recommended format is a flat map (Important #106894), so foo.bar and foo.bar.baz can both have a value:

# config/sites/main/settings.yaml
sitepackage.meta.themeColor: '#1d1d1b'
sitepackage.layout.contactPage: 12

The real settings.yaml of hoja.in currently holds only one value from a core set, written as a tree. TYPO3 still reads the tree form; the settings editor converts it to a map the next time it saves:

# Section pages (canonical = root page), content pool, quicklinks and storage folders
seo:
  sitemap:
    pages:
      excludePagesRecursive: '7,10,11,12,13,14,17,20'

That setting is defined by the core set typo3/seo-sitemap. So this is the second big win of sets: you configure an extension’s behaviour per site in a YAML file that is in git, instead of in a template record.

Step 3: read the values

In TypoScript

Site settings are available as TypoScript constants (that part is older than sets, it came with TYPO3 10.4). So the hard-coded lines in my setup become:

page {
  meta.description = {$sitepackage.meta.description}
  meta.theme-color = {$sitepackage.meta.themeColor}
}

If you migrate an extension from constants to settings and want both to keep working for a while, v13.1 added a null coalescing operator for constants. The core seo extension uses it exactly for the setting above:

excludePagesRecursive = {$plugin.tx_seo.settings.xmlSitemap.sitemaps.pages.excludePagesRecursive ?? $seo.sitemap.pages.excludePagesRecursive}

In Fluid with PAGEVIEW

PAGEVIEW assigns the constants tree as the variable settings, so dotted keys become nested array keys in the template:

<f:if condition="{settings.sitepackage.layout.showBadges}">
    <f:render partial="Badges" />
</f:if>
<f:link.page pageUid="{settings.sitepackage.layout.contactPage}">Contact</f:link.page>

One thing to watch: through TypoScript constants every value arrives as a string. A bool setting with value false is the string "0", which Fluid treats as false in a condition, so the example works. But do not compare it with == false and expect PHP semantics.

In PHP

In a middleware, controller or event listener you get the typed value from the site object of the request:

use TYPO3CMSCoreSiteEntitySite;

$site = $request->getAttribute('site');
if ($site instanceof Site) {
    $contactPage = (int)$site->getSettings()->get('sitepackage.layout.contactPage', 0);
}

Step 4: the backend settings editor

TYPO3 v13.3 added a settings editor (Feature #104794). In v13 it is the module Site Management > Settings. In v14 the backend modules were reorganised (Feature #107628): the separate settings module was merged into Sites > Setup, the same module where you edit the site configuration. The editor lists your categories and settings with proper widgets: a colour picker for color, a page browser for page, a select box for enum.

Two details that matter in a team:

  1. The editor only writes values that differ from the default of the active sets. Your settings.yaml stays small and the diff in git is readable.
  2. When the feature came in v13.3, the module was for administrators only. So plan who changes what. For hoja.in that is me, so nothing to plan.

Because the editor writes a file, a change made on production is a change to a file that is also in git. Decide early whether settings are edited in the backend on production (then do not deploy over settings.yaml) or only in git (then do not give anybody access to the module on production). Mixing both ends with somebody’s change being overwritten on the next deploy. I have seen that with other files in one of my projects, and it is not fun to explain.

When to still use constants

Almost never for new work. For an existing extension with many users, keep the constants for one major version and read them with the ?? fallback shown above, then drop them. For a sitepackage you own, move everything at once; it is an afternoon of work and you get types, labels and git history for free.

If this post helped you, I will be really happy. Cheers!

Further reading

Leave a comment

Your email address will not be published.