Delmon Young
Delmon Young

Reputation: 2053

CQ - Moving content from one page to another

I realize that this is a pretty specific question but I would imagine someone has run into this before. So I've got about fifty pages or so that were created about a year ago. We're trying to revamp the page with new components specifically in the header and the footer. Except the content in the main-content area will stay the same. So I'm trying to move over everything from the old pages to the new pages but just keep the main-content area. The problem is I can't just change the resource type on the old page to point to the new page components because the content is different and I'll have a bunch of nodes in the header and footer that I don't want. For example here is my current content structure:

Old Content

star-trek
    jcr:content
        header
            nav
            social
            chat
        main-content
            column-one
            column-two
        footer
            sign-up
            mega-menu

New Content

star-wars
    jcr:content
        masthead
            mega-menu                                
        main-content
            column-one
            column-two
        bottom-footer
            left-links
            right-links

Does anybody have any ideas on how to move just the content in the main-content node and somehow remove the other nodes. I'm trying to somehow do this programmatically cause I don't want to create 50 pages from scratch. Any help is appreciated!

Upvotes: 0

Views: 4305

Answers (3)

ryanlunka
ryanlunka

Reputation: 236

The problem with the results I'm seeing here is that you are writing servlets that execute JCR operations to move things around. While technically that works, it's not really a scalable or reusable way to do this. You have to write some very specific code, deploy it, execute it, then delete it (or it lives out there forever). It's kind of impractical and not totally RESTful.

Here are two better options:

One of my colleagues wrote the CQ Groovy Console, which gives you the ability to use Groovy to script changes to the repository. We frequently use it for content transformations, like you've described. The advantage to using Groovy is that it's script (not compiled/deployed code). You still have access to the JCR API if you need it, but the console has a bunch of helper methods to make things even easier. I highly recommend this approach.

https://github.com/Citytechinc/cq-groovy-console

The other approach is to use the Bulk Editor tool in AEM. You can export a TSV of content, make changes, then reimport. You'll have to turn the import feature on using an administrative function, but I've used this with some success. Beware, it's a bit buggy though, with array value properties.

Upvotes: 0

Bertrand Delacretaz
Bertrand Delacretaz

Reputation: 6100

You can use the JCR API to move things around at will, I would

  1. Block users from accessing the content in question. Can be done with temporary ACLs, or by closing access on the front-end if you can.
  2. Run a script or servlet that changes the content using JCR APIs
  3. Check the results
  4. Let users access the content again

For the content modification script I suggest a script that modifies a single page (i.e. you call it with an HTTP request that ends in /content/star-trek.modify.txt) so that you can run it either on a single page, for testing, or on a group of pages once it's good.

The script starts form the current node, recurses into it to find nodes that it knowns how to modify (based on their sling:resourceType), modifies them and reports what it did in the logs or on its output.

To modify nodes the script uses the JCR Node APIs to move things around (and maybe Worskpace.move).

Upvotes: 1

bongman1612
bongman1612

Reputation: 440

It is indeed possible to write a code which does what you need :

package com.test;

import java.io.File;
import java.io.IOException;

import javax.jcr.ItemExistsException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.Node;

import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.jackrabbit.core.TransientRepository;
import org.xml.sax.SAXException;

public class test {

    public void test(Document doc) throws RepositoryException {
        try {

            // Create a connection to the CQ repository running on local host 

            Repository repository = JcrUtils
                    .getRepository("http://localhost:4502/crx/server");
            System.out.println("rep is created");

            // Create a Session
            javax.jcr.Session session = repository.login(new SimpleCredentials(
                    "admin", "admin".toCharArray()));
            System.out.println("session is created");

            String starTrekNodePath = "/content/path/";
            String starWarsNodePath = "/content/anotherPath"

            Node starTrekpageJcrNode = null;
            Node starWarstext = null;

            setProperty(java.lang.String name, Node value) 

            boolean starTrekNodeFlag = session.nodeExists(starTrekNodePath);
            boolean starWarsNodeFlag = session.nodeExists(starWarsNodePath);
            if (starTrekNodeFlag && starWarsNodeFlag) {
                System.out.println("to infinity and beyond");
                Node starTrekNode = session.getNode(starTrekNodePath);
                Node starWarsNodeFlag = session.getNode(starWarsNodePath);

                //apply nested looping logic here; to loop through all pages under this node
                //assumption is that you have similar page titles or something

                //on these lines to determine target and destination nodes
                            //2nd assumption is that destination pages exist with the component structures in q
                //once we have the target nodes, the following segment should be all you need

                Node starTrekChildNode = iterator.next();//assuming you use some form of iterator for looping logic
                Node starWarsChildNode = iterator1.next();//assuming you use some form of iterator for looping logic

                //next we get the jcr:content node of the target and child nodes

                Node starTrekChildJcrNode = starTrekChildNode.getNode("jcr:content");
                Node starWarsChildJcrNode = starWarsChildNode.getNode("jcr:content");

                // now we fetch the main-component nodes. 

                Node starTrekChildMCNode = starTrekChildJcrNode.getNode("main-content");
                Node starWarsChildMCNode = starWarsChildJcrNode.getNode("main-content");

                //now we fetch each component node

                Node starTrekChildC1Node = starTrekChildMCNode.getNode("column-one");
                Node starTrekChildC2Node = starTrekChildMCNode.getNode("column-two");

                Node starWarsChildC1Node = starWarsChildMCNode.getNode("column-one");
                Node starWarsChildC2Node = starWarsChildMCNode.getNode("column-two");

                // fetch the properties for each node of column-one and column-two from target
                String prop1;
                String prop2;
                PropertyIterator iterator = starTrekChildC1Node.getProperties(propName);
                while (iterator.hasNext()) {
                    Property prop = iterator.nextProperty();
                    prop1 = prop.getString();
                }

                PropertyIterator iterator = starTrekChildC2Node.getProperties(propName);
                while (iterator.hasNext()) {
                    Property prop = iterator.nextProperty();
                    prop2 = prop.getString();
                }



                // and now we set the values

                starWarsChildC1Node.setProperty("property-name",prop1);
                starWarsChildC2Node.setProperty("property-name",prop2);

                //end loops as appropriate
}

Hopefully this should set you on the right track. You'd have to figure out how you want to identify destination and target pages, based on your folder structure in /content, but the essential logic should be the same

Upvotes: 1

Related Questions