
Creating Custom Cloud Macros 101
Can’t find a macro you need on Confluence Cloud? Join Bobby and Jessie to learn the easiest way to create your own, using ScriptRunner.

Available on-demand
If there's a macro you're craving that doesn't exist in Confluence Cloud: you're in the right place.
In this session, you'll get a walkthrough of how to create your own custom macros, using ScriptRunner.
Get a guided look at:
- What the Custom Macro feature on ScriptRunner is and how you can use it.
- Live scripting and a guided walk-through to build 2-3 useful macros from real customer use cases.
- A copy of the macro scripts so you can use them on your own instance.
Watch this can't-miss session now!
Who's leading this 101?

Jessie Wang
Senior Product Marketing Manager

Bobby Bailey
Senior Customer Success Manager, ScriptRunner
Bobby is a Senior Customer Success Manager and a ScriptRunner extraordinaire!
Resources
Here are all the resources mentioned in the demo.

Script library
Discover even more ready-to-use scripts in our script library.
User Data: Provides the User ID and Email Address of the user selected in the parameters.
def userAccountId = parameters['User'] as String
def userDataURI = "/wiki/rest/api/user?accountId=${userAccountId}"
def userData = get(userDataURI)
.header("Accept", "application/json")
.asObject(Map).body
def macroOutput = ("<p><strong>Data for : </strong>${userData.publicName}</p>"
+ "<p><strong>User ID : </strong>${userData.accountId}</p>"
+ "<p><strong>Email Address : </strong>${userData.email}</p>")
macroOutput = ('<ac:structured-macro ac:name="info" ac:schema-version="1" ac:macro-id="59b88725-71ee-4e2a-903f-7860cdbac9a9"><ac:rich-text-body>'
+ macroOutput +
'</ac:rich-text-body></ac:structured-macro>')
return macroOutput
Label Report: Outputs a table with a count of the specified labels in an instance.
def label = parameters.Label
def labelDataURI = "/wiki/rest/api/label?name=${label}"
def labelData = get(labelDataURI)
.header("Accept", "application/json")
.asObject(Map).body
def labelId = labelData['label']['id']
def pageDataURI = "/wiki/api/v2/labels/${labelId}/pages"
def pageData = get(pageDataURI)
.header("Accept", "application/json")
.asObject(Map).body
def numberOfPages = 0
def macroOutput = ('<table data-layout=\"default\" ac:local-id=\"57400373-37bd-4d1a-a65d-c1385048e5e9\"><colgroup><col style=\"\" />'
+'</h3><table data-layout=\"default\" ac:local-id=\"57400373-37bd-4d1a-a65d-c1385048e5e9\"><colgroup><col style=\"\" />'
+ '<col style=\"\" /><col style=\"\" /></colgroup>'
+ '<tbody><tr><th><p><strong>Page Title</strong></p></th><th><p><strong>Space</strong></p></th><th><p><strong>Owner</strong></p></th></tr>')
pageData.results.each{ curPage ->
def ownerId = curPage['ownerId'] as String
def spaceId = curPage['spaceId']
logger.info(ownerId)
def spaceInfoUri = "/wiki/api/v2/spaces/${spaceId}"
def spaceInfo = get(spaceInfoUri)
.header("Accept", "application/json")
.asObject(Map).body
def userInfoUri = "/wiki/rest/api/user?accountId=${ownerId}"
def userInfo = get(userInfoUri)
.header("Accept", "application/json")
.asObject(Map).body
macroOutput = macroOutput + '<tr>'
macroOutput = macroOutput + ("<td><ac:link><ri:page ri:content-title='${curPage['title']}'/>${curPage['title']}</ac:link></td>"
+"<td>${spaceInfo['name']}</td>"
+"<td>${userInfo['publicName']}</td>")
macroOutput = macroOutput + '</tr>'
++numberOfPages
}
macroOutput = (macroOutput + '</tbody></table>')
macroOutput = ("<p>Number of Pages: ${numberOfPages}</p>" + macroOutput)
macroOutput = ("<p>Label report for label : ${parameters.Label}</p>" + macroOutput)
return macroOutput
Page Info V2: Outputs metadata of a page (e.g. Title, Created Date, Status, Owner), with the option to specify which page the metadata comes from.
import java.text.SimpleDateFormat;
import java.text.DateFormat;
def pageOption = parameters['Page'] as String
def informationType = parameters['Information Type'] as String
def curPageId = parameters.pageId as String
def pageToReadId = ''
boolean directId = false
def macroOutput = ''
logger.info(pageOption)
logger.info(informationType)
logger.info(curPageId)
// Check for ID
if(pageOption.isNumber()){
pageToReadId = pageOption
directId = true
} else {
// Check for other options
switch(pageOption){
case '$parent':
def curPageUri = "/wiki/api/v2/pages/$curPageId"
def curPageInfo = get("$curPageUri")
.header('Content-Type', 'application/json')
.asObject(Map).body
pageToReadId = curPageInfo['parentId']
break;
default:
macroOutput = 'Page option not recognised'
break;
}
}
logger.info(pageToReadId)
def pageUri = "/wiki/api/v2/pages/$pageToReadId"
def pageInfo = get("$pageUri")
.header('Content-Type', 'application/json')
.asObject(Map).body
switch(informationType){
case 'Title':
macroOutput = pageInfo.title as String
break;
case 'Created Date':
def date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").parse(pageInfo.createdAt as String)
def changed = new SimpleDateFormat("dd/MM/yyyy").format(date)
macroOutput = changed
break;
case 'Status':
macroOutput = pageInfo['status'] as String
break;
case 'Owner':
def ownerId = pageInfo['ownerId']
def ownerUri = "/wiki/rest/api/user?accountId=${ownerId}"
def ownerInfo = get("$ownerUri")
.header('Content-Type', 'application/json')
.asObject(Map).body
macroOutput = "<ac:link><ri:user ri:account-id='${ownerInfo.accountId}'/>${ownerInfo.publicName}</ac:link>"
break;
default:
macroOutput = "Information Type option not recognised"
break;
}
return """
<p> ${macroOutput} </p>
"""