Back to the blog
  • Jun 14, 2022
  • 10 MIN
Category Tech
Previewing Content From Content Apps 1200x628
Previewing Structured Content From Content Apps

Previewing Structured Content From Content Apps

Magnolia's headless CMS lets you manage content in a central hub and then use it on multiple touchpoints. Marketers and content authors can manage structured content using a Content app. Content apps make it easy to enter content such as products or events via a form.

The centralized management of content has several practical advantages. For example, changes only need to be made in one place to update the content in every frontend automatically. In addition, rights can be configured so that different departments have their own areas within the same content management system.

While Magnolia offers a visual editor to create and design pages, Content apps don’t offer a preview out of the box. A preview, however, can be very useful to check if the created content will look as desired, for example, a title wraps correctly, or an image looks right.

In this blog article, I would like to show how to create a preview for Content apps easily. You can rebuild this functionality in your environment by copying my code examples.

You need a web app, an additional Maven module, and a Magnolia Light Module:

  • blog-preview-webapp

  • blog-preview-config

  • blog-preview-light

Creating the Events Content App

First, we create a Content Type and Content app for events using Magnolia Light Development, our low-code approach. If you are new to Content Types and apps in Magnolia, I recommend reading the Content Types tutorial.

Creating the Content Type Model Definition

We create a very simple events content type definition following the Content Type documentation.

File: blog-preview-light/contentTypes/events.yaml

  datasource:  workspace: events  autoCreate: true model:  nodeType: event  properties:    - name: name      label: Event name      required: true      i18n: true    - name: location      label: Location      i18n: true    - name: startDate      label: Start date      type: Date    - name: endDate      label: End date      type: Date    - name: abstract      label: Abstract      i18n: true    - name: description      label: Description      type: richText      i18n: true  

Creating the Events Content App

For the Events app, we use the previously defined Content Type. Let’s keep the app simple for now: point it to the events content type and assign it a name and a label.

File path: blog-preview-light/apps/events-app.yaml

  !content-type:events name: events-app label: Events  

We will extend the definition later.

Creating the Events Preview Page Template

To preview content outside of a web application, we need a page template for its presentation. We can use this page template for the preview only, or we can use the page template of the actual web app.

Since we haven’t created any page templates yet, we need to create a new template for the preview now.

Creating the Event Page Template Definition

First, we create a simple page definition without defining a user dialog for now.

File: blog-preview-light/templates/pages/event.yaml

  title: Event templateScript: /blog-preview-light/templates/pages/event.ftl renderType: freemarker  

Writing the Event Page Template Script

The second step is to create a simple template script that displays all event properties.

File: blog-preview-light/templates/pages/event.ftl

  <!DOCTYPE html> <html>  <head>    [ /]    <meta charset="utf-8" />    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />    <style>        .container {/* Insert your Container style*/}        .element {/* Insert your Element style*/}    </style>  </head>  <body>    <!-- ${cmsfn.dump(content, 5, true)} uncomment to see all the properties -->    <div class="container">        <div class="element">Name: ${}</div>        <div class="element">Location: ${content.location}</div>        <div class="element">StartDate: ${content.startDate}</div>        <div class="element">EndDate: ${content.endDate}</div>        <div class="element">Abstract: ${content.abstract}</div>        <div class="element">Description: ${cmsfn.decode(content).description!""}</div>    </div>  </body> </html>  

Updating the Maven Module Configuration

To use the same logic in the preview that will be used in the web app, we need to make two changes in the Maven module.

Updating Module.xml

We make the first change in module.xml by adding the new components using the following id pattern in the component definition: app-<app name>-<subapp name>.

File: blog-preview-config/src/main/resources/META-INF/magnolia/blog-preview-config.xml

  <!-- For the event preview --> <components>  <id>app-events-app-preview</id>    <component>    <type></type>    <implementation></implementation>    <scope>singleton</scope>  </component>  <component>    <type>info.magnolia.ui.framework.ContentClipboard</type>    <implementation></implementation>    <scope>singleton</scope>  </component>  <component>    <type>info.magnolia.ui.vaadin.editor.PageEditorView</type>    <implementation>info.magnolia.ui.vaadin.editor.PageEditorViewImpl</implementation>  </component> </components>  

Bootstrapping URI2RepositoryMapping

We make the second change by adding the URI2RepositoryMapping. To activate the change when starting the environment we use the bootstrap mechanism of the Maven module.

File: blog-preview-config/src/main/resources/mgnl-bootstrap/blog-preview-config/config.server.URI2RepositoryMapping.mappings.event.yaml

  'event':  'URIPrefix': '/events-app'  'handlePrefix': ''  'repository': 'events'  

Creating the Preview Subapp for Events

Now that all necessary parts are in place, we can create the actual preview subapp for the events app. The following code changes are particularly interesting:


