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:
Property | Data |
---|---|
$dotTheme.title | The theme's name, drawn from its folder. |
$dotTheme.path | The directory containing the theme — e.g. /application/themes/THEME_NAME/ . |
$dotTheme.htmlHead | true or false depending on whether the folder contains html_head.vtl . |
$dotTheme.templatePath | The path to the template.vtl file asset. |
The Big Picture: $dotThemeLayout
#
$dotThemeLayout
contains various layout properties.
Property | Data |
---|---|
$dotThemeLayout.title | The title of the template or custom layout. |
$dotThemeLayout.header | true or false depending on the template or layout's settings. |
$dotThemeLayout.footer | true or false depending on the template or layout's settings. |
$dotThemeLayout.body | Contains body layout data; see below. |
$dotThemeLayout.sidebar | Contains 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:
Property | Data |
---|---|
$column.left | A number from 0 to 11, indicating horizontal position based on $mainColumn 's 12 divisions, counting from the left. |
$column.leftOffset | Same as $column.left , but indexed from 1 to 12 instead of 0 to 11. |
$column.width | A value from 1 to 12, indicating the column's width in terms of the number of $mainColumn 's 12 horizontal divisions used. |
$column.widthPercent | Similar to .width , but represented as a percentage of the $mainColumn . |
$column.styleClass | Lists HTML class attributes assigned through the layout editor. |
$column.preview | Equivalent 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.containers | Contains additional object data; see below. |
Each $container
in $column.containers
possesses:
Property | Data |
---|---|
$container.identifier | A reference assigned to each element on the basis of its publishing bundle. |
$container.uuid | An index number to distinguish between elements with the same identifier. |
The Sidebar: $dotThemeLayout.sidebar
or $sidebar
#
$sidebar
contains the following properties:
Property | Data |
---|---|
$sidebar.width | A value of small , medium , or large , as selected in the template editor. |
$sidebar.widthPercent | A percentage of the viewport space, corresponding to $sidebar.width — either 20, 30, or 40. |
$sidebar.location | Either left or right , as defined in the template editor. |
$sidebar.preview | Equivalent 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.containers | Contains 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>