Component inheritance

Inheritance causes components from parent pages to be automatically rendered on the current page too.

  • It saves editors time and effort, and it helps display content consistently across the site. For example, inheritance is often used for a page header or a page footer.

  • It can be used for promotional content that changes often, such as in a "sidebar" or "extras" area. When an editor updates the content on the home page, it updates everywhere in the entire page hierarchy.

  • It is also useful within a section of a site, for example, a subpage of the home page could have a "section" area with an offer only relevant to this section of the website. Content in the area will appear on every subpage of the section page, but not on the home page or on other sections.

Inheritable components diagram

Inheritance behavior

By default, inheritance behaves like this:

  • Editable in parent only: Inherited components can be edited only on the parent page. They don’t have toolbars on child pages.

  • Order is inherited: Inherited components are displayed in the same order on parent and child pages.

  • Inherited first: Inherited components are displayed before non-inherited components in the same area.

Understanding inheritance

While we speak of component inheritance, an entire area is inherited, which is why "Area inheritance" would be more accurate.

The components of the area in all parent pages are inherited, but so are any content properties that might be on the top parent area. This is only relevant if the area has a dialog configured to store properties on the area itself.

Inheritance works bottom up. When an area is rendered, and it has inheritance enabled, then the renderer looks to each of the ancestor pages and gets the content from the areas with the same name, and renders them in the current page. So, on the home page, nothing happens because the page has no ancestor pages. In a child page, the renderer finds the parent pages and includes their content on the current page.

The content from the parent page is only rendered. It is not editable on the current page.

Use inheritance on an area on a page definition. This is the typical use case.

  • For example, an "extras" area.

  • Editors can add additional components to the area on subpages.

  • Or use inheritance on multiple areas on a page: like "extras-list-1", "extras-list-2".

Use inheritance on an area on a page, but only allow a single component.

  • This is useful for a "footer" or "header".

  • The component can be sophisticated, for example, including an area itself.

Avoid using multiple nested levels of inheritance.

  • The inheritance feature is powerful, but can become hard to understand when inheritance is used on multiple nested content.

  • If you are confused by the behavior, try to simplify, and review the Understanding inheritance section above.

Inheritance properties

Configure component inheritance in an area definition.

Below is a simple example where all components are inherited. If you have nested areas in components, you must also configure the inheritance property both at the page level and in the nested area where you want to use inheritance.

Page level area definition
areas:
  promos:
    renderType: freemarker
    type: list
    availableComponents:
      text:
        id: my-module:components/text
      relatable-content:
        id: my-module:components/relatable-content
    inheritance:
      enabled: true
      components: all

Within the promos area, there is a component for relatable content that includes a guest blog area. An example nested area definition for a guest blog area in such a relatable-content component is shown below. In this nested area example, the components property is set to filtered so that authors can choose whether or not to display components on subpages (see Implementing filtering for more details).

Nested area definition
title: Relatable content
renderType: freemarker
templateScript: /my-module/templates/components/relatable-content.ftl
dialog: my-module:components/relatable-content

areas:
  guest-blog:
    templateScript: /my-module/templates/areas/blogs.ftl
    type: list
    availableComponents:
      blog:
        id: my-module:components/blog
    inheritance:
      enabled: true
      components: filtered
Property Description

enabled

optional, default is false

true enables component inheritance in the area.

components

optional, default is filtered

Defines which components are inherited to child pages.

Valid values:

properties

optional, default is all

Inherits area properties such as title and description to child pages. This is useful when you want to inherit just the area configuration, not its content.

Valid values:

  • all : All area properties are inherited.

  • none: No area properties are inherited.

nodeComparatorClass

optional, default is info.magnolia.rendering.template.configured.ConfiguredInheritance.NodeDepthComparator

