Use the Content Blocks Plugin in the Delivery Tier
Content Bean
The setup application's Beanwriter tool does not support the Content Blocks plugin yet, therefore when adding a content blocks field to a document type, the corresponding content bean class must be updated manually.
Each compound type used must have its own bean class as well (the Beanwriter will take care of this).
For the actual content blocks field, there are two approaches: one multi-type list or list for each type.
Single Multi-Type List
The first approach is to add one method to the bean which simply returns a list of all the content blocks, and deal with the different types of blocks in the template.
Advantage: the content blocks can be rendered in the exact order they are stored in the document.
Disadvantage: the template must "know" some implementation logic (no strict separation of concerns).
For example, for a content blocks field called blocks in a namespace myproject:
public List<?> getBlocks() { return getChildBeansByName("myproject:blocks"); }
If standard (out of the box) compound types are used the hst:isBeanType function can be used to check a content block's type in the template:
Freemarker:
<#if document.blocks??> <#list document.blocks as block> <#if hst.isBeanType(block, 'org.hippoecm.hst.content.beans.standard.HippoMirror')> <!-- render link --> <#elseif hst.isBeanType(block, 'org.hippoecm.hst.content.beans.standard.HippoHtml')> <!-- render rich text --> </#if> </#list> </#if>
JSP:
<c:if test="${not empty requestScope.document.blocks}"> <c:forEach var="item" items="${requestScope.document.blocks}"> <c:choose> <c:when test="${hst:isBeanType(item, 'org.hippoecm.hst.content.beans.standard.HippoMirror')}"> // render link </c:when> <c:when test="${hst:isBeanType(item, 'org.hippoecm.hst.content.beans.standard.HippoHtml')}"> // render rich text </c:when> </c:choose> </c:forEach> </c:if>
If custom compound types are used (i.e. their bean classes are in the same project) a property can be added to their bean classes, e.g.:
@Node(jcrType="myproject:videoblock") public class VideoBlock extends HippoCompound { // used to differentiate between different types of content blocks public String getType(){ return "video"; } public String getVideo() { return getProperty("myproject:video"); } }
The type property can then be used in the template to check the content block's type:
Freemarker:
<#if document.blocks??> <#list document.blocks as block> <#if block.type == 'video'> <!-- render video --> <#elseif block.type == 'image'> <!-- render image --> </#if> </#list> </#if>
JSP:
<c:if test="${not empty requestScope.document.blocks}"> <c:forEach var="item" items="${requestScope.document.blocks}"> <c:choose> <c:when test="${item.type=='video'}"> // render video </c:when> <c:when test="${item.type=='image'}"> // render image </c:when> </c:choose> </c:forEach> </c:if>
List Per Type
The second approach is to add a get method to the content bean for each block type.
Advantage: cleaner template, better separation of concerns.
Disadvantage: the order of the different content blocks is lost.
Example:
public List<?> getVideos() { // argument is the type of the compound return getChildBeans("myproject:videoblock"); } public List<?> getImages() { return getChildBeans("myproject:imageblock"); }
The template can then render the content blocks by type:
Freemarker:
<#if document.videos??> <#list document.videos as video> <!-- render video --> </#list> </#if> <#if document.images??> <#list document.images as image> <!-- render image --> </#list> </#if>
JSP:
<c:if test="${not empty requestScope.document.videos}"> <c:forEach var="item" items="${requestScope.document.videos}"> // render video </c:forEach> </c:if> <c:if test="${not empty requestScope.document.images}"> <c:forEach var="item" items="${requestScope.document.images}"> // render image </c:forEach> </c:if>