Macro Transformation

Last modified by Eleni Cojocariu on 2026/10/13 18:18

Explanation

The macro transformation is the rendering transformation that executes macros. It walks the XDOM a parser produced, looks up the component registered under each macro call, runs it, and puts the blocks it returned in the place of the call. Rendering Macros describes what a macro is made of; this page describes the engine that runs it.

The Transformation That Runs First

Several transformations can run over the same XDOM, and rendering.transformations decides which, as Rendering Transformations describes. They run by priority, and the macro transformation declares 100, low enough to be among the first, so that the transformations after it see the content the macros produced rather than the calls.

Finding the Next Macro to Execute

The transformation does not walk the tree in reading order. It collects the macro calls that have a macro registered for the syntax being rendered into a queue ordered by macro priority, and takes the lowest first. Each result goes back into the tree rather than into the output, so the queue can still grow while it is being drained.

What happens after each execution depends on the promise the macro made. A macro that declared its execution isolated cannot have inserted a call anywhere else, so only the blocks it returned are scanned and added to the queue. Any other macro forces a full rescan of the XDOM, because a call may now sit anywhere in it. Macro Execution Rules covers that promise from the macro's side.

The loop is bounded. The transformation counts the executions of macros that were themselves produced by another macro and stops after 1000 of them, so a macro generating itself leaves unexecuted content behind instead of hanging the request.

The component the transformation asks for each call is described in Macro Transformation API.

When a Macro Does Not Run

Four things stop a macro, and each of them replaces the call by an error block in the page rather than failing the rendering.

What happenedWhat the page shows
No macro is registered under that name, for this syntax or for all syntaxesAn unknown macro error naming the id, so a misspelled macro name is visible where it was written
The call sits inside a paragraph or a list item and supportsInlineMode returns falseA standalone macro error explaining that the macro needs a line of its own
A parameter value cannot be converted into the parameters beanAn invalid parameters error carrying the conversion failure
execute throws anything at allA failed to execute error carrying the cause

One broken macro therefore costs its own block, never the page. The single exception is a macro that takes its own call out of the XDOM, as a deprecated macro handing over to its successor does.

The Context a Macro Receives

execute is given a MacroTransformationContext, which carries what the macro cannot read from its own parameters and content.

MemberWhat a macro reads it for
getCurrentMacroBlock()Its own call, to read a raw parameter or to find where in the page it sits
getXDOM()The whole document being transformed
isInline()Whether the call sits inside a paragraph, so the macro can return inline blocks
getTransformation()The running transformation, for a macro that has to transform content of its own, as the include macro does
getTransformationContext()The syntax being rendered and the restricted flag

Reaching the Rendering in Progress from Anywhere

A component that is not a macro reads the same state through the RenderingContext role: the syntax, the target syntax, the document being rendered and the macro call currently executing. It is the supported way for code outside a macro to know that a rendering is under way and in what state.

That context is set by the default TransformationManager as it drives the transformations. Code that executes a Transformation directly leaves it unset, and no public API sets it. Go through the TransformationManager whenever a transformation has to be run.

FAQ

Why is the result of a macro wrapped in an extra block?

The transformation wraps the blocks a macro returned in a macro marker block, which keeps the original call beside its result. That is what lets the XWiki Syntax renderer write the macro call back out after the WYSIWYG editor has edited the page.

Can I execute macros over content myself?

Yes, through the TransformationManager, or from inside a macro through MacroContentParser with transformations enabled.

Why is a macro I wrote below another one executed first?

Because the queue is ordered by macro priority and not by position in the page.

More

To find more about the current topic, you can search or use the table below and filter the columns to narrow your choices.

Related

Get Connected