TYPO3 site package tutorial

A site package is a custom TYPO3 extension that contains files regarding the theme and functionality of a site.

This tutorial describes step by step how to come from your first TYPO3 installation to the first basic site.

You can use the Site Package Builder to create a customized site package. If you want to follow this tutorial, choose "Site Package Tutorial" as base package.


Prerequisites

In this section we mention the prerequisites that you need before you start with this tutorial.

Generate a site package

Generate a site package using the official Site Package Builder and install it.

Create initial pages

Here we use the initialization data provided by your site package to create some initial pages including dummy content.

Assets

Assets usually include CSS files, JavaScript and images / icons used for design purposes.

Fluid Template

We introduce the templating engine Fluid, that is used to render the html pieces in a logically manner. Then we describe the directory structure that is needed in a site package extension. We also explain the first steps to include the previously static files and html pieces using Fluid.

Content mapping

Here we explain the purpose of backend layouts. Additionally we introduce the DatabaseQueryProcessor which is used to render content from a special "colPos" previously defined in the backend layout. We use Fluid to output content from a specific colPos. By this we get to know the cObject ViewHelper.

Main menu

We introduce the main menu, explain how we build up a menu processor with TypoScript and how we can output the menu with Fluid. We introduce the so called "Debug ViewHelper".

Site sets

In this section we configure the site package using the new concept of site sets. The settings are now stored in a yaml file called settings.definitions.yaml.

Content Blocks

We explain how the TYPO3 Extension friendsoftypo3/content-blocks can be used to create custom Content Elements, for example for a jumbotron or slider.

Extension Configuration

We explain the needed composer configurations and we connect it with the site sets configurations that we made in the previous chapter.

Next steps

In this chapter we describe the next steps which you can do with your new site package.

Prerequisites to create a TYPO3 site package extension

Before you start working on this tutorial you should have a working TYPO3 installation in versions 13.4 or above.

We assume you use Composer and work locally with DDEV.

Your TYPO3 installation should be empty and have no pages, designs or third party extensions installed.

You can follow this tutorial to install TYPO3 with DDEV and Composer:

You should be able to log in into the TYPO3 backend and see the following:

Screenshot of a fresh TYPO3 13.4-dev installation with no page in the page tree

A fresh, empty TYPO3 installation (light mode)

This TYPO3 tutorial assumes that the reader has some basic knowledge in the following areas:

It is also helpful if you know the following concepts:

Generate a site package

A site package is a custom TYPO3 extension which contains configuration, templates, assets, etc that are used for the site it belongs to.

So first we generate a minimal extension.

Generate and download a site package

You can download a site package by using the official Site Package Builder at https://get.typo3.org/sitepackage or by using curl.

You have the choice of three site packages types:

  • Bootstrap Package: This site package comes with a ready to use theme
  • Fluid Styled Content: A minimal site package where you can build your own custom theme.
  • Site Package Tutorial: Contains all files that are used as examples in this tutorial.

To follow this tutorial, chose "Site Package Tutorial" as type of the site package.

Download and unzip the zip file, place the result in folder packages/my_site_package, and install it.

Extension installation

This tutorial assumes that your TYPO3 instance is a brand new installation, without any themes, templates, pages or content.

We assume that you are working on your local machine using DDEV and that you followed these steps:

Installing TYPO3 with DDEV

Install the site package you just created

If you used the Site Package Builder, file packages/my_site_package/README.md contains instructions on how to install your site package.

Move / unzip your extension folder my_site_package/ into the packages/ folder. Then require the extension via Composer using the package name defined in the site package extension's composer.json now located at packages/my_site_package/

packages/my-site-package/composer.json
{
   "name": "my-vendor/my-site-package"
}
Copied!

require it by:

Execute in directory page_root
ddev composer require my-vendor/my-site-package:@dev
Copied!

Project file structure

Your project should now have the following structure:

  • .ddev

  • config

    • sites

      • main

        • config.yaml
  • packages

    • my_site_package

      • [All sitepackage files]
      • composer.json
  • public

    • fileadmin

      • [Images for content, PDFs, ...]
    • [public files needed by TYPO3]
  • var

    • log
    • [private files needed by TYPO3]
  • vendor

    • [All installed packages, including TYPO3 source]
  • composer.json
  • composer.lock

Look at the a basic site set

New in version 13.1

The site package build by Site Package Builder comes with a ready to use site set in folder packages/my_site_package/Configuration/Sets/SitePackage/.

The set itself is defined within this folder in the file config.yaml:

packages/my-site-package/Configuration/Sets/SitePackage/config.yaml
name: my-vendor/my-site-package
label: 'My Site Package'
dependencies:
  - typo3/fluid-styled-content
  - typo3/fluid-styled-content-css
Copied!

You will learn more about site sets in chapter The site set.

You can find the complete reference in TYPO3 explained: Site sets.

During installation of your site package a page tree with example content was created, and should already have a site configuration in folder config/sites/main.

When you look at the site configuration in module Site Management > Sites it should already contain the set "My Site package". Other sets, for example if you want to use typo3/cms-form can be added here.

Screenshot demonstrating adding the "My Site package" to the site main

Use module Site Management > Sites to add the "Example: My Site package"

If you made no changes, the site configuration should look like this:

config/sites/main/config.yaml
base: '/'
dependencies:
  - my-vendor/my-site-package
languages:
  -
    title: English
    enabled: true
    languageId: 0
    base: /
    locale: en_US.UTF-8
    navigationTitle: English
    flag: us
rootPageId: 1
websiteTitle: 'My Site Package'
Copied!

The site set as TypoScript Provider

New in version 13.1

TYPO3 uses TypoScript as configuration language. The TypoScript is used to configure the templates, which are created with the templating language Fluid.

A file called packages/my_site_package/Configuration/Sets/SitePackage/setup.typoscript provides the TypoScript to your site. This file contains imports of files from folder packages/my_site_package/Configuration/Sets/SitePackage/TypoScript which contain the actual configuration.

You can learn more about the TypoScript syntax used here in chapter A minimal page created by pure TypoScript of the "Getting Started Tutorial".

The TYPO3 Fluid version

File packages/my_site_package/Configuration/Sets/SitePackage/TypoScript/page.typoscript Defines how the output of all pages of the site is rendered with Fluid templates:

packages/my_site_package/Configuration/Sets/SitePackage/TypoScript/page.typoscript
page = PAGE
page {
  10 = PAGEVIEW
  10 {
    paths {
      0 = EXT:my_site_package/Resources/Private/PageView/
      10 = {$MySitePackage.template_path}
    }

    dataProcessing {
      # makes content elements available as {content} in Fluid template
      10 = page-content
    }
  }
  shortcutIcon = {$MySitePackage.favicon}
}
Copied!

Line 6 defines from what directory the Fluid Templates are loaded. Line 7 allows to override this part via settings.

Learn more about using Fluid Templates in chapter Fluid Templates.

Preview page

Whenever we have made changes to the Fluid templates or TypoScript files, it is necessary to Flush frontend caches in the menu in the top bar before you can preview the page properly:

Flush the frontend cache after changing template files

You can then preview your page by clicking on the button View webpage in the page module.

Composer configuration composer.json

In step Create a minimal TYPO3 extension a file called composer.json was created for you:

packages/my_site_package/composer.json
{
    "name": "my-vendor/my-site-package",
    "type": "typo3-cms-extension",
    "description": "Site package to follow the tutorial.",
    "homepage": "https://docs.typo3.org/permalink/t3sitepackage:start",
    "license": ["GPL-2.0-or-later"],
    "keywords": ["TYPO3 CMS"],
    "require": {
        "typo3/cms-core": "^13.4",
        "typo3/cms-rte-ckeditor": "^13.4",
        "typo3/cms-fluid-styled-content": "^13.4"
    },
    "suggest": {
        "friendsoftypo3/content-blocks": "Allows to create custom content elements. "
    },
    "autoload": {
        "psr-4": {
            "MyVendor\\MySitePackage\\": "Classes/"
        }
    },
    "extra": {
        "typo3/cms": {
            "extension-key": "my_site_package"
        }
    }
}
Copied!

At the top of the composer.json file we see the Composer package name my-vendor/my-site-package (with a dash) and at the bottom we see the TYPO3 extension key in the extra section - my_site_package (with an underscore). The Composer "name" consists of a vendor name followed by a forward slash and the lowercase extension name with dashes.

When you reference files in your extension, the extension key is used, for example when setting your favicon in TypoScript:

package/my-site-package/Configuration/Sets/SitePackage/setup.typoscript
page {
    shortcutIcon = EXT:my_site_package/Resources/Public/Icons/favicon.ico
}
Copied!

Create initial pages

To follow this tutorial you need to have a few pages in your page tree and some content elements on those pages. You also need a basic site configuration.

The site package you build in chapter Generate a site package creates a folder called Initialisation. This folder contains an example page tree with some dummy content in file packages/my_site_package/Initialisation/data.xml, and an example site configuration in file packages/my_site_package/Initialisation/Site/main/config.yaml. Folder packages/my_site_package/Initialisation/data.xml.files contains some example images to demonstrate using certain content elements.

Load the example data automatically

