Template prototype is like a master page template. Anything you configure in the prototype is applied to all page templates. The prototype makes configuration efficient as you only need to do it once. For example, add an area to the prototype to make it available on all pages. You can override the prototype at the page definition level if needed.

Best practice

Put commonly used things in the template prototype. If most pages on your site have the same areas then define those areas in the prototype.

Do I need a prototype?

No, it is not necessary to use a prototype. You can configure a separate page definition for each page template instead. This works fine if you have a small number of templates that are very different from each other.

Prototype is an optional templating mechanism that offers a number of benefits:

  • Ensures uniformity across templates
  • Avoids repeating and duplicating configuration
  • Creates similar templates quickly

Prerequisites

Configuring a prototype

The prototype definition is a page template definition that must use a special class: PrototypeTemplateDefinition . You can use all the page template properties.

You can configure a prototype in:

 If you have the Multisite module (EE Pro) you can configure a different prototype for each site or use the same prototype for all sites.

Configuring a prototype in JCR

In the site definition configure the prototype in the /templates/prototype node.

Example: Prototype in the site definition in the Site app.

Node nameDescription

 templates

 

 prototype

 

 areas

 

 navigation

 

 footer

 

 main

 

 htmlHeader

 

 class

info.magnolia.my-module.definition.PageTemplateDefinition

 templateScript

/my-module/templates/pages/main.ftl

 renderType

site

Configuring a prototype in YAML

While it is not possible to configure a site definition completely in YAML, you can configure the prototype in YAML and reference it in the site definition. The prototype definition can reside in any module.

To configure the prototype in YAML:

  1. In the site definition in /<site name>/templates:
    1. Set the: 
      1. class property to info.magnolia.module.site.templates.ReferencingPrototypeTemplateSettings. This class allows you to use a prototype defined in YAML.
      2. prototypeId to the location of the YAML prototype definition in the <module name>:<relative path to definition> format, for example, travel-demo:pages/prototype.
  2. Remove the /prototype node, if it exists.

    Exampletravel site definition in the Site app.

    Node nameValue

     travel

     

     templates

     

     availability

     

     class

    info.magnolia.module.site.templates.ReferencingPrototypeTemplateSettings

     prototypeId

    travel-demo:pages/prototype

     theme

     

     i18n

     
  3. Create the prototype YAML file in the location defined in the prototypeId property and set the class property to info.magnolia.module.site.templates.PrototypeTemplateDefinition (or a subclass).

     # When using 'renderType=site' all pages inherit their 'templateScript' value from the site definition which is
    # globally defined for whole the site. This is the reason no page YAML definition defines an explicit 'templateScript'
    # to use. The value inherited and currently used is:
    # templateScript: /travel-demo/templates/pages/main.ftl
    # This might be replaced with the template from 'travel-demo-marketing-tags':
    # templateScript: /travel-demo-marketing-tags/templates/pages/main-marketing-tags.ftl
    
    dialog: mtk2:pages/basic
    class: info.magnolia.module.site.templates.PrototypeTemplateDefinition
    
    templateScript: /travel-demo/templates/pages/main.ftl
    renderType: site
    type: feature
    
    jsFiles:
      - link: /.resources/travel-demo-theme/libs/twitterbootstrap/js/bootstrap.min.js
        addFingerPrint: true
      - link: /.resources/travel-demo-theme/libs/twitterbootstrap-extras/ie10-viewport-bug-workaround.js
        addFingerPrint: true
      - link: /.resources/travel-demo-theme/js/viewport-units-buggyfill.js
        addFingerPrint: true
    
    areas:
      htmlHeader:
        createAreaNode: false
        renderType: freemarker
        templateScript: /travel-demo/templates/pages/areas/htmlHeader.ftl
        type: noComponent
      main:
        type: list
      footer:
        editable: false
        templateScript: /travel-demo/templates/pages/areas/footer.ftl
        type: noComponent
        parameters:
          columns: 4
        areas:
          footer1: &footer1
            type: list
            templateScript: /travel-demo/templates/pages/areas/contentContainer.ftl
            parameters:
              cssClass: col-md-3
            inheritance:
              components: all
              enabled: true
            availableComponents:
              textImage:
                id: travel-demo:components/textImage
              linkList:
                id: travel-demo:components/linkList
          footer2: *footer1
          footer3: *footer1
          footer4: *footer1
      navigation:
        class: info.magnolia.demo.travel.definition.NavigationAreaDefinition
        createAreaNode: false
        modelClass: info.magnolia.demo.travel.model.NavigationAreaModel
        renderType: freemarker
        templateScript: /travel-demo/templates/pages/areas/navigation.ftl
        type: noComponent
        userLinksResolvers:
          public-user-registration:
            class: info.magnolia.demo.travel.user.DefaultUserLinksResolver
            loginPageTemplateId: public-user-registration:components/login
            profilePageTemplateId: public-user-registration:components/userUpdate
            registrationPageTemplateId: public-user-registration:components/registration
    

