Magnolia 5.7 reached extended end of life on May 31, 2022. Support for this branch is limited, see End-of-life policy. Please note that to cover the extra maintenance effort, this EEoL period is a paid extension in the life of the branch. Customers who opt for the extended maintenance will need a new license key to run future versions of Magnolia 5.7. If you have any questions or to subscribe to the extended maintenance, please get in touch with your local contact at Magnolia.

In this tutorial, you learn how to create and use content types, how to create a content app based on a content type, how to adapt the app defaults and how to localize it. All the features developed within the tutorial will be part of a Magnolia light module.

The tutorial is suitable for beginners. However, if you are completely new to Magnolia, we recommend you try the Hello Magnolia tutorial first.

We assume that the computer you use to follow this tutorial has Java and Magnolia CLI installed on it.

The Hello Magnolia tutorial can guide you through installing both.

Overview

What is a content type?

A Magnolia content type is a formal definition for a type of content in Magnolia including the properties the type may contain and its relationships to other types of content. A content type is configured in a content type definition that includes the data source definition and the model definition.

Content type items can be managed by a content app. The content can be embedded into web pages or served via REST in a headless approach.

Use case

Magnolia Travels is a travel agency that employs many tour guides. The marketing department of Magnolia Travels wants to promote their popular tour guides on their website as well as on other channels. They decide to record the following information for each tour guide:

  • Name
  • Birthdate
  • Gender
  • Short biography

Your tasks

To begin, you need a Magnolia bundle where you will create a new light module to contain your code. 

You will then configure a content type definition to map the given use case. Then you will create a content app, referring to the content type definition, to manage data for the tour guides. 

Installing a Magnolia bundle and creating a light module

You need a Magnolia bundle where you will create a new light module to contain your code. 

Setting up the Magnolia bundle

Make sure you install Magnolia 6.0+.

Magnolia 6.0+ contains the magnolia-content-types module, which is required to work with content types.

In this section, you use Magnolia CLI to install and start a preconfigured Magnolia bundle. If you do not have Magnolia CLI, install it as described here

To install Magnolia:

  1. Use the shell and change to the directory to where you want to install the Magnolia bundle. In our example, we use the directory ~/dev/mgnl-bundles/content-types-tutorial:

    cd ~/dev/mgnl-bundles/content-types-tutorial
  2. Execute the Magnolia CLI jumpstart command. Choose the magnolia-community-demo-webapp when prompted.

    mgnl jumpstart

    Jumpstart downloads and extracts the magnolia-community-demo-webapp that comes with Tomcat server. 

    The following files and folders are created:

    content-types-tutorial/
    ├── apache-tomcat/
    ├── downloads/
    └── light-modules/
  3. In the ~/dev/mgnl-bundles/content-types-tutorial directory, execute the Magnolia CLI start command:

    mgnl start

    When starting for the first time, Magnolia runs a web update and automatically installs all its modules.

In your preferred browser, open the URL http://localhost:8080/magnoliaAuthor/ and log in as user superuser with the password superuser. Have a look around Magnolia. Access the public instance with the URL http://localhost:8080/magnoliaPublic/.

Creating a light module

The light module serves as a container to which you will add the definitions for content types and for the apps based on those content types.

Use the shell and change into the light-modules directory. 

cd ~/dev/mgnl-bundles/content-types-tutorial/light-modules

You could use the Magnolia CLI create-light-module command to create the light module. However, since we will only use a reduced set of the subfolders which would be created by the CLI, let's do it manually instead.

Create the following folder structure:

light-modules/
└── content-type-examples/
    ├── apps/
    ├── contentTypes/
    └── i18n/

All the files you create in the following sections will go into these folders.

Defining a content type for a tour guide

In this step, you create the content type definition

Create the file /content-type-examples/contentTypes/tourGuide.yaml. The file must be in the light module subfolder contentTypes. Magnolia scans this directory for content type definitions. If the file is syntactically correct, Magnolia registers the defined items.

A content type definition requires a model and a datasource.

Defining the model

Start with the model definition. In the model, you define the properties of a content item.

Following our use case, add this snippet to the tourGuide.yaml file:

model:
  nodeType: mt:tourGuide
  properties:
    - name: birthday
      type: Date
    - name: gender
    - name: shortBio

  • Add one entry to the properties list for each characteristic of a tour guide. Each entry should start with a name.
  • Specify the type for each property. Possible types are:  String (default), BooleanDecimalDoubleLongDate, or another content type or submodel.
  • (warning) Note that we have not defined a property named name even though our use case states that we should store the names of the tour guides. We capitalize on a feature that automatically creates a name property for the app to manage the content type.
  • Ignore the nodeType on the second line for the time being.

Defining the data source

The data source definition defines how content type items are persisted. 

The Magnolia content type framework is data source agnostic, but Magnolia's default implementation uses JCR to persist the data. That's why you should be aware of a few basics concerning JCR.

Understanding JCR basics - node type, namespace and workspace

Storing data in JCR requires: a registered workspace; a defined and registered node type; and the node type may use a namespace that must be registered too.

  • Workspace – The workspace is a container which stores JCR nodes in a tree-like structure. A workspace has a name. (See Workspaces for a list of some predefined Magnolia workspaces.)
  • Node type – A node stores an item of a certain type. Nodes contain properties. A node type defines the nature of a node, it has a name, which typically starts with namespace:. (See Node types for a list of some predefined Magnolia node types.)
  • Namespace – The namespace indicates a certain domain. Node types that belong to the same domain share the same namespace. The namespace nt is used for node types provided by the JCR implementation, mgnl is the namespace for most of the Magnolia-specific node types.

Best practice

A Magnolia bundle comes with several predefined and registered workspaces and node types. However, in most cases, we recommend you use:

  • Different workspaces and node types for different content types.
  • A different namespace for different domains of your content types.

Defining a namespace, node type and workspace for the tour guide content items

Define a distinct namespace, node type definition and workspace for the use case.

Note that you can define and register namespaces, node types and workspaces in different ways

In this tutorial, we will define them in a single YAML file: the content type definition file. This approach is fast and suitable for many use cases.

NamespacemtStands for Magnolia Travels. Use this namespace for all items related to the domain of Magnolia Travels.
Node type namemt:tourGuideThe name of a node to store the data for a tour guide.
Workspace nametourguidesThe workspace to store the mt:tourGuide nodes.

Now we define the data source:

datasource:
  workspace: tourguides
  namespaces:
    mt: https://www.magnolia-travel.com/jcr/1.0/mt
  autoCreate: true

  • workspace – The name of the JCR workspace to store the content items. 
  • namespaces – A list of JCR namespace names. 
  • autocreate – If set to true, both the workspace and the namespaces will be registered by the system, if they have not been registered yet.

The complete content type definition

This is the complete content type definition with both the model and the dataSource:

/content-type-examples/contentTypes/tourGuide.yaml
datasource:
  workspace: tourguides
  namespaces:
    mt: https://www.magnolia-travel.com/jcr/1.0/mt
  autoCreate: true
  
model:
  nodeType: mt:tourGuide
  properties:
    - name: birthday
      type: Date
    - name: gender
    - name: shortBio

  • Line 8, nodeType: The name of the JCR node type for storing an item of the given content type. If nodeType is not provided, mgnl:content is used by default.

Checking the content type definition in the Definitions app and the workspace in the JCR app

If your Magnolia instance is still running and if you have added the content type definition file in the correct location in a light module known to Magnolia, you can now check the content type in the Definitions app.

Now open the JCR Browser app. In the dropdown you can see that a workspace with the name tourguides has been created. (But no content has been added yet.)

 

Editing content type definitions

You can edit content type definitions while Magnolia is running. The system detects the changes and updates the definition. 

Be careful when editing:

  • Develop and refine content type definitions in a development environment. Avoid editing content type definitions in a production environment.
  • Changing the JCR-related parameters of a content type definition may have extensive consequences:
    • Changing the name of a workspace will unregister the old workspace and register the new one. However, the old workspace will not be completely deleted. (See How to delete a JCR workspace).
    • Changing a node type unregisters the old node type and registers a new one. Data created with the old node type then becomes difficult to edit. You may have to migrate it if you rely on it.

Creating a content app based on the content type

With just a content type definition, you cannot manage content items of the defined type. In this section you will create a Magnolia content app to create, edit and delete tour guide items.

What is a content app?

