SBT configuration: built.sbt

The insign play-cms modules are added as library dependencies by default (you could also switch to local code modules if you intend to work on the modules).

We've also added a build configuration for Docker - which lets you very easily build and publish docker containers.

Content blocks: blocks/*

Per-project content blocks are places in the blocks folder, two were added to the demo: DemoPageBlock and TeaserBlock. A content block usually consists of 3 files: The block class, a frontend view template and a backend edit template.

The block class

Let's look at the DemoPageBlock.java:

@Entity
@Table(name = "cms_block_demopage")
@DiscriminatorValue("DemoPageBlock")
public class DemoPageBlock extends PageBlock { 

    @Override
    public Html render() {
        return demoPageBlock.render(this);
 
    }
 
    public Html editForm(Form editForm) {
        return edit.render(this, editForm, Controller.request().getQueryString("backURL"), null);
    }

 // ...
}


It extends from PageBlock, which all normal pages should, which in turn extends from AbstractBlock. The three annotations are from JPA and define that this is an ORM entity and where to store the data. Blocks use JPAs JOINED inheritance strategy. By convention, cms block tables are named cms_block_* and the top-most table is cms_blocks.

There are just two methods: render() renders the frontend template and editForm renders the backend edit form. There's also an example for a custom cache configuration, which would not cache the homepage (you should remove this of course if you continue your project from here).

Frontend view template

Next, let's have a look at the frontend template:

demoPageBlock.scala.html:

@(data: blocks.demopageblock.DemoPageBlock)
 
...
 
@main(data) {
    <h1>@data.getPageTitle</h1>
    <section class="container main-content">
 
        <div class="col-md-2" id="sidebar" role="navigation">
            <div class="well sidebar-nav">
            @_navigationByKey(
                key = PageBlock.KEY_FRONTEND,
                active = data
            )
            </div>
        </div>
 
        <div class="col-md-6">
            <div class="box">
            @Template.addBlockToSlot(classOf[CollectionBlock], data, "main").render()
            </div>
        </div>
 
        <div class="col-md-4">
            <div class="box">
               @Template.addBlockToSlot(classOf[CollectionBlock], data, "sidebar").render()
            </div>
        </div>
 
    </section>
 
    <hr>
 
    <section class="container">
        @Template.addBlockToSlot(classOf[CollectionBlock], data, "bottom").render()
    </section>
 
    <hr>
 
    <footer class="container footer">
        @Template.addBlockByKey(classOf[ContentBlock], "GlobalFooter").render()
    </footer>
}


The first line defines data as our DemoPageBlock to pull data from. @main is the master layout template.

The code below pulls in a navigation template, key identifies the navigation (e.g. main, left, footer .. etc), active is the currently active entry (just our page instance):

@_navigationByKey(
    key = PageBlock.KEY_FRONTEND,
    active = data
)


Of course you can create your own navigation templates.

Then, three blocks are added to slots in the template: main, sidebar and bottom:

@Template.addBlockToSlot(classOf[CollectionBlock], data, "main").render()
@Template.addBlockToSlot(classOf[CollectionBlock], data, "sidebar").render()
@Template.addBlockToSlot(classOf[CollectionBlock], data, "bottom").render()


This means that a CollectionBlock is to be placed in this spot (existing for this page or auto-created if it does not exist). CollectionBlocks are placeholders for other content blocks that the user can add later.

Finally, a named block is added, which here serves as a global footer over all pages:

@Template.addBlockByKey(classOf[ContentBlock], "GlobalFooter").render()


Backend edit template

The demo page block's edit template is a bit boring, it just pulls in the superclass' edit template. You could add your own fields here. Let's have a look at the other block's edit template:

teaserBlockEdit.scala.html:

@(data: blocks.teaserblock.TeaserBlock, editForm: Form[_], backURL: String)(extension: Html=Html.apply(""))
 
...
 
@footerAppend = {
    <script type="text/javascript">
        ...
    </script>
}
@baseBlockEdit(data, editForm, backURL, Messages.get("teaser.block.edit.title"), null, footerAppend){
 
    @mstring(
        data.getTitle,
        editForm,
        "title",
        Messages.get("content.block.edit.title.label"),
        ""
    )
 
    @mstringTextarea(
        data.getContent,
        editForm,
        "content",
        Messages.get("content.block.edit.content.label"),
        "",
        "tinymce-simple"
    )
 
    @mstring(
        data.getLinkUrl,
        editForm,
        "linkUrl",
        Messages.get("teaser.block.field.linkUrl.label"),
        ""
    )
    ...
}
 
@extension


@footerAppend allows to add custom html/js to this template's footer.

@baseBlockEdit pulls in the basic block edit form (handles default settings, such as permissions)

Inside, you can add form controls for your own properties. @mstring is a helper for multi-language strings. There is a tab per configured language, and mstrings switch the content if the user switches the tab. Multi-language strings are persisted and loaded automagically.

@mstringTextarea defines a Textarea, here with a tinymce-simple configuration.