After installing the site package you downloaded from https://get.typo3.org/sitepackage run the following command:

ddev typo3 extension:setup
Copied!

Loading the data might take a few seconds. If you do not see the new pages try reloading the backend.

Screenshot of the backend module "Page" with the loaded example data

The page tree in the module Web > Page now contains a few example pages.

Site configuration

If you followed Load the example data automatically a basic configuration has been created for you.

The site configuration is stored in a file called config/sites/main/config.yaml. You can edit this file in the backend module Site Management > Sites:

Screenshot of the backend module "Site Management"

Edit the site configuration in Site Management > Sites

If you want to create a site configuration manually see Create a new site configuration in the "Getting Started Tutorial".

Asset handling in TYPO3

Assets usually include CSS files, JavaScript and images / icons used for design purposes.

Within an extension, including a site package, assets can only be placed in folder Resources/Public and subfolders of this folder. This folder will be symlinked into public/_assets/<some hash>.

Read more about assets in Getting started, assets.

Referencing assets

You can reference assets by prefixing the path with EXT:extension_name, for example EXT:my_site_package.

For example the path to the favicon can be configured in TypoScript like this:

page {
    shortcutIcon = EXT:my_site_package/Resources/Public/Icons/favicon.ico
}
Copied!

And a CSS asset can be loaded in Fluid using the Asset.css ViewHelper <f:asset.css> like this:

<f:asset.css identifier="main" href="EXT:my_site_package/Resources/Public/Css/main.css" />
Copied!

Managing asset dependencies in real life projects

It is technically possible to use a CDN (Content Delivery Network) to include libraries in TYPO3. However there are privacy and security risks attached to this and it might be a GDPR Violation. Therefore we recommend to host all files yourself by placing them in the Resources/Public folder.

In a later step, you can use npm (Node Package Manager) to manage your JavaScript and CSS dependencies locally. We also recommend using a JavaScript bundler like Vite.

If you decide to use a frontend bundler, make sure that the resulting asset files are placed in a publicly available folder, like Resources/Public in your site package.

There are also TYPO3 extensions like praetorius/vite-asset-collector to bundle your TYPO3 frontend assets with Vite.

Fluid Templates

To understand the following section you need basic knowledge about how to use the Fluid templating engine and TypoScript.

This chapter is based on the following steps:

After this tutorial you have a better understanding of the example templates and how to adjust them to your needs. You should also be able to create some templates yourself.

If you prefer to start with a pure HTML template and build all templates step by step, you can alternatively have a look a Fluid Templates from the Scratch.

The page view

The Fluid templates for the whole page have to be configured via TypoScript.

In the example site package that was Generated for you the according TypoScript can be found in file packages/my_site_package/Configuration/Sets/SitePackage/TypoScript/page.typoscript:

packages/my_site_package/Configuration/Sets/SitePackage/TypoScript/page.typoscript
page = PAGE
page {
  10 = PAGEVIEW
  10 {
    paths {
      0 = EXT:my_site_package/Resources/Private/PageView/
      10 = {$MySitePackage.template_path}
    }

    dataProcessing {
      # makes content elements available as {content} in Fluid template
      10 = page-content
    }
  }
  shortcutIcon = {$MySitePackage.favicon}
}
Copied!

Line 3 defines that Fluid templates should be used for the page by using the TypoScript object PAGEVIEW.

In line 6 the default path to the page view templates is defined. The definition could be extended in line 7 by a setting later own. For now assume all Fluid templates for the page can be found in folder packages/my_site_package/Resources/Private/PageView.

The default page template

Unless a different page layout is chosen, PAGEVIEW expects the main template of the page in file PageView/Pages/Default.html within the defined folder (packages/my_site_package/Resources/Private/PageView).

Let us have a look at this template now:

packages/my_site_package/Resources/Private/PageView/Pages/Default.html
<f:layout name="PageLayout"/>
<f:section name="Main">

    <f:render partial="Stage" arguments="{_all}"/>

    <div class="container">
        <f:render partial="Content" arguments="{records: content.main.records}"/>
    </div>

</f:section>
Copied!
  • In line 1 the Layout ViewHelper <f:layout> is defined to load a layout template from folder PageView/Layouts. The file must have the same name of the templated, followed by .html, therefore file packages/my_site_package/Resources/Private/PageView/Layouts/PageLayout.html is loaded as layout.
  • Line 2 starts a new section with name "Main", using the Section ViewHelper <f:section>.
  • In Line 4 and 7 partial templates are loaded from Partials. They follow the same naming scheme like the Layout and are therefore located in files Documentation/CodeSnippets/my_site_package/Resources/Private/PageView/Partials/Content.html and Documentation/CodeSnippets/my_site_package/Resources/Private/PageView/Partials/Stage.html. To do this they use the Render ViewHelper <f:render>.

The Fluid layout template

The outer most HTML that is needed for all different page layouts is usually defined in a layout template:

/CodeSnippets/my_site_package/Resources/Private/PageView/Layouts/PageLayout.html
<f:asset.css identifier="bootstrap" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" />
<f:asset.css identifier="main" href="EXT:my_site_package/Resources/Public/Css/main.css" />
<main>
    <f:render partial="Header" arguments="{_all}"/>
    <f:render section="Main"/>
    <f:render partial="Footer" arguments="{_all}"/>
</main>
<f:asset.script identifier="bootstrap" src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" />
<f:asset.script identifier="main" src="EXT:my_site_package/Resources/Public/JavaScript/main.js" />
Copied!

The layout template takes care of loading assets like CSS and JavaScript that are needed on all pages, using the Asset collector.

To configure the asset collector, the Asset.css ViewHelper <f:asset.css> and Asset.script ViewHelper <f:asset.script> are used.

The layout also renders sections that need to be defined with the Section ViewHelper <f:section> in the page template. In line 5 the section is rendered, which is defined in line 2-10 of the "Default" page template. It is possible to define several sections and to define optional sections. We do not demonstrate that here.

The layout template also loads some more partials, for example to display menu and the footer.

Outer most HTML structure (body, head)

The outer most HTML structure is usually not handled by your custom templates. It can be configured via the TypoScript configuration of the PAGE object.

For example you can use option shortcutIcon to load a favicon, meta to define meta tags, or add tags to the body tag using bodyTagAdd.

The page object, including examples is described in detail in the TypoScript reference, chapter Configure the PAGE in TypoScript.

Next steps: Fetch the content and configure the menus

Fluid Templates from the Scratch

Create the Fluid templates

Copy the main static HTML file from Resources/Public/StaticTemplate/default.html to Resources/Private/PageView/Pages/Default.html. You can override the file created in step Minimal site package - The TYPO3 Fluid version. The file name must begin with a capital letter

The template name Default.html is used as a fall back if no other template names are defined. Do not change it for now.

Even though this file ends on .html it will be interpreted by the templating engine Fluid.

TYPO3 takes care of creating the outermost HTML structure of the site, including the <html> and <head> tags therefore they need to be removed from the template:

Resources/Private/PageView/Pages/Default.html (difference)
-<!doctype html>
-<html lang="en" data-bs-theme="auto">
-<head>
-    <meta name="viewport" content="width=device-width, initial-scale=1">
-    <title>TYPO3 site package example</title>
-    <link href="../Libaries/bootstrap-5.3.3-dist/css/bootstrap.min.css" rel="stylesheet">
-    <link href="../Css/main.css" rel="stylesheet">
-</head>
-<body>
 <main>
     ...
 </main>
-<script src="../Libaries/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js"></script>
-<script src="../JavaScript/main.js"></script>
-</body>
-</html>
Copied!

The Fluid template Default.html now contains only the HTML code inside the body:

Resources/Private/PageView/Pages/Default.html
<main>
    <nav class="navbar navbar-expand-lg bg-body-tertiary mb-4">
        <div class="container">
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#menuToggler"
                    aria-controls="menuToggler" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="menuToggler">
                <a href="#" class="navbar-brand">
                    <img src="../Images/logo.svg" alt="Logo" height="50px" class="pe-3">
                    Site name
                </a>

                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item"><a href="#" class="nav-link active" aria-current="page">Home</a></li>
                    <li class="nav-item"><a href="#" class="nav-link">Features</a></li>
                    <li class="nav-item"><a href="#" class="nav-link">Pricing</a></li>
                    <li class="nav-item"><a href="#" class="nav-link">FAQs</a></li>
                    <li class="nav-item"><a href="#" class="nav-link">About</a></li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container">
        <div class="p-5 mb-4 bg-body-tertiary">
            <div class="container-fluid py-5">
                <h1 class="display-5 fw-bold">Custom stage</h1>
                <p class="col-md-8 fs-4">This stage contains a button to demonstrate that JavaScript is working: </p>
                <button class="btn btn-dark btn-lg" role="button" href="#" id="exampleButton">Example button</button>
            </div>
        </div>
    </div>
    <div class="container">
        <h2>Start page content</h2>
        <p>The content of the start page is displayed here. This content should be generated from the content element of the startpage </p>
    </div>
    <div class="container">
        <footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
            <div class="col-md-4 d-flex align-items-center">
                <a href="#" class="mb-3 me-2 mb-md-0 text-body-secondary text-decoration-none lh-1">
                    <img src="../Images/logo.svg" alt="Logo" height="24" class="bi">
                </a>
                <span class="mb-3 mb-md-0 text-body-secondary">&copy; 2024 Site name</span>
            </div>

            <ul class="nav col-md-4 justify-content-end">
                <li class="nav-item"><a href="#" class="nav-link px-2 text-body-secondary">Data privacy</a></li>
                <li class="nav-item"><a href="#" class="nav-link px-2 text-body-secondary">Imprint</a></li>
            </ul>
        </footer>
    </div>
