Expand my Community achievements bar.

SOLVED

Remove ghost nodes for multiple pages at once

Avatar

Level 8

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 .

123.png

Is there any way to remove ghost nodes like any shell script or any other way.

 

 

 

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

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!!

View solution in original post

3 Replies

Avatar

Correct answer by
Community Advisor

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!!

Avatar

Community Advisor

@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.

Avatar

Community Advisor

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:

  1. Identify Ghost Nodes:

    • Use the CRXDE Lite or QueryBuilder to identify the paths of pages containing ghost nodes. Ghost nodes typically have a type of sling:nonexisting.
  2. Develop a Java Program:

    • Write a custom Java program using AEM's Java API to remove the identified ghost nodes. You can use the ResourceResolver API to access and manipulate resources in the JCR repository.
  3. 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", ... });
    }
}

 

  1. Execute the Java Program:

    • Compile the Java program and execute it in your AEM environment.
  2. Testing and Validation:

    • Test the Java program thoroughly in a non-production environment before applying it to production. Ensure that it successfully removes ghost nodes without causing any unintended side effects.

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.