Update content on multiple Confluence pages in one go

If you’re looking to update Macros in pages, give a look to our Update Macro feature!

One question we get fairly frequently is how to bulk update page content using ScriptRunner.

One of the complexities of doing so is dealing with the Confluence storage format, which is an XHTML-based document. Doing simple string replacements on HTML using familiar tools like regular expressions can be a bit fraught, but that doesn’t mean we can’t easily get things done. The convenience of the Groovy programming language and powerful libraries like jsoup combine to make these sort of changes feasible.

As a simple example, suppose that we have several different pages in our space that each contain a table. That table has a header column with some placeholder text that we want to change.

Suppose further that all of these pages are children of a known parent page. A script like the one below can be run from the Script Console to perform the update, while leaving placeholder text that’s not in a table header alone.

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

def pageManager = ComponentLocator.getComponent(PageManager)
def rootPage = pageManager.getPage('DS', 'Welcome to Confluence') //You can change this line to point to the right parent page.
rootPage.children.each { page ->
    log.debug "Inspecting page ${page.title}"
    def body = page.bodyContent.body
    def parsedBody = Jsoup.parse(body)
    def tableHeaderWithPlaceholder = parsedBody.select('th:contains(placeholdertext)')
    if (!tableHeaderWithPlaceholder.empty) {
        log.debug "Found table header with placeholder text: ${tableHeaderWithPlaceholder}"
        pageManager.saveNewVersion(page) { pageObject ->
            tableHeaderWithPlaceholder.html("${page.creator.fullName}'s Column")
            pageObject.setBodyAsString(parsedBody.toString())
        }
    }
}

That transforms the table as you might expect to something like this:

Of course, the above script can be updated for more complex use cases, such as iterating through the results of a CQL search, changing content besides placeholders, and so on.

Happy scripting!