Macros

Contents

Macros enable editors to add rich functionality or include dynamic content in the rich text editor.

Macro instructions

A macro instruction is written in plain text. They are similar to HTML or XML tags, but uses square brackets instead of angle brackets.

A macro has a name, a set of attributes, and optionally a body:

[macroname attrib1="value1" attrib2="value2"] body [/macroname]

Sample macro without the body:

[macroname attrib1="value1" attrib2="value2"/]

A user can add macro instructions by typing in the macro manually. But more conveniently by clicking the Insert macro button and selecting one of the macros available in Content Studio.

Descriptor

A macro descriptor is an xml file that allows assigning a user-friendly name, and a description to the macro. It also has a configuration to define the types and names of the macro parameters.

display-name

A simple human readable display name.

display-name@i18n

The key to look up the display-name text in the localization bundles. Optional. Visit Schema localization for more details.

description

A description to show in the Insert macro dialog in Content Studio.

description@i18n

The key to look up the description text in the localization bundles. Optional. Visit Schema localization for more details.

config

The config element is a form where each input element corresponds to a macro parameter. The macro body is represented with an input named "body".

The config form does not support nested elements, so Item Sets are not allowed in the macro config form. Also the HtmlArea input type is not allowed in the config form, since it may contain macros itself.
If you don’t have a input with the name="body", the generated macro tag will be self closing [macro attr="" /]`

Its path follows the pattern src/main/resources/site/macros/<macroName>/<macroName>.xml

<macro>
  <display-name i18n="a-macro.display-name">Current user</display-name>
  <description i18n="a-macro.description">Shows currently logged user</description>

  <form>
    <input name="body" type="TextLine">
      <label>Macro body</label>
    </input>
    <input name="defaultText" type="TextLine">
      <label>Text to show if no user logged in</label>
    </input>
  </form>
</macro>
The macro texts (display-name, description, label and help-text from config input types) can be provided in multiple languages. Visit Schema localization for more details.

Although not strictly required, it is recommended to create a descriptor, as it provides the required details for adding macros through the UI in Content Studio.

Controller

When using the Enonic framework, optionally add a JavaScript controller to render the macro.

When using 3rd party front-end frameworks, the controller can also be used to provide a preview of the macro in Content Studio.

Its path follows the pattern src/main/resources/site/macros/<macroName>/<macroName>.js

A macro controller must export a single macro function that takes a context parameter and returns a response object (see HTTP Response).

The context parameter is a Javascript object with the following properties:

name

a string containing the macro name.

body

a string containing the body of the macro instruction.

params

an object with key-value pairs containing the macro parameters. The values are the strings from the macro instruction attributes.

document

a string with the HTML document that contains the current macro. The document contains the raw source HTML, before any macro instructions have been executed, and before image or content URLs have been resolved. The document is only an input parameter to the macro, it cannot be modified.

request

the request object.

// Example usage: [currentUser _document="__macroDocument4" defaultText="Anonymous"/]
var authLib = require('/lib/xp/auth');
var portalLib = require('/lib/xp/portal');

exports.macro = function (context) {
    var defaultText = context.params.defaultText;
    var macroBody = context.body;

    var user = authLib.getUser();
    var body = '<span>' + macroBody || (user ? user.displayName : defaultText) + '</span>';

    var doc = context.document; // HTML document containing the current macro
    var lineCount = doc.split(/\r\n|\r|\n/).length;
    if (lineCount <= 1) {
        return {
            body: ''
        }
    }

    return {
        body: body,
        pageContributions: {
            headEnd: [
                '<link rel="stylesheet" href="' + portalLib.assetUrl({path: 'css/current-user.css'}) + '"/>'
            ]
        }
    }
};

Note that only the body and pageContributions fields of the response are relevant for macro controllers.

A macro controller can also use libraries, like any other JavaScript controller.

Built-in macros

There are currently 2 built-in macros that are included in XP and available for any site:

disable

The contents (body) of this macro will not be evaluated as macros. That allows rendering another macro instruction as text without executing it. It is useful for documenting macros, for example. This macro has no parameters.

embed

It allows embedding an <iframe> element in an HTML area. This is a generic way for embedding content from an external source (e.g. YouTube videos). This macro has no parameters.

Example using the disable macro:

Example of macro instruction: [myMacro param1="value1"/]

Example using the embed macro:

A macro may optionally have its own specific icon. The icon can be assigned to the macro by adding a PNG or SVG file with the same name, in the macro folder, e.g. site/macros/myMacro/myMacro.svg

Contents

Contents