Content app is a specialized app type for managing structured content. The content app user interface consists of a browser subapp and one or more detail subapps. Content apps make it easy to enter items such as products or events. Many native Magnolia apps such as Tours and Contacts are content apps. Because this app style is used often, the framework provides convenience classes to make building a content app faster.

Starting the app

Add an app launcher tile to make it easier to start the app.

Adding an app launcher tile

To add a tile to the app launcher:

  1. Open the Configuration app.
  2. Duplicate the node /modules/ui-admincentral/config/appLauncherLayout/groups/edit/apps/contacts and rename the newly created node to tourGuides-app (must be the name of the app).
  3. Restart your Magnolia session by logging out and in again.
    The app launcher tile is displayed.

Click the tile to start your app.

Adding translations

The app does not have any user interface labels yet. To fix this, add a messages file to the i18n folder.

Create the file /content-type-examples/i18n/content-type-examples_backend-messages_en.properties:

/content-type-examples/i18n/content-type-examples-backend_en.properties
#
# app "tourGuides-app"
#
tourGuides-app = Tour guides
tourGuides-app.default.label =
tourGuides-app.default.name.label  = Name
tourGuides-app.default.birthday.label = Birthday
tourGuides-app.default.gender.label = Gender
tourGuides-app.default.shortBio.label = About
tourGuides-app.browser.label = Tour guide
# actionbar
tourGuides-app.browser.actionbar.sections.root.label=Guides
tourGuides-app.browser.actionbar.sections.folder.label=Folder
tourGuides-app.browser.actionbar.sections.item.label=Guide
# actions
tourGuides-app.browser.actions.addItem.label=Add guide
tourGuides-app.browser.actions.editItem.label=Edit guide
Close the app and open it again. UI labels are now displayed.

Overriding the auto-generated app descriptor parts

Default app creation patterns

With the minimal app definition shown above, the generated app has a default set of features. The precise generated structure can be seen in the Definitions app.

Here is an overview of what is generated:

  • Two subapps: browser and detail.
  • The editor of the browser subapp has a single form with one tab named default.
  • The editor displays a field for each property in the content type model. Depending on the attributes of a model property, the form renders different fields:

    Model property attributeEditor displays
    type: String (default)Text field
    type: DateDate field
    type: BooleanCheckbox field
    type: <content-type name>Link field
    type: <submodel name>Composite field
    multiple: trueMultivalue field

If <content-type-definition>/model/properties/ does not contain a property with name: name, the app generator automatically adds this property.
The value given to the name property is also used to deduce a feasible JCR node name.
Example: 

  • Value of the name property: John Miller
  • Deduced JCR node name: John-Miller

The generated app structure provides a standard starting point that you can adapt.

This is what the detail editor looks like with the default generated form:

Overriding the defaults

To improve the standard form, we will make the following changes:

Add additional configuration which will overwrite any configuration with the same name coming from the !content-type directive.

Here is the customized app definition:

/content-type-examples/apps/tourGuides-app.yaml
!content-type:tourGuide
name: tourGuides-app
#
subApps:
  detail:
    editor:
      form:
        tabs:
          default:
            fields:
              - name: shortBio
                fieldType: richText
              - name: gender
                fieldType: select
                options:
                - name: female
                  value: female
                - name: male
                  value: male
                - name: other
                  value: other
Create the path to the item that you want to adapt, then adapt the item by changing properties or adding new ones.

  • Lines 11, 12: For the field shortBio, set the fieldType to richText.
  • Lines 13, 14: For the field gender, set the fieldType to select.
  • Lines 15-21: Provide the required options property for the select field.

Save the file, then close and reopen the app tourGuides-app.

Note that the options for the select field must be translated. Make sure you have these lines in the i18n file /content-type-examples/i18n/content-type-examples-messages_en.properties:

tourGuides-app.default.gender.options.female = Female
tourGuides-app.default.gender.options.male = Male
tourGuides-app.default.gender.options.other = Other

When overriding the app descriptor, if you make a typo or another error, the Definitions app Problems tab indicates the error.

If you have to fix an error on the app descriptor:

  • Fix the issue and save the app descriptor file.
  • You may also have to touch the content definition file to trigger the app generation process again.

(thumbs up) Congratulations.

You have just created your first content type and built a customized app to manage the content type items.

Create a few tour guides before you proceed with Part II - Complex content types and security set up.