</main>
Copied!

Flush the caches and preview the page. You should now see a pure HTML page without any styles or images. We will add them in a further step.

https://github.com/TYPO3-Documentation/TYPO3CMS-Tutorial-GettingStarted/issues/441 is done.

Load assets (CSS, JavaScript)

Load all CSS which had been removed in step Create the Fluid templates using the Asset.css ViewHelper <f:asset.css>.

Replace <script> tags in the body by using the Asset.script ViewHelper <f:asset.script>.

Resources/Private/PageView/Pages/Default.html (difference)
+ <f:asset.css identifier="bootstrap" href="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/css/bootstrap.min.css" />
+ <f:asset.css identifier="main" href="EXT:my_site_package/Resources/Public/Css/main.css" />
  <main>
      ...
  </main>
- <script src="../Libaries/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js"></script>
- <script src="../JavaScript/main.js"></script>
+ <f:asset.script identifier="bootstrap" src="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js" />
+ <f:asset.script identifier="main" src="EXT:my_site_package/Resources/Public/JavaScript/main.js" />
Copied!

The path to the assets will be resolved by TYPO3. EXT: tells TYPO3 that this is an extension path. my_site_package is the Extension name defined in the composer.json.

Flush all caches and preview the page. .. todo: Link to cache and preview pages in getting started once they exist

When you load your page and inspect it with the developer tools of your browser you will notice that the assets are loaded from paths like /_assets/99a57ea771f379715c522bf185e9a315/Css/main.css?1728057333. You must never try to use these path directly, for example as absolute paths. They can change at any time. Only use the EXT: syntax.

When you now preview the page you will notice that the your page is loaded with the dummy content from the template and functioning CSS and JavaScript. The logo however is not found.

Load images in Fluid

Replace all <img> tags in the template with the Image ViewHelper <f:image>:

Resources/Private/PageView/Pages/Default.html (difference)
-<img src="../Images/logo.svg" alt="Logo" height="50px" class="pe-3">
+<f:image src="EXT:my_site_package/Resources/Public/Images/logo.svg" alt="Logo" class="pe-3" />
Copied!

Just like happened with the CSS paths in step Load assets (CSS, JavaScript) the path to the image is now replaced in the output by a path like /_assets/99a57ea771f379715c522bf185e9a315/Images/logo.svg?1728057333.

Split up the template into partials

If you compare the two static templates Resources/Public/StaticTemplate/default.html and Resources/Public/StaticTemplate/subpagepage.html they share many parts like the footer or the header with the menu. In order to reuse those parts we extract them to their own Fluid files. These are called partials and stored in path Resources/Private/PageView/Partials.

We can use the Render ViewHelper <f:render> to render the partial in the correct place.

Remove the header from the template and replace it with a render ViewHelper:

Resources/Private/PageView/Pages/Default.html (difference)
 <main>
-     <nav class="navbar navbar-expand-lg bg-body-tertiary mb-4">
-        <div class="container">
-            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#menuToggler"
-                    aria-controls="menuToggler" aria-expanded="false" aria-label="Toggle navigation">
-                <span class="navbar-toggler-icon"></span>
-            </button>
-            <div class="collapse navbar-collapse" id="menuToggler">
-                <a href="#" class="navbar-brand">
-                    <img src="../Images/logo.svg" alt="Logo" height="50px" class="pe-3">
-                    Site name
-                </a>
-
-                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
-                    <li class="nav-item"><a href="#" class="nav-link active" aria-current="page">Home</a></li>
-                    <li class="nav-item"><a href="#" class="nav-link">Features</a></li>
-                    <li class="nav-item"><a href="#" class="nav-link">Pricing</a></li>
-                    <li class="nav-item"><a href="#" class="nav-link">FAQs</a></li>
-                    <li class="nav-item"><a href="#" class="nav-link">About</a></li>
-                </ul>
-            </div>
-        </div>
-    </nav>
+    <f:render partial="Header" arguments="{_all}"/>
     ...
 </main>
Copied!

Move the Fluid code you just remove to a file called my-site-package/Resources/Private/PageView/Partials/Header.html.

Do the same with the stage, the breadcrumb, and the footer.

You should now have the following files:

  • packages/my_site_package/Resources/Private/PageView

    • Pages

      • Default.html
      • Subpage.html
    • Partials

      • Footer.html
      • Header.html
      • Stage.html

The Fluid template Resources/Private/PageView/Pages/Default.html should now look like this:

Resources/Private/PageView/Pages/Default.html
<f:asset.css identifier="bootstrap" href="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/css/bootstrap.min.css" />
<f:asset.css identifier="main" href="EXT:my_site_package/Resources/Public/Css/main.css" />
<main>
    <f:render partial="Header" arguments="{_all}"/>
    <f:render partial="Stage" arguments="{records: content.stage.records}"/>
    <div class="container">
        <h2>Start page content</h2>
        <p>The content of the start page is displayed here. This content should be generated from the content element of the startpage </p>
    </div>
    <f:render partial="Footer" arguments="{_all}"/>
</main>
<f:asset.script identifier="bootstrap" src="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js" />
<f:asset.script identifier="main" src="EXT:my_site_package/Resources/Public/JavaScript/main.js" />
Copied!

You will learn how to display the dynamic content in chapter Display the content elements on your page.

Extract the menu into a partial

Partials can also be rendered from within another partial. We move the menu in the partial Resources/Private/PageView/Partials/Header.html to its own partial, Resources/Private/PageView/Partials/Navigation/Menu.html:

packages/my_site_package/Resources/Private/PageView/Partials/Header.html (Difference)
 <nav class="navbar navbar-expand-lg bg-body-tertiary mb-4">
     <div class="container">
         <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#menuToggler"
                 aria-controls="menuToggler" aria-expanded="false" aria-label="Toggle navigation">
             <span class="navbar-toggler-icon"></span>
         </button>
         <div class="collapse navbar-collapse" id="menuToggler">
             <a href="#" class="navbar-brand">
                 <f:image src="{settings.mySitepackage.logo}" alt="{settings.mySitepackage.logo-alt}" class="pe-3" />
                 Site name
             </a>
-            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
-                <li class="nav-item"><a href="#" class="nav-link active" aria-current="page">Home</a></li>
-                <li class="nav-item"><a href="#" class="nav-link">Features</a></li>
-                <li class="nav-item"><a href="#" class="nav-link">Pricing</a></li>
-                <li class="nav-item"><a href="#" class="nav-link">FAQs</a></li>
-                <li class="nav-item"><a href="#" class="nav-link">About</a></li>
-            </ul>
+             <f:render partial="Navigation/Menu.html" arguments="{_all}"/>
         </div>
     </div>
 </nav>
Copied!

The Render ViewHelper <f:render> is used the same like from within the template.

Chapter Main menu will teach you how to make the menu work.

Move the content into a section

You can also move a part of the template into a section, surrounded by a Section ViewHelper <f:section> and use the Render ViewHelper <f:render> with argument section to render it.

We move the content, including the Stage into such a section:

Resources/Private/PageView/Pages/Default.html (difference)
 <f:asset.css identifier="bootstrap" href="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/css/bootstrap.min.css" />
 <f:asset.css identifier="main" href="EXT:my_site_package/Resources/Public/Css/main.css" />
 <main>
     <f:render partial="Header" arguments="{_all}"/>
-    <f:render partial="Stage" arguments="{records: content.stage.records}"/>
-    <div class="container">
-        <h2>Start page content</h2>
-        <p>The content of the start page is displayed here. This content should be generated from the content element of the startpage </p>
-    </div>
+    <f:render section="Main"/>
     <f:render partial="Footer" arguments="{_all}"/>
 </main>
 <f:asset.script identifier="bootstrap" src="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js" />
 <f:asset.script identifier="main" src="EXT:my_site_package/Resources/Public/JavaScript/main.js" />

+<f:section name="Main">
+    <f:render partial="Stage" arguments="{_all}"/>
+    <div class="container">
+        <h2>Start page content</h2>
+        <p>The content of the start page is displayed here. This content should be generated from the content element of the startpage </p>
+    </div>
+</f:section>
Copied!

The result looks like this:

Resources/Private/PageView/Pages/Default.html
<f:asset.css identifier="bootstrap" href="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/css/bootstrap.min.css" />
<f:asset.css identifier="main" href="EXT:my_site_package/Resources/Public/Css/main.css" />
<main>
    <f:render partial="Header" arguments="{_all}"/>
    <f:render section="Main"/>
    <f:render partial="Footer" arguments="{_all}"/>
</main>
<f:asset.script identifier="bootstrap" src="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js" />
<f:asset.script identifier="main" src="EXT:my_site_package/Resources/Public/JavaScript/main.js" />

