Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Macro removal in many pages

Normann P_ Nielsen _Netic_
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 26, 2025

Hi,

 

We have +500 pages that are affected by 

https://help.refined.com/space/MIGRATETOOLKITCLOUD/5334139038/Preparation+guide and using the old legacy editor in cloud is not a real option.

So - anyone with a good idea / tool to do some change via the databae prior to migration - like remove these parts:

Screenshot 2025-03-26 at 10.23.54.png

 

The would prevent the nesting (at least). Such a tool would be gold for many Confluence migrators.

PS: I know of all the dangers regarding this :-)

2 answers

0 votes
Abi Brown- Kolekti
Atlassian Partner
March 27, 2025

Hi @Normann P_ Nielsen _Netic_  if you would like some scriptrunner help you can contact the customer success team here 

 

0 votes
Shawn Doyle - ReleaseTEAM
Community Champion
March 26, 2025

Hi @Normann P_ Nielsen _Netic_ 

This is a job for Scriptrunner, if you don't already have it, it is one of the addons that I break my rule of not recommending addons by name.  They have a builtin script for removing or updating macros.  

Take a look at this thread as well for more info:

https://community.atlassian.com/forums/App-Central-questions/delete-macro-reference-with-Scriprunner/qaq-p/922084

Normann P_ Nielsen _Netic_
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 27, 2025

Hi - Love scriptrunner - and using it like this:

 

import com.atlassian.confluence.pages.PageManager
import com.atlassian.sal.api.component.ComponentLocator
import org.jsoup.Jsoup

def pageManager = ComponentLocator.getComponent(PageManager)
def page = pageManager.getPage('SDTEAM', 'CLOUD - How to make change templates') //You can change this line to point to the right parent page.

log.debug "Inspecting page ${page.title}"
def body = page.bodyContent.body
def parsedBody = Jsoup.parse(body)

def macroBody = parsedBody.select('ac|structured-macro').attr('ac:name', 'ui-steps')
def bodyToSave = macroBody.select('ac|rich-text-body')

pageManager.saveNewVersion(page) { pageObject ->
//macroBody.remove() // Removes the entire macro
//macroBody.empty() // Empties the body

//We need to remove the body but keep the body part
XXXXX


// pageObject.setBodyAsString(parsedBody.toString())
}
The XXX is my missing code with i need to replace the entire 'ui-steps' macro with bodyToSave
If I use macroBody.remove() I losse everything
If I use macroBody.empty() its the opposite of what I need.

def macroBody = parsedBody.select('ac|structured-macro').attr('ac:name', 'ui-steps')

 

give me the inner part, but I need a hadle to the entire macro.

 

In Short - I want to remove the "ui-steps" macro - BUT keep all inside its rich-text-body

Like Jose Rojo likes this
Normann P_ Nielsen _Netic_
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 27, 2025

ok, I am close to giving up - either I am stupid or jsoup is :-/

 

The page source for my page when fetched like:

 

def page = pageManager.getPage('SDTEAM', 'CLOUD - How to make change templates') //You can change this line to point to the right parent page.
when I do:
def body = page.bodyContent.body
def parsedBody = Jsoup.parse(body)
this line (for body):
<ac:structured-macro ac:macro-id="c1274913-7457-4d41-95c2-2424dbb3cd57" ac:name="ui-step" ac:schema-version="1">
becomes (for parsedBody):
<ac:structured-macro ac:name="ui-steps" ac:schema-version="1" ac:macro-id="c1274913-7457-4d41-95c2-2424dbb3cd57">
Hence ui-step becoms up-steps ...
Shawn Doyle - ReleaseTEAM
Community Champion
March 27, 2025

I'd ask Scriptrunner support for the syntax, @Abi Brown- Kolekti added a link for them.

If I understand correctly you need to remove the contents from the macro, remove the macro then put the contents into a different macro?  This is doable with script runner I've done something similar in the past.

Normann P_ Nielsen _Netic_
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 28, 2025

Ive submittet a ticket to Adaptavist, and stared https://www.mos-eisley.dk/spaces/ATLASSIAN/pages/279478283/Confluence+Data+Center+to+Cloud+Migration+Tips for advising other on stuff :-)

Jose Rojo
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
May 16, 2025

Hi @Normann P_ Nielsen _Netic_ , your script was useful to us as a base, we had the same usecase of needing to remove macros in multiple pages.

I fixed a couple things in it:

def macroBody = parsedBody.select('ac|structured-macro').attr('ac:name''ui-steps')

This was finding all structured-macros, then setting the ac:name attribute to "ui-steps", instead of only finding the one with that attribute.

pageObject.setBodyAsString(parsedBody.toString())

Here you save the parsed body with the changes, but I noticed that JSoup applies some kind of prettifier to it by default when you call toString, that breaks some macro configurations by adding spaces and line breaks.

Here's what the final script we used looks like:

import com.atlassian.confluence.pages.PageManager
import com.atlassian.sal.api.component.ComponentLocator
import org.jsoup.Jsoup

def space = '...'
def pageName = '...'

def pageManager = ComponentLocator.getComponent(PageManager)
def page = pageManager.getPage(space, pageName)

log.warn "Inspecting page ${page.title}"

def body = page.bodyContent.body
def parsedBody = Jsoup.parse(body)

// Remove the unwanted macros, we wanted to remove these three
parsedBody.select('ac|structured-macro[ac:name=getlastmodifiername]').remove()
parsedBody.select('ac|structured-macro[ac:name=getlastdatemodified]').remove()
parsedBody.select('ac|structured-macro[ac:name=getpageversion]').remove()

// Set prettyPrint to false to not break macro configurations with spaces and line breaks
parsedBody.outputSettings().prettyPrint(false)

// log.warn parsedBody.toString()
// Save the page

pageManager.saveNewVersion(page) { pageObject ->
    pageObject.setBodyAsString(parsedBody.toString())
}
Normann P_ Nielsen _Netic_
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 19, 2025

Hi @Jose Rojo 

 

I really dont get how a "select" in:

def macroBody = parsedBody.select('ac|structured-macro').attr('ac:name''ui-steps')

Can do a "set" on someting :-)

But thanks for looking into the script, I will do some testing of the refactored script.

Normann P_ Nielsen _Netic_
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 19, 2025

@Jose Rojo 

 

I get it regarding the Attribute

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events