How can I add a global footer to all pages?

Solution: Simply add the footer block by its class and key:

@Template.addBlockByKey(classOf[MyFooterBlock], "footer").cached

Note: Since such blocks are not present in the normal block parent/children hierarchy, you need to take special action when using caching (typically for global blocks you'll want to flush the complete cache when the global block changes).

I want to subclass PageBlock and add some properties. How do I access them in the navigation template?

Problem: Since the navigation template loops through PageBlock instances, you do not have access to your subclass getters.

Solution: Use delegation. Create a static getter in your subclass, e.g. MyPage.getNavSubtitleOf(PageBlock block).

DefaultContentPage.java:

public class DefaultContentPage extends PageBlock {
 
    /**
     * Helper to get the project-specific sub nav titles if available, or an empty mstring if not, from all page subclasses.
     * @param page
     * @return nav subtitle mstring or empty mstring, if type is not a DefaultContentPage instance
     */
    public static MString getNavSubtitleOf(PageBlock page) {
        if (page instanceof DefaultContentPage) {
            return ((DefaultContentPage) page).getNavSubtitle();
        } else {
            return new MString();
        }
    }

 

navigation.scala.html:

@for(subPage <-root.getSubPages) {
    <li @if(subPage == active){class="active"}>
    @subPage.getNavTitle<br />
    <small>@DefaultContentPage.getNavSubtitleOf(subPage)</small>

Note: Since the cms has its own PageBlock subclasses (e.g. LinkBlock), you cannot just filter for your own subclass type(s).

 

How can I limit the subblock types that can be added to a page or collection?

Problem: The list of sub block types is too large or does not fit the given collection. E.g. a sidebar column should be limited to contain only sub block types that fit there.

 

Solution 1: Define a context and configure it in application.conf

You can set a context (just a string identifier) to each block. This can be done from everywhere, but ideally is done from the template. Example:

template.scala.html:

@Template.addBlockToSlot(classOf[CollectionBlock], data, "slot1").context("maincolumn").cached
@Template.addBlockToSlot(classOf[CollectionBlock], data, "slot2").context("sidebar").cached

You can then configure the allowed or excluded sub blocks like this:

application.conf:

cms.context.maincolumn.excludedSubblocks = [SidebarBlock]
cms.context.sidebar.allowedSubblocks = [SidebarBlock, ContentBlock]

In this example, we define explicitly two blocks for the sidebar, while allowing all blocks except SidebarBlock in the maincolumn.

 

Solution 2: Override getAllowedSubBlocks()

You could also override you block's getAllowedSubBlocks() - if you already have one. You should not subclass e.g. CollectionBlock just for this - then better use solution 1.

 

Hint: You can also use the per-context block configuration for your own configuration purposes. Just create a Config subclass and in configNamespace() return "cms.context.mycontext".