<f:section name="Main">
    <f:render partial="Stage" arguments="{records: content.stage.records}"/>
    <div class="container">
        <h2>Start page content</h2>
        <p>The content of the start page is displayed here. This content should be generated from the content element of the startpage </p>
    </div>
</f:section>
Copied!

You will learn how to display the dynamic content in chapter Display the content elements on your page.

The Fluid template for the subpage

We can repeat the above steps for the subpage and write such a template:

Resources/Private/PageView/Pages/Subpage.html
<f:asset.css identifier="bootstrap" href="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/css/bootstrap.min.css" />
<f:asset.css identifier="main" href="EXT:my_site_package/Resources/Public/Css/main.css" />
<main>
    <f:render partial="Header" arguments="{_all}"/>
    <f:render section="Main"/>
    <f:render partial="Footer" arguments="{_all}"/>
</main>
<f:asset.script identifier="bootstrap" src="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js" />
<f:asset.script identifier="main" src="EXT:my_site_package/Resources/Public/JavaScript/main.js" />

<f:section name="Main">
    <f:render partial="Stage" arguments="{_all}"/>
    <f:render partial="Navigation/Breadcrumb" arguments="{_all}"/>
    <div class="container">
        <div class="row">
            <div class="col-md-8">
                <h2>Main page content (2/3)</h2>
                <p>The main content of each page can be displayed here.</p>
            </div>
            <div class="col-md-4">
                <h2>Sidebar page content (1/3)</h2>
                <p>The sidebar content of each page can be displayed here. </p>
            </div>
        </div>
    </div>
</f:section>
Copied!

Extract the breadcrumb into a partial

The subpage template contain a breadcrumb, between stage and content, that you can also move to a partial.

The breadcrum partial looks like this:

Resources/Private/PageView/Partials/Navigation/Breadcrumb.html
<div class="container">
    <nav aria-label="breadcrumb">
        <ol class="breadcrumb breadcrumb-chevron p-3 bg-body-tertiary">
            <li class="breadcrumb-item">
                <a class="link-body-emphasis fw-semibold text-decoration-none" href="#">Home</a>
            </li>
            <li class="breadcrumb-item">
                <a class="link-body-emphasis fw-semibold text-decoration-none" href="#">Library</a>
            </li>
            <li class="breadcrumb-item active" aria-current="page">
                Data
            </li>
        </ol>
    </nav>
</div>
Copied!

Extract the repeated part to a layout

Lines 1-9 of file Subpage.html in step The Fluid template for the subpage step are exactly the same like in file Resources/Private/PageView/Pages/Default.html.

We can extract these lines into a so called Fluid layout and load them with the Layout ViewHelper <f:layout>:

Resources/Private/PageView/Pages/Subpage.html (difference)
-<f:asset.css identifier="bootstrap" href="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/css/bootstrap.min.css" />
-<f:asset.css identifier="main" href="EXT:my_site_package/Resources/Public/Css/main.css" />
-<main>
-    <f:render partial="Header" arguments="{_all}"/>
-    <f:render section="Main"/>
-    <f:render partial="Footer" arguments="{_all}"/>
-</main>
-<f:asset.script identifier="bootstrap" src="EXT:my_site_package/Resources/Public/Libaries/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js" />
-<f:asset.script identifier="main" src="EXT:my_site_package/Resources/Public/JavaScript/main.js" />
+<f:layout name="Layout"/>
 <f:section name="Main">
     ...
 </f:section>
Copied!

Save the extracted layout to a file called Resources/Private/PageView/Layouts/Layout.html. This file now contains the following:

packages/my_site_package/Resources/Private/PageView/Layouts/PageLayout.html
<f:asset.css identifier="bootstrap" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" />
<f:asset.css identifier="main" href="EXT:my_site_package/Resources/Public/Css/main.css" />
<main>
    <f:render partial="Header" arguments="{_all}"/>
    <f:render section="Main"/>
    <f:render partial="Footer" arguments="{_all}"/>
</main>
<f:asset.script identifier="bootstrap" src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" />
<f:asset.script identifier="main" src="EXT:my_site_package/Resources/Public/JavaScript/main.js" />
Copied!

Repeat the same for file Resources/Private/PageView/Pages/Default.html.

  • packages/my_site_package/Resources/Private/PageView

    • Layouts

      • Layout.html
    • Pages

      • Default.html
      • Subpage.html
    • Partials

      • Navigation

        • Breadcrumb.html
        • FooterMenu.html
        • Menu.html
      • Footer.html
      • Header.html
      • Stage.html

You can use the Site Package Builder to create a customized site package. If you want to follow this tutorial, choose "Site Package Tutorial" as base package.

Display the content elements on your page

In step Move the content into a section we moved the part of our template, that will contain the content, into its own section. This section is however still filled with dummy content:

Resources/Private/PageView/Pages/Default.html
<f:layout name="Layout"/>
<f:section name="Main">
    <f:render partial="Stage" arguments="{_all}"/>
    <div class="container">
        <h2>Start page content</h2>
        <p>The content of the start page is displayed here. [...] </p>
    </div>
</f:section>
Copied!

Include the site sets of fluid-styled-content as dependency

In step Minimal site package - Create a basic site set we created a basic site set for our site package.

Add a dependency to the sets provided by the system extension typo3/cms-fluid-styled-content . This step is a prerequisite to display the content in the next steps.

Your site set configuration should now look like this:

packages/my_site_package/Configuration/Sets/SitePackage/config.yaml
name: my-vendor/my-site-package
label: 'My Site Package'
dependencies:
  - typo3/fluid-styled-content
  - typo3/fluid-styled-content-css
Copied!

Create a default page layout with page TSconfig

In order to map the content from the backend to the frontend we create a new file Configuration/Sets/SitePackage/page.tsconfig containing page TSconfig.

By placing the file within the site set, you created in step Create a basic site set, the newly created file is loaded within the page tree of your site automatically:

packages/my_site_package/Configuration/Sets/SitePackage/page.tsconfig
@import './PageTsConfig/'
@import './PageTsConfig/BackendLayouts/'

Copied!

This file automatically includes all .tsconfig files from the designated folder in which we will store the page layouts.

We now create a default page layout with two areas: One for the main content and one for the stage.

packages/my_site_package/Configuration/TsConfig/Page/PageLayout/Default.tsconfig
mod.web_layout.BackendLayouts {
  Default {
    title = Standard
    icon = EXT:my_site_package/Resources/Public/Icons/BackendLayouts/default.svg
    config {
      backend_layout {
        colCount = 1
        rowCount = 3
        rows {
          1 {
            columns {
              1 {
                name = Stage
                colPos = 1
                identifier = stage
                slideMode = slide
              }
            }
          }

          2 {
            columns {
              1 {
                name = Main Content
                colPos = 0
                identifier = main
              }
            }
          }
        }
      }
    }
  }
}
Copied!

Changed in version TYPO3 13

Each area in the page layout becomes an identifier that can be used during content mapping. If no content element is added in the backend of that page and the slide mode is activated, content from the parent page is displayed. This is useful for design elements like side bars, jumbotrons or banners that should be the same for a page and its subpage. You can find all details of the Page / backend layouts in the TSconfig reference.

When you make changes to the files of an extension it is usually necessary to flush all caches by hitting the button.

Flush all caches

After flushing the all caches the new backend layout is available in the page properties at Appearance > Page Layout > Backend Layout.

Choose the backend layout

Choose the page layout in the page properties

Switch to the new backend layout and save the page properties. In the Page module you will see two areas called "Stage" and "Main Content" now.

If you followed step Load the example data automatically the areas "Stage" and "Main" should already contain some example content.

Create new content element

In the database each content element record is stored in the table tt_content. This table has a column called colPos. If the value stored in column colPos is the same as defined in the page layout in page TSconfig the content element is displayed in the according area of the page layout.

It is considered best practice to store the main content in an area with colPos=0. This makes switching between different layouts easier.

Content rendering via page-content data processor

New in version TYPO3 13

The TypoScript object PAGEVIEW, that we defined in step Fluid version of the minimal site package enables us to introduce a data processor to facilitate content mapping.

Edit the TypoScript configuration of the PAGEVIEW object to define a data processor of type page-content:

Configuration/Sets/SitePackage/setup.typoscript (diff)
 page {
   10 {
     paths {
       100 = EXT:my_site_package/Resources/Private/PageView/
     }

+    dataProcessing {
+      # makes content elements available as {content} in Fluid template
+      10 = page-content
+    }
   }
 }
Copied!

This data processor provides the variable content to your Fluid template.

You can debug this variable in the main section of your template using the Debug ViewHelper <f:debug>:

Resources/Private/PageView/Pages/Default.html
 <f:layout name="Layout"/>
 <f:section name="Main">
     <f:render partial="Stage" arguments="{_all}"/>
+    <f:debug>{content}</f:debug>
     <div class="container">
         <h2>Start page content</h2>
         <p>The content of the start page is displayed here. [...] </p>
     </div>
 </f:section>
Copied!

The debug output after clearing all caches and previewing the page should look like this:

Screenshot of the debug output of {content}

The debug output should contain sections "stage" and "main"

TypoScript mapping in Fluid template

