Writing Advanced User Macros

Still need help?

The Atlassian Community is here for you.

Ask the community


Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.

Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.

*Except Fisheye and Crucible

    

User macros are a great way to extend the base functionality of Confluence. In this article, we’ll build on the concepts described in the Writing User Macros article by writing macros that can pass information to other macros on the page and using conditionals.

Conditional Sections User Macro

One good case for creating a user macro would be conditionally showing or hiding sections of content depending on a predefined “ID“ at the top of the page. That way everyone can work off of one template, and automatically hide any content that isn’t relevant to them.

Design

We’re going to create two user macros that will work together to define each segment, and control which ones should be visible:

  • conditional-template-controller

    • Holds the ID of the content we want to show. It’s important to make a separate user macro for this task because we will have multiple conditional segments, but we only want to set the ID of which sections to show once.

  • conditional-template-section

    • Handles holding the content that we want to show or hide, and tag it with an ID that can be compared with the controller.

You can find the user macros page for your instance by navigating to General Configuration > User Macros.

You'll need System Administrator permissions to create and manage user macros. 

conditional-template-controller

Create the following user macro:

Macro Name

conditional-template-controller

Macro Title

Conditional Template Controller

Description

A macro that allows you to define which segments of a page should be shown.

Macro Body Processing

No macro body

Template

See code below

The controller macro sits at the top of the page and takes in a single string (ID). Sections that match the ID set here will be shown.

(warning) This macro must always be above the first template section on the page, as each macro is run in the order they are put on the page.

## Macro title: Conditional Template Controller
## Macro has a body: N
##
## Date created: 30/03/2022
##
## @param ID:title=ID|type=string|required=true|desc=The ID of the sections you would like to show|multiple=true

$renderContext.addParam("controllerPresent", true)
$renderContext.addParam("controllerShownSections", ${paramID.toString()})


Here, we are using the addParam method of $renderContext to pass the ID we set in the page editor to the render context to the page. The render context is shared by all macros on the page, which will allow the conditional-template-section macro to access our parameters.

In this case, we are adding 2 parameters to the render context:

  • controllerPresent

    • Declared to notify template sections that a controller is present on the page. If one is not present, the template sections default to showing their contents with a warning panel.

  • controllerShownSections

    • The ID that should be shown, template sections compare this value to their own to decide if they should render their content.

    • You may have noticed that we are setting this parameter to ${paramID.toString()}, $ is a special character that allows you to add logic in your user macros. Confluence’s user macro scripting is based off of the Apache Velocity templating language. You can find more information on Velocity in the official documentation, or learn about the Confluence specific objects you can use in your scripts.

conditional-template-section

Create the following user macro:

Macro Name

conditional-template-section

Macro Title

Conditional Template Section

Description

A macro that defines anything inside it as part of a "section" that can be shown or hidden based on the conditional template controller settings.

Macro Body Processing

Rendered

Template

See code below

This macro contains all the content for a given section that you want to conditionally show or hide. It takes in a single string (ID) and shows the content inside if it matches the ID set in the controller. Multiple sections can share the same ID.

We’re setting macro body processing to rendered because we want the content within the macro to be shown as though the macro is not there at all.

(warning) If you have defined sections but no controller is present, all sections will be shown with a warning.

## Macro title: Conditional Section
## Macro has a body: Y
##
## Date created: 30/03/2022
##
## @param ID:title=ID|type=string|required=true|desc=The ID used by the controller to determine which sections to show. You can specify multiple sections to have the same ID if desired.

#if( $renderContext.getParam("controllerPresent") )
   #if( $renderContext.getParam("controllerShownSections") == $paramID || $renderContext.getParam("controllerShownSections") == "all")
      <ac:structured-macro ac:name="section">
         <ac:rich-text-body>
            $body
         </ac:rich-text-body>
      </ac:structured-macro>
   #end
#else
   <p><br /></p>
   <ac:structured-macro ac:name="warning">
      <ac:rich-text-body>
         <p>The following section is designated as conditional, but there is no conditional controller present on this page.</p>
      </ac:rich-text-body>
   </ac:structured-macro>
   <ac:structured-macro ac:name="section">
      <ac:rich-text-body>
         $body
      </ac:rich-text-body>
   </ac:structured-macro>
#end


After collecting the section ID from the user we first use an if conditional to check if the controller is present using the controllerPresent parameter we set in the conditional-template-controller macro.

(lightbulb) Velocity has support for many more conditionals, operators, and loops. For further reference, check the Apache Velocity user guide.


If the controller is not present, we default to showing the contents (and a warning panel) using the else directive.

If the controller is present, we do a comparison matching the controllerShownSections parameter and the ID we set in the page editor. We also do a comparison matching the controllerShownSections and the string “all“. If either condition is true then we render the content as normal, otherwise, the macro ends.

Inside the if conditional, we are using the || (OR) logical operator. This operator combines two conditions and returns true if either condition (or both) are true. Functionally, this means that we will render our content if the IDs match OR if the controller is set to "all".

Sample Page

Here’s what a sample page might look like in the editor.

(info) In this case, everything in the accounting macro would be hidden.

Useful Links

Here's a quick collection of handy links to reference while writing user macros:


Last modified on Aug 14, 2023

Was this helpful?

Yes
No
Provide feedback about this article
Powered by Confluence and Scroll Viewport.