Confluence Docs 3.0 : Writing Macros This page last changed on Jun 25, 2009 by cjerozal. Macros are written and deployed into Confluence as Macro Plugins. This page describes how to write a macro (but not how to get the plugin working, refer to the other page for that). ### First steps Make sure you have created your first macro plugin using our description over here. That will save you a lot of time. ### The Macro Class All macros must implement the `com.atlassian.renderer.v2.macro.Macro` interface. The Javadoc comments are probably the best place to start: http://docs.atlassian.com/atlassian-renderer/latest/apidocs/index.html?com/atlassian/renderer/v2/macro/Macro.html
| The BaseMacro class While it's not a requirement, your macro should extend the `com.atlassian.renderer.v2.macro.BaseMacro` abstract class. This class does not contain any functionality, but if the `Macro` interface changes in the future, the `BaseMacro` class will be maintained in order to ensure backwards compatibility with existing macros.
### Writing Your Macro When writing a macro, you will need to override the following methods:
Method | Should return...
--- | ---
hasBody() | `true` if this macro expects to have a body, false otherwise
getBodyRenderMode() | The `RenderMode` under which the body should be processed before being passed into the macro
isInline() | `false` if the macro produces a block element (like a paragraph, table or div) true if it is inline and should be incorporated into surrounding paragraphs
execute() | a fragment of HTML that is the rendered macro contents
### Understanding `RenderMode` The `RenderMode` tells the Confluence wiki renderer which wiki-conversion rules should be applied to a piece of text. Once again, the best place to start is the Javadoc: http://docs.atlassian.com/atlassian-renderer/latest/apidocs/index.html?com/atlassian/renderer/v2/RenderMode.html There are a number of pre-defined render modes. The ones that would be useful to macro writers are probably:
Mode | Description
--- | ---
`RenderMode.ALL` | Render everything
`RenderMode.NO_RENDER` | Don't render anything: just return the raw wiki text
`RenderMode.INLINE` | Render things you'd normally find inside a paragraph, like links, text effects and so on
`RenderMode.SIMPLE_TEXT` | Render text made up only of paragraphs, without images or links
If you want finer control, `RenderMode` is implemented as a bit-field. Each constant of `RenderMode` starting with `F_` is a feature of the renderer that can be turned on or off. You can construct a RenderMode by manipulating these bits through the following methods:
Method | Description | Example
--- | --- | ---
`RenderMode.allow()` | Allow only the renderings specified | `RenderMode.allow(RenderMode.F_LINKS || RenderMode.F_HTMLESCAPE)` will only render links, and escape HTML entities.
`RenderMode.suppress()` | Allow all renderings except those specified | `RenderMode.suppress(RenderMode.F_MACROS || RenderMode.F_TEMPLATE)` will render everything except macros and template variables
`and()` | Perform a logical AND on an existing render mode | `RenderMode.SIMPLE_TEXT.and(RenderMode.suppress(RenderMode.F_PARAGRAPHS))` will render SIMPLE_TEXT without paragraphs
`or()` | Perform a logical OR on an existing render mode | `RenderMode.SIMPLE_TEXT.and(RenderMode.allow(RenderMode.F_MACROS))` will render SIMPLE_TEXT with macros
| Many macros (like this note macro) produce a `div`. Often, if there's only one line of text within a div, you don't want it surrounded in paragraph tags. For this reason, the `RenderMode.F_FIRST_PARA` flag controls the first line of wiki text that is rendered. If `F_FIRST_PARA` is not set, and the first line of text is a paragraph, the paragraph tags will not be rendered.
### How to determine the context your macro is being rendered in One of the parameters to the execute() method, the one with type RenderContext, can be used to determine how the macro is being rendered. See the relevant Confluence Developer FAQ entry for the details. ### Accessing the Rest of the System Like all Confluence plugin modules, Macros are autowired by the Spring framework. To obtain a manager object through which you can interact with Confluence itself, all you need to do is provide a Javabeans-style setter method for that component on your `Macro` class. See Accessing Confluence Components From Plugin Modules ### Advanced Macro Techniques Macros are often most powerful when combined with other plugin modules. For example, the {livesearch} macro uses an XWork plugin to perform its server-side duties, and the {userlister} plugin uses a listener plugin to listen for login events and determine who is online. You may also consider using a component plugin to share common code or state between macros. ### How Macros are Processed If you want to know exactly what happens when a macro is processed, the following (slightly overly-detailed) description should help: Consider the following code in a Wiki page:
    {mymacro:blah|width=10|height=20}This _is_ my macro body{mymacro}
The `MacroRendererComponent` finds the first {`mymacro:blah|width=10|height=20`} tag, and asks the `MacroManager` if a macro is currently active with the name "mymacro". The `MacroManager` returns a singleton instance of your `Macro`. The `MacroRendererComponent` calls `hasBody()` on the `Macro`. If `hasBody()` returns false, the macro is processed with a 'null' body, and the next {mymacro} tag will be processed as a separate macro. If `hasBody()` returns true, the `MacroRendererComponent` looks for the closing {mymacro}. Anything between the two becomes the macro body. If there is a macro body, the `MacroRendererComponent` then calls `getRenderMode()` on the macro to determine how that body should be rendered The macro body is processed through the wiki renderer with the given RenderMode before being passed to the macro The `MacroRendererComponent` calls `execute` on the macro, passing in the macro parameters, the (processed) body, and the current RenderMode The `execute` method should return an HTML string. No further wiki processing is performed on macro output. The parameters are a `Map` of {{String}}s, keyed by parameter name. If any parameter is not named, it is keyed by the string representation of its position: so for the above example, `parameters.get("0")` would return `"blah"`. `parameters.get(Macro.RAW_PARAMS_KEY)` will return the raw parameter string, in this case: `"blah|width=10|height=20"` The `MacroRendererComponent` calls `isInline()` on the macro to determine if its results should be inserted into the surrounding page as an inline (i.e. part of a surrounding paragraph) or a block element.

Document generated by Confluence on Nov 05, 2009 23:34