Open the file Resources/Private/PageView/Page/Default.html and locate the main content area. It contains a headline (look for the <h2>-tags) and some dummy content (look for the <p>-tags).

Replace these lines with a Fluid for-loop, rendering each content element using the CObject ViewHelper <f:cObject>:

Resources/Private/PageView/Pages/Default.html (diff)
 <f:layout name="Layout"/>
 <f:section name="Main">
     <f:render partial="Stage" arguments="{_all}"/>
-    <f:debug>{content}</f:debug>
         <div class="container">
-            <h2>Start page content</h2>
-            <p>The content of the start page is displayed here. [...] </p>
+            <f:for each="{content.main.records}" as="record">
+                <f:cObject
+                     typoscriptObjectPath="{record.mainType}"
+                     data="{record.rawRecord}"
+                     table="{record.mainType}"
+                  />
+            </f:for>
         </div>
 </f:section>
Copied!

For content elements the main type is always tt_content. Therefore we include the TypoScript object tt_content here. It is defined in the TypoScript of the system extension typo3/cms-fluid-styled-content . We included the site set of that extension in step Include the site sets of fluid-styled-content as dependency.

fluid-styled-content internally uses Fluid templates and TypoScript with data processors just like the ones we were defining above. If you desire to change the output of these content elements you could override the Fluid templates of the extension typo3/cms-fluid-styled-content .

Extract the content element rendering to a partial

As we want to reuse the Fluid part about rendering content elements in the next steps, we extract it into a partial, like we did with the menu in step Extract the menu into a partial.

We want to be able to render content elements of any content area. Therefore pass the records of the page layout area to be rendered as variable records to the partial:

Resources/Private/PageView/Pages/Default.html (diff)
 <f:layout name="Layout"/>
 <f:section name="Main">
     <f:render partial="Stage" arguments="{_all}"/>
     <div class="container">
-        <f:for each="{content.main.records}" as="record">...</f:for>
+        <f:render partial="Content" arguments="{records: content.main.records}"/>
     </div>
 </f:section>
Copied!

The partial then looks like this:

packages/my_site_package/Resources/Private/PageView/Partials/Content.html
<f:for each="{records}" as="record">
    <f:cObject
        typoscriptObjectPath="{record.mainType}"
        data="{record}"
        table="{record.mainType}"
    />
</f:for>
Copied!

Splitting up the TypoScript into files

At this point the file packages/my_site_package/Configuration/Sets/SitePackage/setup.typoscript has started to have several lines. When we start rendering the Menues, make more sophisticated Settings etc the TypoScript configuration file is going to grow more. We therefore suggest, to use TypoScript imports and structure your TypoScript in different files that are then combined at this point.

The rest of the Tutorial will assume that your files are in the directory packages/my_site_package/Configuration/Sets/SitePackage/TypoScript/ and imported as described in TypoScript imports.

Next steps

TypoScript imports

In step Minimal site package - The TYPO3 Fluid version we placed all TypoScript into the site set, file packages/site-package/Configuration/Sets/SitePackage/setup.typoscript.

In the following chapters we will need additional TypoScript setup configurations.

Theoretically you could put all TypoScript into one big file and it would work fine. But you have better overview if you split it up in multiple files ordered by purpose.

Familiarize yourself with the TypoScript @import syntax first: TYPO3 Explained, @import syntax.

Import the TypoScript from a different location

Create a new folder called Configuration/Sets/SitePackage/TypoScript. In this create a file called page.typoscript and copy the content from file Configuration/Sets/SitePackage/setup.typoscript into it.

Then change the latter file to contain the following:

Configuration/Sets/SitePackage/setup.typoscript
@import './TypoScript/page.typoscript'
Copied!

Flush the caches and preview the page. The output should be unchanged.

Import all TypoScript files from a folder using a wildcard

We will create more TypoScript files in the next steps. We could import them file by file. But as the order will not matter we can import all of them via wildcard:

packages/my_site_package/Configuration/Sets/SitePackage/setup.typoscript
@import './TypoScript/*.typoscript'
@import './TypoScript/Navigation/*.typoscript'
Copied!

Only files from the folder directly will be imported. If you create subfolders later on you have to import them separately.

Structure of the Configuration directory

Your Configuration directory should now have the following structure:

  • packages/my_site_package/Configuration

    • Sets

      • SitePackage

        • TypoScript

          • page.typoscript
        • config.yaml
        • setup.typoscript

In the next steps you will create more TypoScript files to configure the Content mapping and the menus.

The Stage: Fall back to content of parent page (sliding)

Page Layout with slide mode

The page layout contains a definition for the stage area in lines 10-19:

packages/my_site_package/Configuration/Sets/SitePackage/PageTsConfig/BackendLayouts/default.tsconfig
mod.web_layout.BackendLayouts {
  Default {
    title = Standard
    icon = EXT:my_site_package/Resources/Public/Icons/BackendLayouts/default.svg
    config {
      backend_layout {
        colCount = 1
        rowCount = 3
        rows {
          1 {
            columns {
              1 {
                name = Stage
                colPos = 1
                identifier = stage
                slideMode = slide
              }
            }
          }

          2 {
            columns {
              1 {
                name = Main Content
                colPos = 0
                identifier = main
              }
            }
          }
        }
      }
    }
  }
}
Copied!

The definition is similar to the one we have seen for the main content area in section Create a default page layout with page TSconfig.

There are some key differences:

  • The stage has the colPos 1, therefore all content elements in the stage area will automatically have a 1 instead of a 0 in field "Column" / database column colPos.
  • The identifier is stage therefore the content of the content area is available as variable {content.stage.records} in the partial template.
  • The slideMode is set to slide therefore if no content is found in the content area on the current page, TYPO3 will look one page up etc until content is found or the page root is reached.

Using a content area with slide mode

The content elements will be automatically found and provided to your template. Therefore the template for the area "Stage" looks no different from the one for the main area except that is uses the corresponding variable of course:

packages/my_site_package/Resources/Private/PageView/Partials/Stage.html
<f:for each="{content.stage.records}" as="record">
    <div class="container">
        <f:cObject
            typoscriptObjectPath="{record.mainType}"
            data="{record}"
            table="{record.mainType}"
        />
    </div>
</f:for>
Copied!

Additional subpage layout

Edit the file packages/my-site-package/Resources/Private/PageView/Pages/Subpage.html.

Exchange the main content area just as we have done before with the default template. Now replace the content area of the sidebar with the content elements in the Fluid variable {sidebarContent}.

Resources/Private/PageView/Pages/Subpage.html (diff)
<f:layout name="Layout"/>
<f:section name="Main">
    <f:render partial="Stage" arguments="{_all}"/>
    <f:render partial="Navigation/Breadcrumb" arguments="{_all}"/>
    <div class="container">
        <div class="row">
            <div class="col-md-8">
-                <div class="h-100 p-5 text-bg-white">
-                    <h2>Page content</h2>
-                    <p>The content of each page can be displayed here. </p>
-                </div>
+                <f:render partial="Content" arguments="{records: content.main.records}"/>
            </div>
            <div class="col-md-4">
-                <div class="h-100 p-5 bg-body-tertiary">
-                    <h2>Sidebar </h2>
-                    <p>Place for some shared content</p>
-                </div>
+                 <f:render partial="Content" arguments="{records: content.sidebar.records}"/>
            </div>
        </div>
    </div>
</f:section>
Copied!

Create a subpage page layout with page TSconfig

We now create a subpage layout with two columns and a row for the stage in a new file packages/my-site-package/Configuration/TsConfig/Page/PageLayout/Subpage.tsconfig containing page TSconfig. :

packages/my_site_package/Configuration/Sets/SitePackage/PageTsConfig/BackendLayouts/subpage.tsconfig
#
# BACKENDLAYOUT: EXAMPLE
#
mod {
    web_layout {
        BackendLayouts {
            subpage {
                title = LLL:EXT:my_site_package/Resources/Private/Language/locallang_be.xlf:backend_layout.subpage
                config {
                    backend_layout {
                        colCount = 2
                        rowCount = 2
                        rows {
                            1 {
                                columns {
                                    1 {
                                        name = LLL:EXT:my_site_package/Resources/Private/Language/locallang_be.xlf:backend_layout.column.stage
                                        colPos = 1
                                        colspan = 2
                                        identifier = stage
                                        slideMode = slide
                                    }
                                }
                            }
                            2 {
                                columns {
                                    1 {
                                        name = LLL:EXT:my_site_package/Resources/Private/Language/locallang_be.xlf:backend_layout.column.normal
                                        colPos = 0
                                        identifier = main
                                    }
                                    2 {
                                        name = LLL:EXT:my_site_package/Resources/Private/Language/locallang_be.xlf:backend_layout.column.right
                                        colPos = 2
                                        identifier = sidebar
                                        slideMode = collectReverse
                                    }
                                }
                            }
                        }
                    }
                }
                icon = EXT:my_site_package/Resources/Public/Icons/BackendLayouts/subpage.svg
            }
        }
    }
}
Copied!

Switch to the two column layout with a sidebar for subpages

You can now use the Two Column backend layout for the Start page subpages at Appearance > Page Layout > Backend Layout. Edit the page properties of Start page to use the backend layout "Two Columns" for subpages.

