Creating the Template VTL File

The template VTL (Velocity Template Language) file is a theme's backbone, and the most basic requirement for the creation of a new theme. Simply place a folder containing a template.vtl file into a site's application/themes directory, and dotCMS will detect a new theme, taking the theme's name from the folder.

The quickest way to get started building your own custom template.vtl is to use the default System theme's as a starting point, adding VTL includes to replace layout placeholders. An example of one way this might look can be found at the bottom of the page.

Velocity Variables#


Template VTLs are able to call two important pre-defined Velocity variables, pointing to theme and layout data:

  • $dotTheme
  • $dotThemeLayout

Discussion of these two variables will be broken up into four subsections, in view of important nested properties.

Key Paths and More: $dotTheme#

$dotTheme contains basic information about the theme:

PropertyData
$dotTheme.titleThe theme's name, drawn from its folder.
$dotTheme.pathThe directory containing the theme — e.g. /application/themes/THEME_NAME/.
$dotTheme.htmlHeadtrue or false depending on whether the folder contains html_head.vtl.
$dotTheme.templatePathThe path to the template.vtl file asset.

The Big Picture: $dotThemeLayout#

$dotThemeLayout contains various layout properties.

PropertyData
$dotThemeLayout.titleThe title of the template or custom layout.
$dotThemeLayout.headertrue or false depending on the template or layout's settings.
$dotThemeLayout.footertrue or false depending on the template or layout's settings.
$dotThemeLayout.bodyContains body layout data; see below.
$dotThemeLayout.sidebarContains sidebar layout data; see below.

The two properties .body and .sidebar are special; both contain additional nested properties. In the system template.vtl, these two are given aliases for ease of reference:

## Main column
#set( $mainColumn = $dotThemeLayout.body )
## Sidebar
#set( $sidebar = $dotThemeLayout.sidebar )

We shall here consider these aliases to be a matter of convention.

The Body: $dotThemeLayout.body or $mainColumn#

$mainColumn contains only a single array: $mainColumn.rows. Each individual $row within contains the $row.columns property, an array of individual $column elements.

A pair of nested #foreach loops can iterate through the whole structure:

#foreach( $row in $mainColumn.rows )
    <!-- row html -->
    #foreach( $column in $row.columns )
        <!-- column html -->
        $render.eval($column.draw())
        <!-- column html after content -->
    #end
    <!-- html concluding the row -->
#end

At the innermost loop lies a series of $column structures, which have the following properties:

PropertyData
$column.leftA number from 0 to 11, indicating horizontal position based on $mainColumn's 12 divisions, counting from the left.
$column.leftOffsetSame as $column.left, but indexed from 1 to 12 instead of 0 to 11.
$column.widthA value from 1 to 12, indicating the column's width in terms of the number of $mainColumn's 12 horizontal divisions used.
$column.widthPercentSimilar to .width, but represented as a percentage of the $mainColumn.
$column.styleClassLists HTML class attributes assigned through the layout editor.
$column.previewEquivalent to $column.isPreview(); yields true or false.
$column.draw()Generates a #parsecontainer macro for the column, which can be read by $render.eval() — a method of the RenderTool Viewtool.
$column.containersContains additional object data; see below.

Each $container in $column.containers possesses:

PropertyData
$container.identifierA reference assigned to each element on the basis of its publishing bundle.
$container.uuidAn index number to distinguish between elements with the same identifier.

$sidebar contains the following properties:

PropertyData
$sidebar.widthA value of small, medium, or large, as selected in the template editor.
$sidebar.widthPercentA percentage of the viewport space, corresponding to $sidebar.width — either 20, 30, or 40.
$sidebar.locationEither left or right, as defined in the template editor.
$sidebar.previewEquivalent to $sidebar.isPreview(); yields true or false.
$sidebar.draw()Generates a #parsecontainer macro for the sidebar, which can be read by $render.eval() — a method of the RenderTool Viewtool.
$sidebar.containersContains additional object data; identical to $column.containers, in the previous section.

Including Other VTLs in template.vtl#


As with any case of including a VTL file, your html_head.vtl, header.vtl, and footer.vtl can be included with a call to the #dotParse macro, albeit with one small difference: They will require the $dotTheme.path variable in their file path.

Here are examples:

Including the HTML Head#

#if($dotTheme.htmlHead)
    #dotParse("${dotTheme.path}html_head.vtl")
#end

Including the Header#

#if($dotThemeLayout.header)
    #dotParse("${dotTheme.path}header.vtl")
#end

Including the Footer#

#if($dotThemeLayout.footer)
    #dotParse("${dotTheme.path}footer.vtl")
#end

Example: Complete template.vtl#