We define an action that calls our preview subapp defined below.

Action bar:

In the Action bar, we activate the previously defined ShowPreview action.

Detail subapp:

In the details subapp, we add a hidden property 'mgnl:template' with the default value 'blog-preview-light:pages/event' for each newly created event. This is the magic that allows us to use the rendering engine of the web application.

Preview subapp:

In the preview subapp, we define the ‘extensionViews’ from the Magnolia Pages app as well as some actions in the action bar. The 'extensionViews' are responsible for displaying, for example, the language changer in the lower area of the preview.

File: blog-preview-light/templates/pages/event.yaml

  !content-type:events name: events-app label: Events subApps:  browser:    actions:      showPreview:        $type: openDetailSubappAction        label: Show preview        icon: icon-view        viewType: view        appName: events-app        subAppName: preview        availability:          writePermissionRequired: true          nodeTypes:            event: event    actionbar:      sections:        item:          groups:            addActions:              items:                showPreview: {}  detail:    label: Event    form:      properties:        mgnl:template:          $type: hiddenField          defaultValue: 'blog-preview-light:pages/event'  preview:    class:    extensionViews:      title:        class:      status:        class:      link:        class:      language:        class:    itemProvider:      $type: jcrNodeFromLocationProvider    actions:      activate:        $type: jcrCommandAction        icon: icon-publish        catalog: default        command: publish        params:          recursive: true        availability:          writePermissionRequired: true          rules:            isPublishable: &isPublishable              $type: jcrPublishableRule      deactivate:        $type: jcrCommandAction        icon: icon-unpublish        catalog: default        command: unpublish        availability:          writePermissionRequired: true          rules:            isPublishable: *isPublishable            notDeleted:              $type: jcrIsDeletedRule              negate: true            isPublished:              $type: jcrPublishedRule    actionbar:      sections:        previewActions:          label: Preview actions          groups:            publish:              items:                - name: activate                - name: deactivate          availability:            rules:              inPreview:                class:  

Congratulations! If you now start your server and open the Events app, you can preview your events.


You might notice, though, that the preview tab does not display the name of the event node. Let’s see how we can fix this.

Displaying the Node Name in the Preview

To show the node name in the preview tab, we have to leave the world of Light Development and do a little Java customization. This change is necessary because the default behaviour of title generation does not work for Content Types.

Creating a Custom DetailDescriptor

First, we create a DetailDescriptor to make our subapp known.

File: blog-preview-config/src/main/java/info/magnolia/blog/preview/preview/

  package;   import;   public class NodePreviewDetailDescriptor extends PageDetailDescriptor {      public NodePreviewDetailDescriptor() {        setSubAppClass(NodePreviewDetailSubApp.class);    } }  

Creating a Custom DetailSubApp

In the DetailSubApp we override the getCaption method to create the node title in a preview tab.

File: blog-preview-config/src/main/java/info/magnolia/blog/preview/preview/

  package;   import; import; import; import; import; import info.magnolia.ui.contentapp.detail.ContentDetailSubApp; import info.magnolia.ui.vaadin.editor.PageEditorView;   import javax.inject.Inject;   public class NodePreviewDetailSubApp extends PageDetailSubApp {      private final PageEditorStatus pageEditorStatus;      @Inject    public NodePreviewDetailSubApp(SubAppContext subAppContext, PageDetailDescriptor subAppDescriptor, ContentDetailSubApp.LocationContext locationContext, MoveComponentContext moveComponentContext, PageEditorStatus pageEditorStatus, PageEditorView pageEditorView) {        super(subAppContext, subAppDescriptor, locationContext, moveComponentContext, pageEditorStatus, pageEditorView);        this.pageEditorStatus = pageEditorStatus;    }      @Override    public String getCaption() {        return pageEditorStatus.getNodePath().substring(pageEditorStatus.getNodePath().lastIndexOf('/') + 1).trim();    } }  

Updating the Preview Subapp Class

Finally, we change the events app’s definition. Instead of using the default class we define the new class in line 33.

File: blog-preview-light/templates/pages/event.yaml

  subApps:  [...]  preview:    class:  [...]  

This is what the preview tab now looks like:


Creating a Preview for Content App is Easy and Helps Authors

With relatively simple means, it is possible to preview any content quickly. A preview for Content apps can really improve the editorial experience. Authors can check how their content will look in just one click, saving time and nerves.

About the Author

Tobias Kerschbaum Solution Architect at Magnolia

As a solution architect, Tobias works closely with customers and partners, sharing his knowledge and expertise. He helps organizations evaluate and understand how Magnolia can meet project requirements. He contributes to the project plan and ensures the right modules and technologies are chosen. Besides delivering tailored workshops, Tobias also gets involved when customers and partners need to implement new functionality or custom requirements.

Read more