Switch to the Backend Layout "Two Columns" for subpages

Switch to the Backend Layout "Two Columns" for subpages

After saving you will be able to see on "Page 1" that the content of the columns "main" and "stage" remains unchanged while there is a third column "sidebar". This is due to the fact that the backend layout "Default" and "TwoColumns" use the same colPos number for these columns.

The pages generated in step Create initial pages already contain "Menu of subpages" an example content in "sidebar" column.

A new column "Sidebar" appears

A new column "Sidebar" appears

Preview the page once more. A sidebar will appear in the frontend:

The sidebar appears in the frontend

The sidebar appears in the frontend

Add content in the TYPO3 backend

The pages generated in step Create initial pages already contain some example content.

You can add additonal content in the backend. Go to Web > Page and select any of the pages you created before, (for example "Page 2"). Click the + Create new content button in the column labelled "Main" and choose the "Regular Text Element" content element.

Create new content element

Create new content element

Choose "Regular Text Element"

Choose "Regular Text Element"

Enter a headline and some arbitrary text in the Rich Text Editor (RTE).

Enter a headline

Enter a headline

Enter some arbitrary text in the Rich Text Editor (RTE)

Enter some arbitrary text in the Rich Text Editor (RTE)

Save your changes by clicking button Save at the top. You can return to the previous view by clicking Close.

Save and close the new content element

Save and close the new content element

Preview the page by clicking button View webpage.

View webpage button

View webpage button

Check that the content is displayed as expected.

Verify if your new content is displayed on the page

Verify if your new content is displayed on the page

Whenever you edit the content elements on a page the cache of the current page is automatically deleted. If the content fails to update you should still delete the TYPO3 caches and force your browser to reload.

There are many tips and tricks around content editing. The topic is described in more depth in chapter Content Elements of the Editors Tutorial.

Rendering menus in TYPO3

There are several strategies to display menus or other navigation elements like breadcrumbs and sitemaps in TYPO3.

TypoScrip configuration of the main menu

We use TypoScript to configure these menus. The main menu is configured like this:

packages/my_site_package/Configuration/Sets/SitePackage/TypoScript/Navigation/menu.typoscript
page {
  10 {
    dataProcessing {
      20 = menu
    }
  }
}
Copied!

This menu defines that the variable with the default name menu should contain the information about the complete page tree of the current page.

System folders like the "Footer menu" from your example data, special page types and pages excluded from the navigation are excluded.

A complete reference of this menu can be found in the TypoScript Reference: menu data processor.

Fluid partial of the main menu

In packages/my_site_package/Resources/Private/PageView/Partials/Navigation/Menu.html you can find the partial that renders the main menu.

A menu usually contains several menu entries. We use the For ViewHelper <f:for> to iterate over all menu entries and render them in turn:

packages/my_site_package/Resources/Private/PageView/Partials/Navigation/Menu.html
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
    <f:for each="{menu}" as="menuItem">
        <li class="nav-item">
            <a class="nav-link {f:if(condition: menuItem.active, then:'active')}"
               href="{menuItem.link}"
               target="{menuItem.target}"
               title="{menuItem.title}"
            >
                {menuItem.title}
            </a>
        </li>
    </f:for>
</ul>
Copied!

In each loop the current menu item is stored in variable {menuItem}.

You can use the Debug ViewHelper <f:debug> to debug what kind of data the variable contains like this:

packages/my_site_package/Resources/Private/PageView/Partials/Navigation/Menu.html (changed for debug output)
<ul class="navbar-nav mr-auto">
    <f:for each="{menu}" as="menuItem">
+       <f:debug>{menuItem}</f:debug>
        <li class="nav-item {f:if(condition: menuItem.active, then:'active')}">
Copied!

The debug output on your page should now look like this:

array(8 items)
    data => array(78 items)
    title => 'My page' (22 chars)
    link => '/my-page' (26 chars)
    target => '' (0 chars)
    active => 0 (integer)
    current => 0 (integer)
    spacer => 0 (integer)
    hasSubpages => 1 (integer)
Copied!

The following data is of interest:

{menuItem.data}:
Contains the raw data of the database record of the page for the menu item.
{menuItem.link}:
The actual link to the page. For external links it contains the URL.
{menuItem.target}:
This might contain "_blank" if the menu item represents an external link.
{menuItem.title}:
The title to be displayed in the menu. By default the navigation title if set, the title otherwise.
{menuItem.active}
Contains 1 if the page of the current menu item is in the rootline of the current page.

The construct {f:if(condition: menuItem.active, then: 'active')} output the string "active" if {menuItem.active} is set. The syntax might look confusing at first. It is an If ViewHelper <f:if> displayed in the Fluid inline notation.

Preview the page and use the menu

Whenever you change TypoScript files or Fluid templates, flush all caches:

ddev typo3 cache:flush
Copied!
Checking from the backend if the menu is generated as expected.

Checking from the backend if the menu is generated as expected.

Different menu types

We use the menu data processor to demonstrate different menu types:

  • A breadcrumb configured in packages/my_site_package/Configuration/Sets/SitePackage/TypoScript/Navigation/breadcrumb.typoscript and rendered in packages/my_site_package/Resources/Private/PageView/Partials/Navigation/Breadcrumb.html.
  • A footer menu consisting of pages within a selected folder configured in packages/my_site_package/Configuration/Sets/SitePackage/TypoScript/Navigation/footerMenu.typoscript and rendered in packages/my_site_package/Resources/Private/PageView/Partials/Navigation/FooterMenu.html.

Site settings: Further configuration options

New in version 13.1

Site sets and settings therein have been introduced with TYPO3 13.1.

In step Minimal site package - Create a basic site set we created a basic site set for our site package.

The site set

Changed in version 13.1

In TYPO3 v13.1 and above the TypoScript files are made available as sets and included in the site. For TYPO3 v12 read the section in the tutorial for TYPO3 v12.4: Make TypoScript available (TYPO3 v12.4).

In step Create a basic site set we already created a basic site set for your site package.

In step Include the site sets of fluid-styled-content as dependency we included the dependencies to the site sets of typo3/cms-fluid-styled-content .

Your site set configuration should now look like this:

packages/my_site_package/Configuration/Sets/SitePackage/config.yaml
name: my-vendor/my-site-package
label: 'My Site Package'
dependencies:
  - typo3/fluid-styled-content
  - typo3/fluid-styled-content-css
Copied!

Line 1 defines the name of the set. As the example site-package extension only provides one set, the name of the set should be the same as the composer name.

In line 4 and 5 dependencies are defined. In this example the site package depends on typo3/cms-fluid-styled-content , therefore the sets provided by this system extension are included as dependency. By doing so all settings and TypoScript definitions provided by the extension are automatically included.

Your site set folder now contains the following files:

  • my_site_package/Configuration/Sets/SitePackage

    • config.yaml
    • page.tsconfig
    • setup.typoscript

Introduce site settings to configure fluid-styled-content

Place a file called settings.yaml in the folder Configuration/Sets/SitePackage.

We override some default settings of the site set Site set "Fluid Styled Content":

packages/my_site_package/Configuration/Sets/SitePackage/settings.yaml
styles:
    templates:
        layoutRootPath: EXT:my_site_package/Resources/Private/ContentElements/Layouts
        partialRootPath: EXT:my_site_package/Resources/Private/ContentElements/Partials
        templateRootPath: EXT:my_site_package/Resources/Private/ContentElements/Templates
    content:
        textmedia:
            maxW: 1200
            maxWInText: 600
            linkWrap:
                lightboxEnabled: true
                lightboxCssClass: lightbox
Copied!

Here we override some values for maximal image width in text-media content elements, we enable a lightbox for images and set paths for overriding the templates of that extension.

Settings can also be used in conditions: Check if a setting/constant is set to a certain value.

How to use settings as variables in templates

Certain information is used in different parts of the templates over and over again like the uid of the data privacy page or the contact e-mail address.

You can keep central information in settings. They can then be adjusted as needed in the Site Management > Settings module in the backend by administrators.

Setting definition

Settings definitions are used to set values that can be used in the TypoScript setup throughout the project.

They are stored in the file settings.definitions.yaml in your site set.

The settings can be displayed and adjusted in module Site Management > Settings:

Screenshot of module "Site Management > Settings" with the settings of the example site package open

Administrators can view and adjust settings and save them here.

If administrators change settings here, they get saved to config/sites/my-site/settings.yaml so this path and file have to be writable for TYPO3. If the file is not writable for example when you have it under version control, administrators can als export the settings and download them.

Let us have a look at the example generated by the Site Package Builder:

packages/my_site_package/Configuration/Sets/SitePackage/settings.definitions.yaml
categories:
  MySitePackage:
    label: 'My Site Package'
  MySitePackage.templates:
    label: 'Templates'
    parent: MySitePackage
  MySitePackage.layout:
    label: 'Layout'
    parent: MySitePackage
  MySitePackage.menus:
    label: 'Menus'
    parent: MySitePackage

