Hi,
We have more than 260 pages with the ghost nodes.
For example on this path(/content/products/en-us//Efficiency/compressor-monitoring/jcr:content/root/body-container/scrolling_panel/item_1657619257205/download_library) we deleted download library panel component inside the live copy AEM creates a placeholder ghost component for it.
Like this, we have multiple pages .
Is there any way to remove ghost nodes like any shell script or any other way.
Solved! Go to Solution.
Write a groovy script to fetch the nodes with the resource type as wcm/msm/components/ghost and delete them. Once upon the deletion save the session. Please refer sample snippet
import javax.jcr.query.Query;
import javax.jcr.Node;
import java.util.List
import groovy.transform.Field
def query = createSQL2Query()
def result = query.execute();
def rows = result.rows
def total = 0
List<String> list = new ArrayList<>();
List<String> updatedList = new ArrayList<>();
rows.each{ row ->
println row.path;
Resource res = resourceResolver.getResource(row.path);
Node currentNode = res.adaptTo(javax.jcr.Node);
currentNode.remove();
session.save();
total++
}
println "Total nodes :: "+ total
def createSQL2Query(){
def queryManager = session.workspace.queryManager
def statement = "select child.[jcr:path] from [cq:Page] AS page INNER JOIN [cq:PageContent] AS jcrContent ON ISCHILDNODE(jcrContent, page) INNER JOIN [nt:unstructured] AS child ON ISDESCENDANTNODE(child, jcrContent) where ISDESCENDANTNODE(page, '/content/PROJECT_DIR') and child.[sling:resourceType] = 'wcm/msm/components/ghost'";
//println statement
def query = queryManager.createQuery(statement,Query.JCR_SQL2)
query.setLimit(3000);
query.setOffset(0);
query
}
You can run a dry run by commenting session.save() to check whether its listing exact paths or not.
Hope this helps!!
Write a groovy script to fetch the nodes with the resource type as wcm/msm/components/ghost and delete them. Once upon the deletion save the session. Please refer sample snippet
import javax.jcr.query.Query;
import javax.jcr.Node;
import java.util.List
import groovy.transform.Field
def query = createSQL2Query()
def result = query.execute();
def rows = result.rows
def total = 0
List<String> list = new ArrayList<>();
List<String> updatedList = new ArrayList<>();
rows.each{ row ->
println row.path;
Resource res = resourceResolver.getResource(row.path);
Node currentNode = res.adaptTo(javax.jcr.Node);
currentNode.remove();
session.save();
total++
}
println "Total nodes :: "+ total
def createSQL2Query(){
def queryManager = session.workspace.queryManager
def statement = "select child.[jcr:path] from [cq:Page] AS page INNER JOIN [cq:PageContent] AS jcrContent ON ISCHILDNODE(jcrContent, page) INNER JOIN [nt:unstructured] AS child ON ISDESCENDANTNODE(child, jcrContent) where ISDESCENDANTNODE(page, '/content/PROJECT_DIR') and child.[sling:resourceType] = 'wcm/msm/components/ghost'";
//println statement
def query = queryManager.createQuery(statement,Query.JCR_SQL2)
query.setLimit(3000);
query.setOffset(0);
query
}
You can run a dry run by commenting session.save() to check whether its listing exact paths or not.
Hope this helps!!
@Vani1012 : This could be useful for you: https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/issue-with-wcm-msm-compone...
basically, instead of deleting the ghost nodes, you can implement the approach mentioned in the previously accepted response. These ghost nodes will be needed if you have to restore the inheritance for removed section at some point in future which is a valid use-case to re-store the previously existing content.
thanks.
Hi @Vani1012 ,
Yes, you can use a Java-based approach to remove ghost nodes from multiple pages in Adobe Experience Manager (AEM). You can write a custom Java program to iterate over the pages and remove the ghost nodes programmatically. Here's a general outline of how you can do it:
Identify Ghost Nodes:
Develop a Java Program:
Example Java Code:
Here's a simplified example of Java code to remove ghost nodes from multiple pages:
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Workspace;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
public class RemoveGhostNodes {
private ResourceResolver resourceResolver;
public RemoveGhostNodes(ResourceResolverFactory resourceResolverFactory) {
try {
// Get a resource resolver
resourceResolver = resourceResolverFactory.getServiceResourceResolver(null);
} catch (Exception e) {
// Handle exception
}
}
public void removeGhostNodes(String[] paths) {
for (String path : paths) {
try {
// Get the page resource
Resource pageResource = resourceResolver.getResource(path);
if (pageResource != null) {
Node pageNode = pageResource.adaptTo(Node.class);
if (pageNode != null) {
// Remove ghost nodes
NodeIterator childNodes = pageNode.getNodes();
while (childNodes.hasNext()) {
Node childNode = childNodes.nextNode();
if (childNode.isNodeType("sling:nonexisting")) {
childNode.remove();
}
}
pageNode.getSession().save();
}
}
} catch (RepositoryException e) {
// Handle exception
}
}
}
public static void main(String[] args) {
// Initialize the RemoveGhostNodes class with a resource resolver factory
// (Inject the resource resolver factory as needed)
RemoveGhostNodes remover = new RemoveGhostNodes(resourceResolverFactory);
// Call the removeGhostNodes method with paths containing ghost nodes
remover.removeGhostNodes(new String[] { "/content/products/en-us/page1", "/content/products/en-us/page2", ... });
}
}
Execute the Java Program:
Testing and Validation:
This Java-based approach allows you to programmatically remove ghost nodes from multiple pages in AEM efficiently. However, always exercise caution when making changes directly to the content repository and test thoroughly before applying changes in a production environment.