What is a Valid Hippo Head Contribution?

October 26th 2018 Hippo CMS Freemarker

In Hippo CMS, a page is generated from a hierarchy of Freemarker templates. The root template will typically take care of the basic HTML page structure, i.e. its head and body. If other templates need to add some content to the head or other specific parts of the page, they can use the head contribution mechanic.

Its documentation explains the basics well but doesn't mention the restrictions it imposes. In this post, I'm listing the ones I have encountered along with recommendations how to circumvent them.

Single Root Element per Contribution

Each head contribution can only contain a single root element. This means that the following is not a valid head contribution:

<@hst.headContribution category="templates">
    <script id="first-template" type="text/x-handlebars-template">
        <div></div>
    </script>
    <script id="second-template" type="text/x-handlebars-template">
        <div></div>
    </script>
</@hst.headContribution>

None of its content will be included in the generated page. The following error will be reported in the console:

[INFO] [talledLocalContainer] [Fatal Error] :4:6: The markup in the document following the root element must be well-formed.

To make it work, you will need to put each element in its own head contribution:

<@hst.headContribution category="templates">
    <script id="first-template" type="text/x-handlebars-template">
        <div></div>
    </script>
</@hst.headContribution>
<@hst.headContribution category="templates">
    <script id="second-template" type="text/x-handlebars-template">
        <div></div>
    </script>
</@hst.headContribution>

All Tags Must Be Closed

Although HTML allows unclosed tags, the following head contribution won't be included in the generated page:

<@hst.headContribution category="templates">
    <script id="first-template" type="text/x-handlebars-template">
        <input type="checkbox" name="check">
    </script>
</@hst.headContribution>

An error will be reported instead:

[INFO] [talledLocalContainer] [Fatal Error] :3:7: The element type "input" must be terminated by the matching end-tag "</input>".

This time the error already suggests the fix - add a closing tag. Self-closing the tag works just as well:

<@hst.headContribution category="templates">
    <script id="first-template" type="text/x-handlebars-template">
        <input type="checkbox" name="check" />
    </script>
</@hst.headContribution>

All Attributes Must Have a Value

Valid HTML attributes without values aren't allowed either:

<@hst.headContribution category="templates">
    <script id="first-template" type="text/x-handlebars-template">
        <input type="checkbox" name="check" checked />
    </script>
</@hst.headContribution>

Again, an error will be reported and the head contribution won't be added to the generated page:

[INFO] [talledLocalContainer] [Fatal Error] :2:53: Attribute name "checked" associated with an element type "input" must be followed by the ' = ' character.

Adding the = character alone is not enough. A value is also required:

<@hst.headContribution category="templates">
    <script id="first-template" type="text/x-handlebars-template">
        <input type="checkbox" name="check" checked="checked" />
    </script>
</@hst.headContribution>

No Content in Non-Leaf Elements

Even elements which contain a combination of other elements and immediate content aren't processed correctly:

<@hst.headContribution category="templates">
    <script id="second-template" type="text/x-handlebars-template">
        <div>Result: <strong>PASS</strong></div>
    </script>
</@hst.headContribution>

To make matters worse, no error will be reported in such cases. The head contribution will be added to the generated page but all the content from non-leaf elements will be skipped:

<script id="second-template" type="text/x-handlebars-template">
    <div><strong>PASS</strong></div>
</script>

The only way I managed to work around the issue was to wrap problematic content in extra tags:

<@hst.headContribution category="templates">
    <script id="second-template" type="text/x-handlebars-template">
        <div><span>Result: </span><strong>PASS</strong></div>
    </script>
</@hst.headContribution>

Now, the head contribution was included in full. However, depending on the CSS, the extra markup might affect the rendering.

If possible, it's best to to not use head contributions for HTML content. As long as you only use it for adding script and style references, you avoid all issues except the first one. And the suggested workaround for that one doesn't affect the markup in the generated page.

Copyright
Creative Commons License