TYPO3: Well-formed fluid templates

The Fluid template engine - developed for the Flow3 project - is used more and more in TYPO3's core and extensions.

Fluid templates look like XML. Every functionality is implemented as a custom XML tag or tag attribute - very unlike e.g. Smarty or Twig which invented a terse template markup language that's easy to write.

Basic fluid functionality is wrapped in tags that are prefixed with f:, like <f:if> or <f:comment>

Unfortunately, fluid's inventors did not follow the way of XML to the end: Most fluid templates are not even well-formed.

Fluid-XML

This is a typical "partial" template:

{namespace f=TYPO3\CMS\Fluid\ViewHelpers}
<h3>{headline}</h3>
<p><f:if condition="{text}">{text}</f:if></p>

Several problems make the file non-wellformed:

  1. XML declaration missing
  2. XML requires a single root tag, but the template contains multiple
  3. Namespace prefix f is not defined

Let's fix the issues:

<?xml version="1.0" encoding="utf-8"?>
<div xmlns:f="TYPO3FluidViewHelpers">
  <h3>{headline}</h3>
  <p><f:if condition="{text}">{text}</f:if></p>
</div>

The XML is well-formed now. Unfortunately, the rendered template is broken:

...
<?xml version="1.0" encoding="utf-8"?>
<div xmlns:f="TYPO3FluidViewHelpers">
  <h3>Headline 1</h3>
  <p>Text 1</p>
</div>
<?xml version="1.0" encoding="utf-8"?>
<div xmlns:f="TYPO3FluidViewHelpers">
  <h3>Headline 2</h3>
  <p>Text 2</p>
</div>
...

The fluid template engine renders both XML declaration and the additional root tag, although we neither want nor need it. Depending on the context of our partial, we might even get invalid HTML.

Attempt to fix

To get rid of the root tag in our output, we could try to use a <f:if> tag with an always-true condition:

<?xml version="1.0" encoding="utf-8"?>
<f:if condition="1" xmlns:f="TYPO3FluidViewHelpers">
  <h3>{headline}</h3>
  <p><f:if condition="{text}">{text}</f:if></p>
</f:if>

Let's render it and ... congratulations, you just ran into bug #56481:

#1237823695: Argument "xmlns:f" was not registered

But even if my patch gets merged some day, the XML declaration will still get rendered.

Fixing broken output

Fluid's <f:render> tag supports a section attribute. It simply says that a certain section within the given template shall be rendered instead of the whole file:

<f:for each="{data}" as="datum" key="key">
  <f:render partial="datum" section="p" arguments="{datum: datum, key:key}" />
</f:for>

Now we just have to wrap our partial's HTML code with a section tag:

<?xml version="1.0"?>
<html xmlns:f="TYPO3FluidViewHelpers">
  <f:section name="p">
    <h3>{headline}</h3>
    <p><f:if condition="{text}">{text}</f:if></p>
  </f:section>
</html>

That's it. You can use that solution for templates and partials - but not for layouts.

Why?

Why do I want well-formed fluid templates?

Well-formed XML can be validated automatically through git pre-commit hooks. Utilizing them lets developers spot errors earlier.

Update 2015-06: A solution for TYPO3 7.3+

One year after my my bug had been rejected, a new one was opened and got fixed.

TYPO3 version 7.3 now allows you to use xmlns declarations on any elements in a fluid template. As long as their value begins with http://typo3.org/ns/, they are removed from the output.

The root tag issue was also fixed with that commit; adding data-namespace-typo3-fluid="true" on a root HTML tag in a fluid template causes it to not be rendered in the output.

This makes it possible to have well-formed layout templates, too - which was not possible with the section workaround.


You might want to read how to write well-formed templates with dynamic tags.

Written by Christian Weiske.

Comments? Please send an e-mail.