settings:
  MySitePackage.template_path:
    label: 'Page template path'
    category: MySitePackage.templates
    description: 'Path to the templates of the My Site Package.'
    type: string
    default: 'EXT:my_site_package/Resources/Private/Templates/'

  MySitePackage.logo:
    label: 'Logo'
    category: MySitePackage.layout
    description: 'Path to the logo of My Site Package.'
    type: string
    default: 'EXT:my_site_package/Resources/Public/Images/logo.svg'

  MySitePackage.logo-alt:
    label: 'Logo Alt text'
    category: MySitePackage.layout
    description: 'Alternative text of the logo for the visually impaired'
    type: string
    default: 'Logo'

  MySitePackage.favicon:
    label: 'Favicon'
    description: 'This icon is displayed in search engine results and in the browser tab'
    category: MySitePackage.layout
    type: string
    default: 'EXT:my_site_package/Resources/Public/Icons/favicon.ico'

  MySitePackage.footerMenuRoot:
      label: 'Footer menu root uid'
      description: 'The subpages of this page are displayed in the footer'
      category: MySitePackage.menus
      type: int
      default: 2
Copied!

Settings can be assigned to categories so that they are easier to find for administrators. These categories are defined in lines 1-12.

Let us now have a look at the definition of a setting entry in detail:

packages/my_site_package/Configuration/Sets/SitePackage/settings.definitions.yaml (excerpt)
MySitePackage.footerMenuRoot:
  label: 'Footer menu root uid'
  description: 'The subpages of this page are displayed in the footer'
  category: MySitePackage.menus
  type: int
  default: 2
Copied!

Line 1 defines the identifier of the settings. Identifiers are available globally within the complete project and installed extensions might define some. Use a unique prefix therefore. Here we use MySitePackage.. We used the same prefix for the categories. This is suggested but not mandatory in a site package.

Line 2-3 define labels to be displayed in the backend module.

Line 4 sets the category.

Line 5 sets the type. See all available types here: Site setting definition types.

Line 6 defines a default. If you define a default its type in YAML has to match the type defined in line 5.

All properties that can be defined for setting definitions can be found here: Site setting definition properties.

Using setting entries in a Fluid template

The site settings are available as variable {settings} (see settings) within the templates of the page as we are using the PAGEVIEW TypoScript object.

In the site package example we display the logo once in the header in large and once in the footer in smaller and use the settings to determine the path and alt text in both cases:

packages/my_site_package/Resources/Private/PageView/Partials/Footer.html
<div class="container">
    <footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
        <div class="col-md-4 d-flex align-items-center">

            <f:link.page pageUid="{site.rootPageId}" class="mb-3 me-2 mb-md-0 text-body-secondary text-decoration-none lh-1">
                <f:image src="{settings.MySitePackage.logo}" alt="{settings.MySitePackage.logo-alt}" height="24" class="bi" />
            </f:link.page>
            <span class="mb-3 mb-md-0 text-body-secondary">&copy; <f:format.date format="Y">now</f:format.date> {site.configuration.websiteTitle}</span>
        </div>

        <f:render partial="Navigation/FooterMenu.html" arguments="{_all}"/>
    </footer>
</div>
Copied!

At the time of writing the settings are not available out-of-the-box in templates configured by FLUIDTEMPLATE objects, for example in custom content element templates or within Custom Content Blocks. You would have to supply them with a Custom data processor.

Using settings in TypoScript

In both frontend TypoScript and backend TypoScript, also called TSconfig, the settings can be used with the TypoScript constants syntax.

In the site package example we use constants to configure the path to the favicon and templates (both of type string):

packages/my_site_package/Configuration/Sets/SitePackage/TypoScript/page.typoscript
page = PAGE
page {
  10 = PAGEVIEW
  10 {
    paths {
      0 = EXT:my_site_package/Resources/Private/PageView/
      10 = {$MySitePackage.template_path}
    }

    dataProcessing {
      # makes content elements available as {content} in Fluid template
      10 = page-content
    }
  }
  shortcutIcon = {$MySitePackage.favicon}
}
Copied!

And in the footer menu we use a setting of type int to set the root folder in which the pages for the footer menu are found:

packages/my_site_package/Configuration/Sets/SitePackage/TypoScript/Navigation/footerMenu.typoscript
page {
    10 {
        dataProcessing {
            40 = menu
            40 {
                as = footerMenu
                special = directory
                special.value = {$MySitePackage.footerMenuRoot}
            }
        }
    }
}
Copied!

It is also possible to use settings in TypoScript conditions: Check if a setting/constant is set to a certain value.

Overriding the default templates of content elements

The content elements that are rendered up to this point are rendered by the TYPO3 system extension Fluid Styled Content ( typo3/cms-fluid-styled-content ).

This extensions offers default templates to render content elements. Without such an extension, no content would be rendered at all. The default templates provided by this extension can be overridden with site settings provided by Fluid Styled Content.

Your site package, if generated by the Site Package Builder already overrides two templates from Fluid Styled Content and you are free to override additional ones.

Use Settings to override template paths of Fluid Styled Content

Your site package already configures the paths to override the templates of Fluid Styled Content content elements in file packages/site_package/Configuration/Sets/SitePackage/settings.yaml:

packages/my_site_package/Configuration/Sets/SitePackage/settings.yaml
styles:
    templates:
        layoutRootPath: EXT:my_site_package/Resources/Private/ContentElements/Layouts
        partialRootPath: EXT:my_site_package/Resources/Private/ContentElements/Partials
        templateRootPath: EXT:my_site_package/Resources/Private/ContentElements/Templates
    content:
        textmedia:
            maxW: 1200
            maxWInText: 600
            linkWrap:
                lightboxEnabled: true
                lightboxCssClass: lightbox
Copied!

If you wanted to create this file yourself you could do it as follows:

Site settings can be saved both in the site configuration and in the site package extension.

We will save the settings to the site package but use the settings editor to write the YAML for us.

Go to module Site Management > Settings and edit the settings of your site. Override the paths to the templates of Fluid Styled Content like this:

Screenshot demonstrating the site settings module

Override the templates of Fluid Styled Content

If you would click Save now, the settings would be saved to your site configuration at config/sites/my-site/settings.yaml. We however want to save the settings to the site set of our site package extension.

Click the button YAML export to copy the configuration to your Clipboard instead, then save it to the following file:

packages/my_site_package/Configuration/Sets/SitePackage/settings.yaml
styles:
  templates:
    templateRootPath: 'EXT:my_site_package/Resources/Private/ContentElements/Templates'
    partialRootPath: 'EXT:my_site_package/Resources/Private/ContentElements/Partials'
    layoutRootPath: 'EXT:my_site_package/Resources/Private/ContentElements/Layouts'
Copied!

Override the "Menu of Subpages" template

Your site package already overrides the template MenuSubpages of Fluid Styled Content in file packages/my_site_package/Resources/Private/ContentElements/Templates/MenuSubpages.html.

If you wanted to create this Template manually you could do it like this:

On "Page 1" of the example data a content element of type "Subpages" was added. We now have to find out what this type is called in the database. The raw values saved to the database are displayed in the TYPO3 backend when the debug mode is activated:

Screenshot demonstrating the backend debug mode for Content element "Subpages" on "Page 1"

You can now see that the Type (saved in field CType) is stored as menu_subpages

Now we must find and copy the original template from Fluid Styled Content. TYPO3 extensions are saved by their composer key, here typo3/cms-fluid-styled-content , into the folder vendor during installation via Composer. You can find the files belonging to Fluid Styled Content in folder vendor/typo3/cms-fluid-styled-content therefore. This folder is structured similarly to your site package extension and you can find the original templates in folder Resources/Private/PageView here.

By convention the templates of Fluid Styled Content have the name of the CType in CamelCase. Copy file vendor/typo3/cms-fluid-styled-content/Resources/Private/Templates/MenuSubpages.html into folder packages/my_site_package/Resources/Private/ContentElements/Templates/MenuSubpages.html

Edit the file to add some classes as used in menus in Bootstrap, for example like this:

packages/my_site_package/Resources/Private/ContentElements/Templates/MenuSubpages.html
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:layout name="Default" />
<f:section name="Main">

    <f:if condition="{menu}">
        <ul class="nav flex-column">
            <f:for each="{menu}" as="page">
                <li class="nav-item">
                    <a href="{page.link}" class="nav-link{f:if(condition: 'page.active', then: ' active')}">
                        <span>{page.title}</span>
                    </a>
                </li>
            </f:for>
        </ul>
    </f:if>

</f:section>
</html>
Copied!

In most parts the changes we made are pretty straight forward. In line 9 we use the Fluid inline notation of the If ViewHelper <f:if> to only output class active if the page in the menu is in the root line.

Override the sitemap template

In a similar fashion we now copy and adjust the template for the sitemap from vendor/typo3/cms-fluid-styled-content/Resources/Private/Templates/MenuSitemap.html into folder packages/site_package/Resources/Private/ContentElements/Templates/MenuSitemap.html and then adjust it:

packages/my_site_package/Resources/Private/ContentElements/Templates/MenuSitemap.html
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:layout name="Default" />
<f:section name="Main">

    <f:render section="Menu" arguments="{menu: menu, level: 1}" />

