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:
- A Composer-based TYPO3 installation, at least version 13.4.
- You need Initial pages and a site configuration.
- You need a Minimal site package.
- The assets should be in the correct locations: Copy the assets of the theme.
After this tutorial you have created Fluid templates and split them into manageable pieces.
Create the Fluid templates
Copy the main static HTML file from
Resources/
to Resources/
. 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.
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:
-<!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>
The Fluid template Default.
now contains only the HTML
code inside the body:
<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 jumbotron</h1>
<p class="col-md-8 fs-4">This jumbotron 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">© 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>
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.
Note
Each time you change a Fluid template you must flush the caches. Fluid
templates preprocessed into PHP files and stored in the folder
var/
.
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>.
+ <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" />
The path to the assets will be resolved by TYPO3. EXT:
tells TYPO3 that this is
an extension path. my_
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
/_
. 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>:
-<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" />
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
/_
.
Split up the template into partials
If you compare the two static templates
Resources/
and Resources/
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/
.
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:
<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>
Move the Fluid code you just remove to a file called
my-
.
Do the same with the jumbotron, the breadcrumb, and the footer.
You should now have the following files:
-
-
-
Default.html
-
Subpage.html
-
-
-
Footer.html
-
Header.html
-
Jumbotron.html
-
-
The Fluid template Resources/
should now look like this:
<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="Jumbotron" arguments="{records: content.jumbotron.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" />
You will learn how to display the dynamic content in chapter Display the content elements on your page.
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 Jumbotron into such a section:
<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="Jumbotron" arguments="{records: content.jumbotron.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="Jumbotron" 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>
The result looks like this:
<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="Jumbotron" arguments="{records: content.jumbotron.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>
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:
<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="Jumbotron" 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>
Extract the breadcrumb into a partial
The subpage template contain a breadcrumb, between jumbotron and content, that you can also move to a partial.
The breadcrum partial looks like this:
<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>
Extract the repeated part to a layout
Lines 1-9 of file Subpage.
in step The Fluid template for the subpage step are exactly the
same like in file Resources/
.
We can extract these lines into a so called Fluid layout and load them with the Layout ViewHelper <f:layout>:
-<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>
Save the extracted layout to a file called
Resources/
. This file now contains
the following:
<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" />
Repeat the same for file Resources/
.
-
-
-
Layout.html
-
-
-
Default.html
-
Subpage.html
-
-
-
-
Breadcrumb.html
-
FooterMenu.html
-
Menu.html
-
-
Footer.html
-
Header.html
-
Jumbotron.html
-
-
You can finde the complete site package extension at this step at branch main-step/fluid.