Below is an example of a functional template.vtl file, based on the System theme VTL. Bootstrap-style classes used throughout correspond to styles defined in the original's head; in the example below, those definitions — and other head elements — are assumed to have been moved to a html_head.vtl file in order to illustrate its inclusion and reduce screen clutter.

<!doctype html>
<html lang="en">

    <head>
        ############################
        ## HTML_HEAD (IF PRESENT) ##
        ############################
        #if($dotTheme.htmlHead)
            #dotParse("${dotTheme.path}html_head.vtl")
        #end        
        #set($utilClass = $dotPageContent.title.toLowerCase().replace(' ', '-'))
    </head>
    
    <body id="$utilClass" #if($EDIT_MODE)class="edit-mode"#end>
        
        <div class="body-wrapper">  
            #########################
            ## HEADER (IF PRESENT) ##
            #########################
            #if($dotThemeLayout.header)
                <header>
                    #dotParse("${dotTheme.path}header.vtl")
                </header>
            #end
            
            #############
            ## ALIASES ##
            #############
            ## Main column
            #set($mainColumn = $dotThemeLayout.body)
            ## Sidebar
            #set($sidebar = $dotThemeLayout.sidebar)
            
            ###############################
            ## LEFT SIDEBAR (IF PRESENT) ##
            ###############################
            #if ($sidebar && $sidebar.location != "")
            
                #if ($sidebar.width == 'small')
                    #set ($sidebarColumn1Span = "col-sm-2")
                    #set ($sidebarColumn2Span = "col-sm-10")
                #elseif ($sidebar.width == 'medium')
                    #set ($sidebarColumn1Span = "col-sm-3")
                    #set ($sidebarColumn2Span = "col-sm-9")
                #elseif ($sidebar.width == 'large')
                    #set ($sidebarColumn1Span = "col-sm-4")
                    #set ($sidebarColumn2Span = "col-sm-8")
                #else
                    #set ($sidebarColumn1Span = "")
                    #set ($sidebarColumn2Span = "")
                #end
    
                <div class="container">
                    <div class="grid">
                    #if ($sidebar.location == "left")
                        <div class="$sidebarColumn1Span">
                            ## Draw the column content
                            $render.eval($sidebar.draw())
                        </div><!--/div sidebar left-->
                        <div class="$sidebarColumn2Span">
                    #else
                        <div class="$sidebarColumn2Span">
                    #end
            #end
            
            #########################################
            ## ADDING THE ROWS FOR THE MAIN COLUMN ##
            #########################################  
            #if ($mainColumn.rows)

                #set($rowCount = 0)
                #foreach($row in $mainColumn.rows)
                    #set($rowCount = $rowCount + 1)
                    #set($rowLeftOffset = 1)
                    ## Each row has a number of columns, using bootstrap grid layout
                    #foreach($column in $row.columns)
                        #if($velocityCount == 1)
                        
                        <section id="section-$!{rowCount}" class="section $!{row.styleClass}">
                            <div class="container">
                                <div class="grid">
                        #end

                        ## Define width by the column settings
                        #set ($currentColumnSpan = "col-lg-${column.width}")
                        #set ($offset = 0)
                        
                        ## Set the bootstrap offset of each column based on the row's left offset. 
                        #if ($rowLeftOffset == $column.leftOffset)
                            #set($columnOffset = "")
                        #else
                           #set($offset = $column.leftOffset - $rowLeftOffset)
                           #set($columnOffset = "offset-lg-${offset}")
                        #end
                        #set($rowLeftOffset = $rowLeftOffset + $column.width + $offset)
                        
                                    <div class="$currentColumnSpan $columnOffset $!{column.styleClass}">
                                        ## Draw the column content
                                        $render.eval($column.draw())
                                    </div><!--/Column-->
                        
                        #if($velocityCount == $row.columns.size())
                                </div><!--/row-->
                            </div><!--/container-->
                        </section><!-- /row-wrapper-->
                        #end
                    #end
                #end
            #end
                
            ################################
            ## RIGHT SIDEBAR (IF PRESENT) ##
            ################################
            #if ($sidebar && $sidebar.location != "")
                #if ($sidebar.location == "left")
                    </div><!--/div columns-->
                #else
                    </div><!--/div columns-->
                    <div class="$sidebarColumn1Span">
                        ## Draw the column content
                        $render.eval($sidebar.draw())
                    </div><!--/div sidebar right-->
                #end
                </div><!--/div row-->
            </div><!-- /container-->
            #end
        </div><!-- /body-wrapper -->
        
        #########################
        ## FOOTER (IF PRESENT) ##
        #########################
        #if($dotThemeLayout.footer)
            <footer>
                #dotParse("${dotTheme.path}footer.vtl")
            </footer>
        #end
    </body>
</html>
    Creating the Template VTL File | dotCMS Dev Site