</f:section>
<f:section name="Menu">

    <f:if condition="{menu}">
        <ul class="list-group ps-4 mt-2">
            <f:for each="{menu}" as="page">
                <li class="list-group-item">
                    <a href="{page.link}" class="text-decoration-none text-dark level-{level}{f:if(condition: '{level} < 2', then: ' fw-bold')}">
                        <span>{page.title}</span>
                    </a>
                    <f:render section="Menu" arguments="{menu: page.children, level: '{level + 1}'}" />
                </li>
            </f:for>
        </ul>
    </f:if>

</f:section>
</html>
Copied!

We want to adjust the HTML output of the sitemap for different levels. The original template however gives us no means to output the level.

Line 5 uses the ViewHelper Render ViewHelper <f:render> to render everything in the section defined in lines 8-23.

In the original template the argument menu was already passed on as variable to the section. We now enhance this line to also pass on variable level set to 1.

In line 17 the section Menu recursively includes itself to display further levels of the sitemap. We now add 1 to the level so that within the recursive call we are in level 2.

In line 14 we use that level to determine which class to use for the page link, using once more the Fluid inline notation of the If ViewHelper <f:if>.

Override the partial template for image rendering

The templates of some content elements use the Render ViewHelper <f:render> to include a partial template. This is true wherever images are displayed for example.

Partials in turn can include different partials.

The templates for "Image" and "Textpic" both contain the following line:

vendor/typo3/cms-fluid-styled-content/Resources/Private/Templates/Image.html (Excerpt)
<f:render partial="Media/Gallery" arguments="{_all}" />
Copied!

If you open that partial, it includes yet another partial:

vendor/typo3/cms-fluid-styled-content/Resources/Private/Partials/Media/Gallery.html (Excerpt)
<f:render partial="Media/Type" arguments="{file: column.media, dimensions: column.dimensions, data: data, settings: settings}" />
Copied!

Which contains another until we finally arrive at vendor/typo3/cms-fluid-styled-content/Resources/Private/Partials/Media/Rendering/Image.html which does contain the actual Media ViewHelper <f:media>.

By overriding this one partial we can add a class to all images that are displayed with the "Image" or "Text with Media" content elements. For example we could display all images as circles by adding the class rounded-circle:

packages/my_site_package/Resources/Private/ContentElements/Partials/Media/Rendering/Image.html
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:media class="image-embed-item rounded" file="{file}" width="{dimensions.width}" height="{dimensions.height}" alt="{file.alternative}" title="{file.title}" loading="{settings.media.lazyLoading}" decoding="{settings.media.imageDecoding}" />
</html>
Copied!

Custom Content Blocks

When we filled the stage with content we noticed that the content does not look like the content within the original HTMl layout.

This is because the stage does not contain normal content, as provided by Fluid-Styled Content, but a Jumbotron element or a slider.

Install extension Content Blocks

The extension friendsoftypo3/content-blocks is an extension that is not part of the TYPO3 Core but maintained by a group of community members.

There are plans to integrate this extension into the Core, however at the time of writing there are no finite decisions yet.

First install the extension friendsoftypo3/content-blocks :

ddev composer req friendsoftypo3/content-blocks
Copied!

Set up the extension and delete all caches:

ddev typo3 extension:setup
ddev typo3 cache:flush
Copied!

The jumbotron Content Block

The site package you generated in step Generate a site package comes with two content elements. We look at the more basic content elements first.

You can now replace the content element in the area "Stage" of start page with one of type "Jumbotron".

Screenshot of the "New Page Content" dialog with the Carousel and Jumbotron as additional features

The new Content Blocks "Jumbotron" and "Carousel"

You can now create a jumbotron with a button and a link.

Directory packages/my_site_package/ContentBlocks/ContentElements contains one directory for each Content Block that can be used as normal Content Elements.

Directory structure of a Content Block

A Content Block consists of a configuration (config.yaml), a template and optionally assets and or language files:

The jumbotron consists of the following files:

  • packages/my_site_package/ContentBlocks/ContentElements/jumbotron

    • assets

      • icon.svg
    • language

      • labels.xlf
    • templates

      • frontend.html
    • config.yaml

The configuration of the jumbotron Content Block

File packages/my_site_package/ContentBlocks/ContentElements/jumbotron/config.yaml defines what fields should be available for the Content Block in the backend:

packages/my_site_package/ContentBlocks/ContentElements/jumbotron/config.yaml
name: my-site-package/jumbotron
typeName: my_site_package_jumbotron
group: my_site_package
prefixFields: true
prefixType: full
fields:
  -
    identifier: header
    useExistingField: true
  -
    identifier: bodytext
    useExistingField: true
    enableRichtext: true
  -
    identifier: button_text
    type: Text
    default: 'Read more'
    min: 4
    max: 15
  -
    identifier: button_link
    type: Link
    required: true
Copied!

Each Content Block must have a unique name with a prefix of your choice that should be unique within your project. (Line 1)

It is possible to use fields that are already pre-defined in the TYPO3 Core like header (Line 8) and bodytext (Line 11).

We also newly define two fields, one of type Text (Line 15-19) and one of type Link (Line 21-23). You can find all available types here: Field Types.

The meaning behind the other settings here can be found in the YAML reference of the Content Blocks guide.

The jumbotron template

The frontend template for the Content Block "Jumbotron" is a normal Fluid template. You already used Fluid for the Page templates and to adjust the templates of Fluid-Styled Content elements in chapter Overriding the default templates of content elements.

packages/my_site_package/ContentBlocks/ContentElements/jumbotron/templates/frontend.html
<div class="p-5 mb-4 bg-body-tertiary">
    <div class="container-fluid py-5">
        <h1 class="display-5 fw-bold">{data.header}</h1>
        <p class="col-md-8 fs-4"><f:format.html>{data.bodytext}</f:format.html></p>
        <f:link.typolink class="btn btn-dark btn-lg" parameter="{data.button_link}">{data.button_text}</f:link.typolink>
    </div>
</div>
Copied!

Line 3: The values of the database entry of the current content element can be found in variable {data}. In this line we render the content of the field header. The field was defined in line 8 of the config.yaml.

Line 4: Here we output the content of field bodytext as this field is a Rich-Text Editor we use the Format.html ViewHelper <f:format.html> to format and sanitize the output.

Line 5: We use the Link.typolink ViewHelper <f:link.typolink> to render a link to the target that was defined in our custom field button_link.

Next steps

Frequently asked questions

How to get started quickly

You can use the Site Package Builder to create a customized site package. If you want to follow this tutorial, choose "Site Package Tutorial" as base package.

What files are included in a site package?

A site package typically includes the following files:

  • Configuration files, such as site settings, TypoScript, and RTE (rich-text editor) configurations
  • Public assets: CSS, JavaScript, fonts, theme related images
  • Templates: Fluid templates that generate the HTML output
  • Code extending TYPO3 Core functionality or third-party extensions, such as Event listeners and Middlewares (Request handling)

When not to put files in a site package

If you are developing functionality that may need to be shared across multiple sites or TYPO3 installations in the future, it is advisable to create a custom extension for that functionality instead.

Where to download the example site package

Use Site Package Builder with "Site Package Tutorial" as base package.

Next Steps

Enhance the site package

The site package extension, as it stands now, still has some shortfalls. Let us have a closer look what you could or should do as the next steps to address these.

  1. Navigation menu features one level only

    The bigger the website becomes, the more likely is a multi-level page structure required. This means, editors will likely create sub-pages of the root page "Page 1" for example. At the moment, the menu does not support sub-pages.

    If this becomes a requirement, the TypoScript code used to generate the menu (see chapter TypoScrip configuration of the main menu) and the Fluid template file that outputs the menu (Resources/Private/Layouts/Page/Default.html) need to be updated.

    Learn more about the menu data processor menu data processor

  2. Stage has no background image

    The Stage stands as a place holder for various options in our example. Some readers may like to implement a banner with rotating images, some prefer a text content element or a video player instead. All this and much more is possible with TYPO3, but beyond the scope of this tutorial.

  3. There are no icons for pages in the menu

    It would be possible to define an additional field in the pages table to store an icon for each page and then output them in the menu for example.

  4. There is not footer

    The page could receive a footer with content taken from a special page or column of the root page.

In general, the nature of a tutorial, such as this document, is to provide detailed instructions to walk a beginner through a particular task. By building your own site package extension from scratch, you have learned each step that is required to turn a basic web design template into a fully working website in TYPO3.

When you create site packages in the future, you probably do not want to create every file over and over again, but use a pre-built version of the site package extension. Therefore, it make sense to store and maintain the current state in a central place, such as a Git repository. Despite the fact that for a learning experience it is always beneficial to develop the extension yourself, you can also download the extension built in this tutorial below.

Further readings

Videos on YouTube

TYPO3 has an official YouTube channel.

Where to ask questions

Lastly, after searching to find information already published, you may want to ask the TYPO3 community.

You can get information about where to get help on https://typo3.org/help.

Specifically, choose one of these options:

  1. The TYPO3 community has a forum at https://talk.typo3.org/ where you can Ask TYPO3 related questions.
  2. Meet the TYPO3 Community you can go to a Local TYPO3 User Group meet us online on Slack (How to get your TYPO3 Slack account) and/or find us at numerous events.

Sitemap