The FLUIDTEMPLATE cObject

March 25, 2011

Author: Rens Admiraal

The FLUIDTEMPLATE object was introduced in TYPO3 4.5. This new cObject offers Fluid flexibility in your frontend templates. This article is meant as a hands-on introduction. Besides the basic usage it also reveals some new stuff which will be available in the next Fluid release. Use this article at will, and see how Fluid will fit you. I'm sure you will love this new feature!

First of all you need some basic understanding of how Fluid works. This is beyond the scope of this article, so please follow the supplied links if you've the need for more information. For this article some basic knowledge about Fluid template parts is needed, so here a short description: 

Layout 

Most web applications / websites have certain parts which are shown on all templates. Like a header bar with a logo or a footer for example. These elements can be defined in a layout. 

Template 

The main template like you know it, will contain the main part of your page. 

Partial 

A snippet which you can re-use. This is extremely useful if you've recurring elements in multiple templates. You can also pass arguments to a partial for dynamic parts. 

More information about layout / template / partial parts: flow.typo3.org/documentation/guide/partii/view.html

Note: This example shows the use of the format.raw viewhelper which is in git, but not yet released in the 1.3.0 release! Use the fallback mentioned in the notes for use with the 1.3.0 release.

Basic usage

So, now we want to create a frontend! Let's start with a basic template which contains a menu (TypoScript object: lib.mainMenu), and 2 columns (normal and left) rendered with css_styled_content. For this we need to create a new PAGE object in TypoScript, and add a FLUIDTEMPLATE cObject to it. This cObject is configured with some paths, and a pointer to the template to use. We also pass the cObjects we want to display to the variables property: 

page = PAGE
page {
    10 = FLUIDTEMPLATE
    10 {
        file = fileadmin/templates/Home.html
        partialRootPath = fileadmin/templates/Partials/
        layoutRootPath = fileadmin/templates/Layouts/
        variables {
            pageTitle = TEXT
            pageTitle.data = page:title
            leftColumn < styles.content.getLeft
            content < styles.content.get
        }
    }
}

Your HTML template (Home.html) could now for example contain the following: 

<f:section name="body">
    <h1>{pageTitle}</h1>
    <div id="mainMenu">
        <f:cObject typoscriptObjectPath="lib.mainMenu" />
    </div>
    <div id="leftColumn">
        {leftColumn -> f:format.raw()}
    </div>
    <div id="content">
        {content -> f:format.raw()}
    </div>
</
f:section>

{var -> f:format.raw()} is the shorthand notation to use a Fluid viewhelper. For more information about the standard set of viewhelpers, read: http://wiki.typo3.org/wiki/Fluid#Standard_View_Helpers or http://flow.typo3.org/documentation/guide/partv/fluidviewhelperreference.html.

The format.raw viewhelper is recently added to git, and not yet available in the 1.3.0 release of Fluid. In the 1.3.0 you could use a TypoScript object path and the cObject viewhelper:

TypoScript:

lib.mainContent < styles.content.get

Template:

<f:cObject typoscriptObjectPath="lib.mainContent" />

Adding a layout and using partials

Ok, the basic template is in place. Now we want our header and footer. Let's create a layout. Create create the file Default.html in the layouts folder we configured. The layout will contain 3 parts, a header, content area and a footer. The header will always contain a logo, which we will create in a partial for this example. The content area will be the content of the main template, and is called a section. The footer is just plain HTML: 

<div id="header">
    <f:render partial="Logo" />
</
div>
<
div id="body">
    <f:render section="Body" />
</
div>
<
div id="footer">
    Disclaimer
</
div>

This layout will of course render the HTML it contains, and also calls the render viewhelper twice. The first time it's used to render the Logo.html partial in the partials folder. The second time it renders the 'Body' section of the template. This section is declared by adding 2 lines in the main template. 

We also have to add a layout declaration to the template to use this layout, so let's see how our Home.html will now look like:

<f:layout name="Default" />
<
f:section name="body">
    <h1>{pageTitle}</h1>
    <div id="mainMenu">
        <f:cObject typoscriptObjectPath="lib.mainMenu" />
    </div>
    <div id="leftColumn">
        {leftColumn -> f:format.raw()}
    </div>
    <div id="content">
        {content -> f:format.raw()}
    </div>
</
f:section>

Read the online documentation of Fluid for more information about the render viewhelpers. You can also read the inline comments of the Fluid viewhelpers, since they contain very useful examples.

Alternative format (typeNum)

The typeNum of TYPO3 is used a lot for alternative output formats like a plain-text / PDF version of a page. Can this be done using FLUIDTEMPLATE too? Yeah, of course! Let's refactor the TypoScript setup a bit, and add a second PAGE object with typeNum 99 for a plain-text version of our website: 

temp.template = FLUIDTEMPLATE
temp.template {
    file = fileadmin/templates/Home.html
    partialRootPath = fileadmin/templates/Partials/
    layoutRootPath = fileadmin/templates/Layouts/
    variables {
        mainMenu < lib.mainMenu
        leftColumn < styles.content.getLeft
        content < styles.content.get
    }
}

page 
= PAGE
page 
{
    10 =< temp.template
}

text 
= PAGE
text 
{
    typeNum = 99
    config {
        disableAllHeaderCode = 1
        additionalHeaders = Content-type: text/plain
    }
    10 =< temp.template
    10 {
        file = fileadmin/templates/Home.txt
        format = txt
    }
}

Now we have 2 typeNums, and the template which will be used is set to Home.txt. The content of this plain-text template is: 

 {namespace ext=Tx_ExampleViewhelperContainer_ViewHelpers}
<
f:layout name="Default" />
<
f:section name="Body">
<
ext:plainText>{content}</ext:plainText>
<
ext:plainText>{leftColumn}</ext:plainText>
</f:section> 

Ok, now we're dropping in some new stuff. Declaring the layout and the body section is the same as the HTML template. The namespace declaration needs some more explanation.  

We need something to cleanup our content cince the output of css_styled_content already contains a lot of HTML. Since Fluid has no viewhelper which helps in this case, we create our own. For this I created an empty extension, only containing this viewhelper. The namespace declaration points all <ext:* /> tags to the viewhelpers available in the Classes/ViewHelpers/ folder of this extension. The plainText viewhelper does nothing more than just stripping the HTML tags from the content, and some string replaces. 

Want to know more about making your own viewhelpers? Read e.g. http://www.t3node.com/blog/writing-a-basic-fluid-viewhelper-for-typo3/.

The layout we use for the text version is almost equal to the HTML version, besides the fact it does not contain HTML code: 

 <f:render partial="Logo" />
{pageTitle}
<f:render section="Body" />

 =============== 

 Disclaimer 

It's important to know that the render viewhelper will now look for files with the following naming pattern: <name>.<format>. So, this layout is named Default.txt, and the Logo partial is called Logo.txt. This last file will of course contain a beautiful piece of ASCII art representing the logo.

Available soon: Dynamic layout name

A new feature which will be available in the next Fluid release (available in git already) is passing a variable to the layout viewhelper. So, you can than set your layout using:

<f:layout name=”{layout}” />

This gives you the ability to set the layout based on the page property layout for example. To do this one could use the following configuration:

page = PAGEpage {typeNum = 0= FLUIDTEMPLATE10 {file = fileadmin/templates/Home.html=fileadmin/templates/Partials/= fileadmin/templates/Layouts/{layout = CASElayout {key.data = page:layout=TEXT0.value = Default= TEXT.value = Alternativedefault < .0}}}
}

Documentation and references:

http://forge.typo3.org/projects/typo3v4-mvc/wiki/FLUIDTEMPLATE_Content_Object
http://wiki.typo3.org/wiki/Fluid
http://flow.typo3.org/documentation/guide/partii/view.html
http://flow.typo3.org/documentation/guide/partv/fluidviewhelperreference.html

I hope this article inspires you to use the FLUIDTEMPLATE, and I'm looking forward to see more blog posts and use cases of this cObject! 

Greetz, 

Rens