Prototype template properties

Prototype is a  TemplateDefinition  which means it supports the same properties as page definition, including common template properties. However, typically you don't use them all. Here are the typical use cases:

areas

optional

Common areas such as footer or navigation that are used on most pages. Each child node is an area definition. Define the areas in the prototype so you don't have to repeat them in each page definition.

templateScript

optional

The templateScript property allows you to define a common page template script for the whole site. For a page to inherit its template script from the prototype you must also define renderType=site in the template definition.

A page template script typically starts with an opening <html> element and ends with the closing </html> element when rendering HTML output. See main.ftl in the Travel Demo.

Example: The travel demo demo defines a template script in the prototype. This common script is used for all pages. It is also the reason why no YAML page definition in the demo has an explicit templateScript property. The page definitions set renderType=site to inherit the script from the prototype, see home.yaml for example.

class

optional

A custom definition class which extends ConfiguredTemplateDefinition , an implementation of TemplateDefinition . You only need a custom class if you want to add your own nodes and properties in the prototype. Implement corresponding methods to operate on those properties in the definition class.

Example: PageTemplateDefinition (Git) is a custom definition class used in the Travel Demo. It adds support for a jsFiles node which allows you to define JavaScript files in the prototype the same way a theme defines them.

Merging a prototype with a page definition

When a user requests a page Magnolia merges the prototype with a page definition. The result is a merged template definition which is then used to render the page.

The merged definition is virtual. You won't find its configuration anywhere. It is created dynamically at the time of rendering. However, you can access the merged definition in a template script using the  def   rendering context object .

Example: Merging a prototype (configured in JCR) with a home page definition (configured in YAML)

  1. Prototype defines the main area type as list. Page definition adds availableComponents for the area. The result contains both.
  2. Prototype defines a templateScript. Page definition says nothing about script. The result is that the home page uses the script defined in the prototype.
  3. Prototype defines the footer area as not editable. Page definition overrides this decision by allowing footer editing on the home page. The result is that the footer can be edited on the home page only.

Before mergeAfter merge

Prototype:

Node nameDescription

  prototype

 

  areas

 

  footer

 

  availableComponents

 

  textImage

 

  id

mtk:components/textImage

  linkList

 

  id

mtk:components/linkList

  editable

false

  type

list

  main

 

  type

list

  templateScript

/example/templates/pages/main.ftl

Page template definition:

home.yaml
renderType: site
areas:
  footer:
    editable: true
  main:
    availableComponents:
      textImage:
        id: mtk:components/textImage
      teaserInternal:
        id: mtk:components/teaser

Merged template definition:

Node nameDescription

  prototype

 

  areas

 

  footer

 

  availableComponents

 

  textImage

 

  id

mtk:components/textImage

  linkList

 

  id

mtk:components/linkList

  editable

true

  type

list

  main

 

  availableComponents

 

  textImage

 

  id

mtk:components/textImage

  teaser

 

  id

mtk:components/teaser

  type

list

  templateScript

/example/templates/pages/main.ftl

#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))