Overview

Create a package which contains 3 files:

  1. Model class (MyContentBlock.java)
  2. Component class (MyContentBlockComponent.java)
  3. Module class (MyContentBlockModule.java)
  4. Edit form (myContentBlockEdit.scala.html)
  5. Frontent view template (myContentBlockShow.scala.html)

Then you register your new block with the cms and restart play and you're done.

Create the model

Create a class that extends from the chosen archetype:

  • PageBlock for pages or navigation entries
  • CollectionBlock for collections of content blocks that can be added e.g. to page columns
  • ContentBlock for any movable block that contains content


Example, MyContentBlock.java:

package blocks.mycontentblock;

import ch.insign.cms.models.ContentBlock;
import ch.insign.commons.db.MString;
import play.data.Form;
import play.mvc.Controller;
import play.mvc.Http;
import play.twirl.api.Html;

import javax.persistence.*;

@Entity
@Table(name = "my_content_block")
@DiscriminatorValue("MyContentBlock")
public class MyContentBlock extends ContentBlock {

    @OneToOne(cascade= CascadeType.ALL)
    private MString subtitle = new MString();

    public MString getSubtitle() {
        return subtitle;
    }

    public void setSubtitle(MString subtitle) {
        this.subtitle = subtitle;
    }

    @Override
    public Html render(Http.Request request) {
        return super.render(request);
    }

    @Override
    public Html editForm(Http.Request request, Form editForm) {
        String backURL = Controller.request().getQueryString("backURL");
        return blocks.mycontentblock.html.edit.render(this, editForm, backURL, null);
    }
}


Notes:

  • Block classes inherit from Model and thus are JPA entity classes
  • Add multi-language properties using MString as seen in the example
  • render() Returns the block's rendered frontend view
  • editForm() returns the rendered edit form for this block
  • @Table and @DiscriminatorValue must be unique in your project.
  • How to access subclass getters from navigation

Create component class

Create a class that extends GenericBlockComponent and implements BlockWrapper.

Example, MyContentBlockComponent.java:

package blocks.mycontentblock;

import blocks.mycontentblock.html.edit;
import blocks.mycontentblock.html.show;
import ch.insign.cms.blocks.BlockWrapper;
import ch.insign.cms.blocks.GenericBlockComponent;
import ch.insign.cms.repositories.BlockRepository;
import ch.insign.cms.views.admin.utils.BackUrl;
import ch.insign.cms.views.html._blockBase;
import ch.insign.commons.db.SmartFormFactory;
import play.data.Form;
import play.libs.F;
import play.mvc.Http;
import play.twirl.api.Html;

import javax.inject.Inject;

public class MyContentBlockComponent extends GenericBlockComponent<MyContentBlock> implements BlockWrapper<MyContentBlock> {

    private final SmartFormFactory formFactory;
    private final BlockRepository<MyContentBlock> blockRepository;
    private final _blockBase blockBase;

    @Inject
    public MyContentBlockComponent(SmartFormFactory formFactory,
                                BlockRepository<MyContentBlock> blockRepository,
                                _blockBase blockBase) {
        this.formFactory = formFactory;
        this.blockRepository = blockRepository;
        this.blockBase = blockBase;
    }

    @Override
    public Html wrapContent(Http.Request request, Html content, MyContentBlock block) {
        return blockBase.render(
                block,
                false,
                true,
                true,
                false,
                "Content",
                "red",
                false,
                "pcms-horizontal",
                content,
                request
        );
    }

    @Override
    public Html display(Http.Request request, MyContentBlock block) {
        return show.render(block, request);
    }

    @Override
    public Html edit(Http.Request request, MyContentBlock block) {
        Form<MyContentBlock> form = formFactory.form(MyContentBlock.class).fill(block);
        return edit.render(block, form, BackUrl.get(request), request);
    }

    @Override
    public F.Either<Html, ? extends MyContentBlock> save(Http.Request request, MyContentBlock block) {
        Form<MyContentBlock> editForm = formFactory.form(MyContentBlock.class)
                .fill(block)
                .bindFromRequest(request);

        if (editForm.hasErrors()) {
            return F.Either.Left(edit.render(block, editForm, BackUrl.get(request), request));
        }

        MyContentBlock updatedBlock = editForm.get();
        return F.Either.Right(blockRepository.save(updatedBlock));
    }

    @Override
    public boolean supports(String blockName) {
        return MyContentBlock.class.getName().equals(blockName);
    }
}

Create module class

Create a class, that extends AbstractBlockModule and override it's configure() method.

package blocks.mycontentblock;

import ch.insign.cms.inject.AbstractBlockModule;

public class MyContentBlockModule extends AbstractBlockModule {

    @Override
    protected void configure() {
        bindBlock().toInstance(MyContentBlock.class);
        bindComponent().to(MyContentBlockComponent.class);
    }
}

Create the edit form

You can either choose to use the default edit form base and place your content elements inside.

Example, edit.scala.html:

@(data: blocks.mycontentblock.MyContentBlock, editForm: Form[_], backURL: String)(extension: Html=Html.apply(""))
@import ch.insign.cms.views.html.admin._
@contentBlockEdit(data, editForm, backURL){
 
    @mstringTextarea(
        data.getSubtitle,
        theForm = editForm,
        formKey = "subtitle",
        label = "Subtitle",
        placeholder = ""
    )
    @extension
}


The base edit template currently includes:

  • language tabs (for MString properties)
  • Virtual path and visibility control (for PageBlock subclasses)
  • Time- and role-based access management


Tip: add @extension to allow later subclasses to add their content.

Alternatively, you can create your own template. 

Create the frontend template

This is straight-forward. Example:

show.scala.html:

@(data: blocks.mycontentblock.MyContentBlock)
@import ch.insign.cms.views.html._
@import ch.insign.cms.models.Template
 
@_blockBase(data = data, delete=true, edit=true, add=false, color="red", name="MyContentBlock") {
    @Template.html(data.getSubtitle)
}


Note: 

  • Use @_blockBase() to import the default cms frontend edit controls. They're only visible for logged in users with write access to the particular block.
  • Edit buttons can be controlled as seen
  • Color and name are used for the debug mode (&debug=true)
     

Register your new block

In your application.conf following line should be added:

cms.blocks.enabled += "blocks.mycontentblock.MyContentBlock"

Also, add a line to enable module

play.modules.enabled += "blocks.mycontentblock.MyContentBlockModule"

 

Congratulations, your new ContentBlock is ready and can be added to pages and collections.

Note: When adding blocks to the play-cms itself, an entry in play-cms-orm.xml is also required.