Our scenario:
We have "news" node with child nodes for each year.
Within this parent "news" nodes there are pages that need to be moved into their respective year child nodes.
When I used the on-prem version of AEM (pre-Cloud), it was as simple as drag and drop into the folders and all references to those moved pages were updated.
Now I can move single pages, going through the steps, but I can't multi-select 50,100 or more pages to move. I can publish this amount, just not move.
Is this possible in AEM nowadays for a basic author to do and not bother the Development team to write scripts or export/import packages?
this is what ChatGPT gave me as a response,
----
Yes — in Adobe Experience Manager (AEM) you can bulk move pages from one location to another, and AEM can also update references to those moved pages if you do it through the Move operation in Sites.
Here’s the breakdown:
In the Sites console, you can select multiple pages at once.
Choose Move from the top action bar (or right-click > Move). (THIS PART DOESNT SEEM TO APPEAR FOR MULTI SELECTED PAGES - and right click brings up the browser menu nothing to do with AEM)
You’ll be asked to select the new destination node.
AEM will move all selected pages (and their children) to the new location.
During the Move wizard, AEM shows a References step.
This lists internal references (links, language copies, live copies, launch references, etc.).
You can choose whether to update references automatically or leave them unchanged.
If you confirm the update, AEM rewrites links in other pages/components that referenced the old path, so they now point to the new one.
-----
Solved! Go to Solution.
Views
Replies
Total Likes
Hi @ChrisPhillipsUC,
You can use Groovy Console - If allowed, your dev team can quickly write a Groovy script to bulk-move nodes and invoke the PageManager.move()
API (which handles references the same way as the UI wizard).
Pasting an sample groovy script for you just for reference:
import com.day.cq.wcm.api.PageManager
import com.day.cq.wcm.api.Page
import javax.jcr.Session
// --- CONFIGURE THESE ---
def SOURCE_PATH = "/content/site/news" // where your pages currently are
def DESTINATION_BASE = "/content/site/news" // base news node where year folders exist
def MOVE_BY_PROPERTY = "year" // property that indicates year, or null if you parse from name
// --- SCRIPT START ---
def session = resourceResolver.adaptTo(Session)
def pageManager = resourceResolver.adaptTo(PageManager)
def sourcePage = pageManager.getPage(SOURCE_PATH)
if (!sourcePage) {
println "Source path not found: $SOURCE_PATH"
return
}
sourcePage.listChildren().each { Page child ->
try {
// skip if this child is already a "year" folder
if (child.listChildren().size() > 0 && child.getName().isNumber()) {
return
}
// decide target folder
def year
if (MOVE_BY_PROPERTY) {
year = child.getProperties().get(MOVE_BY_PROPERTY, "")
} else {
// fallback: parse from page name (e.g., "2021-something")
year = (child.getName() =~ /^(\d{4}).*/)[0][1]
}
if (!year) {
println "Skipping ${child.path} (no year found)"
return
}
def destinationPath = "${DESTINATION_BASE}/${year}"
def destinationPage = pageManager.getPage(destinationPath)
if (!destinationPage) {
println "Destination folder not found: $destinationPath"
return
}
def newPath = destinationPage.path + "/" + child.name
pageManager.move(child.path, destinationPage.path, null, true, true, null)
println "Moved: ${child.path} → ${newPath}"
} catch (Exception e) {
println "Error moving ${child.path}: ${e.message}"
}
}
session.save()
println "Done moving pages."
Views
Replies
Total Likes
Hi @ChrisPhillipsUC,
You can use Groovy Console - If allowed, your dev team can quickly write a Groovy script to bulk-move nodes and invoke the PageManager.move()
API (which handles references the same way as the UI wizard).
Pasting an sample groovy script for you just for reference:
import com.day.cq.wcm.api.PageManager
import com.day.cq.wcm.api.Page
import javax.jcr.Session
// --- CONFIGURE THESE ---
def SOURCE_PATH = "/content/site/news" // where your pages currently are
def DESTINATION_BASE = "/content/site/news" // base news node where year folders exist
def MOVE_BY_PROPERTY = "year" // property that indicates year, or null if you parse from name
// --- SCRIPT START ---
def session = resourceResolver.adaptTo(Session)
def pageManager = resourceResolver.adaptTo(PageManager)
def sourcePage = pageManager.getPage(SOURCE_PATH)
if (!sourcePage) {
println "Source path not found: $SOURCE_PATH"
return
}
sourcePage.listChildren().each { Page child ->
try {
// skip if this child is already a "year" folder
if (child.listChildren().size() > 0 && child.getName().isNumber()) {
return
}
// decide target folder
def year
if (MOVE_BY_PROPERTY) {
year = child.getProperties().get(MOVE_BY_PROPERTY, "")
} else {
// fallback: parse from page name (e.g., "2021-something")
year = (child.getName() =~ /^(\d{4}).*/)[0][1]
}
if (!year) {
println "Skipping ${child.path} (no year found)"
return
}
def destinationPath = "${DESTINATION_BASE}/${year}"
def destinationPage = pageManager.getPage(destinationPath)
if (!destinationPage) {
println "Destination folder not found: $destinationPath"
return
}
def newPath = destinationPage.path + "/" + child.name
pageManager.move(child.path, destinationPage.path, null, true, true, null)
println "Moved: ${child.path} → ${newPath}"
} catch (Exception e) {
println "Error moving ${child.path}: ${e.message}"
}
}
session.save()
println "Done moving pages."
Views
Replies
Total Likes
Hi @ChrisPhillipsUC ,
Indeed, as suggested by @SantoshSai Groovy works the best. However, if your business users also want to do that more often in the future, then I could suggest creating a Managed Control Process.
Eventually some sort of script or process needs to be implemented indeed.
I hope it helps.
Thanks!
Thanks @Abie , I might look into the Managed Control Process at some point. We want to empower the business users to do this themselves (with strict guidelines) so our Developers can concentrate on the bigger tasks. We'll go with @SantoshSai idea and see how that goes.
Thanks both for you help.
Chris
Sure you can select the solution out of all the options, but in my opinion, giving Groovy access to the business users is quite dangerous for various reasons-
1. They do not know code (mostly)
2. Any small syntax could halt their process.
3. Mostly importantly, using groovy one could execute any kind of change, could delete/unpublish the entire content.
With due respect, I think Groovy is not a solution for the business users, but only for the developers or operations.
Thanks!
Views
Replies
Total Likes
@ChrisPhillipsUC Just checking in! Were you able to get this resolved? If you found your own solution, sharing the details would be a big help to others who might face the same issue later on. And if one of the replies here helped—whether it fully solved the problem or simply pointed you in the right direction—marking it as accepted makes it much easier for future readers to find. Thanks again for helping close the loop and contributing to the community!
Views
Replies
Total Likes
Views
Likes
Replies
Views
Likes
Replies
Views
Likes
Replies