Defines the order in which inherited components are displayed on the child page. The default NodeDepthComparator follows the order of nodes in the JCR repository. Nodes higher up in the hierarchy are displayed before nodes deeper down. Nodes on the same level are displayed as siblings. This means that inherited components are displayed in the same order on parent and child pages by default. You can implement a custom nodeComparatorClass to change the sort order. Set the property to a fully qualified class name.

nodeTypes

optional, default are mgnl:component and mgnl:resource

A list of content node types that can be returned.

predicateClass

optional, default is info.magnolia.rendering.template.configured.FilteredInheritancePredicate

In Java, predicate is a functional interface that returns either true or false. Here, we use a predicate to decide whether a component or property should be inherited or not. The default info.magnolia.rendering.template.configured.FilteredInheritancePredicate checks whether inheritance is enabled and how the components and properties are set, then it makes the decision. You can implement a custom predicate class that makes the decision based on some other variables. Set the property to a fully qualified class name.

Specific configuration scenarios

Implementing filtering through the inheritable property

Filtering can be achieved by using the inheritable property, which is read at render time. In this case, component inheritance includes only nodes with a property named inheritable that needs to be present and set to true (info.magnolia.rendering.template.configured.FilteredInheritancePredicate).

The inheritable property must be set on the dialog of the component that should be inheritable.

Example: Inheritable as checkbox field

The following configuration allows you to switch inheritance for components with a checkbox field.

<module-name>/dialogs/components/disclaimer.yaml
form:
  properties:
    heading:
      $type: textField
      label: Heading
    text:
      $type: richTextField
      label: Disclaimer Text
    inherit:
      name: inheritable (1)
      $type: checkBoxField
      label: Inherit
      buttonLabel: Inherited by Subpages
      defaultValue: true (2)
1 The property must be named inheritable.
2 Set defaultValue to true.

Example: Inheritable as hidden field

This variant allows you to switch inheritance for components with a hidden field. The configuration makes the component always inherited, the component cannot be changed.

<module-name>/dialogs/components/disclaimer.yaml
form:
  properties:
    heading:
      $type: textField
      label: Heading
    text:
      $type: richTextField
      label: Disclaimer Text
    inherit:
      name: inheritable
      $type: hiddenField
      defaultValue: 'true' (1)
1 In this configuration, the value of defaultValue is a String ('true' with single quotes, as opposed to just true in the previous example) because hiddenField expects a String, not a Boolean value.

Returning area contents when area has content subnodes

In some cases, you want to retrieve the content of the area itself. By default, only single properties are inherited. Content subnodes (such as a multi field, composite field, or switchable field) that are relevant to the area’s dialog are not returned.

You can configure the inheritance to return them by adding the contentNode node type, as shown at the end of the following example.

inherit-lm/templates/pages/inherit-freemarker.yaml
title: 'Inherit Freemarker'
dialog: inherit-lm:components/basic

templateScript: /inherit-lm/templates/pages/inherit-freemarker.ftl
renderType: freemarker
visible: true

areas:
  inheritOnNestedAreaWithComposite:
    title: Inherit ON (Nested Area With Composite)
    templateScript: /inherit-lm/templates/components/area-with-area-and-composite.ftl
    dialog: inherit-lm:components/basic-with-composite
    inheritance:
      enabled: true
      components: all
      nodeTypes:
        - mgnl:contentNode

Component inheritance in SPA

Component inheritance in SPA is not fully supported as in FreeMaker. This is because JSON responses from the Delivery endpoint can’t have identically named siblings.

For more details about this and other limitations, see Component autogeneration and inheritance in the Headless Docs.

For this usage, the endpoint must be configured with $type: jcrPagesDeliveryEndpoint_v2.

Example definitions

See the component-inheritance-examples repository for examples of component inheritance in FreeMarker and headless/SPA projects.

Related topics
Feedback

DX Core

×

Location

This widget lets you know where you are on the docs site.

You are currently perusing through the DX Core docs.

Main doc sections

DX Core Headless PaaS Legacy Cloud Incubator modules