Copying a Page, programatically

Posted by Community Admin on 04-Aug-2018 16:16

Copying a Page, programatically

All Replies

Posted by Community Admin on 29-May-2012 00:00

Hello,
We have a requirement that we allow an admin user to select a page group (Page A) from a custom module, and duplicate that page group under another page group (Page B). I was hoping that someone had done this before, and might have an example of how they achieved this?

Posted by Community Admin on 04-Jun-2012 00:00

Hello Travis,

Please find below a short sample I've prepared for you - it will take the Page group title as an argument and will copy it, and its children under a specified page (currently ti just duplicates them with a _Copy string in the title, but you can modify this as per your specific requirements.

public void DuplicatePageAndChildPages(string pageTitle)
      
          var pageToDuplicate = App.WorkWith().Pages().ThatArePublished().Where(p => p.Title == pageTitle).Get().SingleOrDefault();
          var myDuplicatedPage = App.WorkWith().Page(pageToDuplicate.Id).Duplicate().Do(p =>
          
              p.Title = pageToDuplicate.Title + " Copy";
              p.UrlName = pageToDuplicate.UrlName + "_copy";
              p.ShowInNavigation = true;
              if (p.Page != null)
              
                  p.Page.Title = p.Title;
              
          ).SaveAndContinue().Get();
          WorkflowManager.MessageWorkflow(myDuplicatedPage.Id, typeof(PageNode), null, "Publish", false, new Dictionary<string, string>());
          var myChildPages = App.WorkWith().Pages().ThatArePublished().Where(p => p.ParentId == pageToDuplicate.Id).Get();
          if (myChildPages != null && myChildPages.Count() > 0)
          
              foreach (var pg in myChildPages)
              
                  var myDuplicatedChild = App.WorkWith().Page(pg.Id).Duplicate().Do(p =>
                  
                      p.ParentId = myDuplicatedPage.Id;
                      p.Title = pg.Title + " Copy";
                      p.UrlName = pg.UrlName + "_copy";
                      p.ShowInNavigation = true;
                      if (p.Page != null)
                      
                          p.Page.Title = p.Title;
                      
                  ).SaveAndContinue().Get();
                  WorkflowManager.MessageWorkflow(myDuplicatedChild.Id, typeof(PageNode), null, "Publish", false, new Dictionary<string, string>());
              
          
 
      


Kind regards,
Boyan Barnev
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 06-Jun-2012 00:00

being new in sitefinity development, could you also post how to integrate this piece of code with the UI. or at least point to the right direction?

I've been trying to figure out how to add an additional action to the backend pages treeview -> actions context menu and i can't seem to find a code sample.

Posted by Community Admin on 11-Jun-2012 00:00

Hello Travis,

Please take a look at the second part of this blog post - Adding a new Action command in the individual Content item Actions menu , I believe you might find it useful.

Greetings,
Boyan Barnev
the Telerik team

Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 12-Jun-2012 00:00

Thanks a lot, i'll check it out

Posted by Community Admin on 12-Jun-2012 00:00

Hi again,
I've followed the example in the post yet i can't seem to bind the new action to do something:
First things first, i added a new Action in:
Setting->Advanced->ContentView->Controls->FrontendPages->Views->FrontendPagesListView->ViewModes->TreeTable->
Columns->ActionLinkText->MenuItems
and added a new action named duplicateX. The properties set are exactly as the example says, only instead of "duplicate" i put "duplicateX" since a duplicate entry allready exists.

This part works, the new action exists in the action menu. (but it will not appear for group pages and i can't find the configuration to modify this behaviour)

I made a new service:

[ServiceContract]
    public interface IExtendedPagesService
    
        [WebInvoke(Method = "POST", UriTemplate = "pageId/duplicateX/", ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        string DuplicatePage(string pageId);
    
    public class ExtendedPagesService : IExtendedPagesService
    
        public string DuplicatePage(string pageId)
        
            ....
        
     

and initialized it in global.asax:
protected void Application_Start(object sender, EventArgs e)
        
            Bootstrapper.Initialized += new EventHandler<Telerik.Sitefinity.Data.ExecutedEventArgs>(Bootstrapper_Initialized);
        
 
        void Bootstrapper_Initialized(object sender, Telerik.Sitefinity.Data.ExecutedEventArgs e)
        
            SystemManager.RegisterWebService(typeof(ExtendedPagesService), "Sitefinity/Services/Pages/ExtendedPagesService.svc");
        

and finally added a .js in the root/FrontendPagesAdditions folder named FrontendPagesAdditions.js
function duplicateXCommandHandler(sender, args)
    if (args._commandName == "duplicateX")
        jQuery.ajax(
            type: "POST",
            url: sender._baseUrl + "Sitefinity/Services/Pages/ExtendedPagesService.svc/" + args._dataItem.Id + "/duplicateX/",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            processdata: false,
            success: function (data)
                if (data != "ERROR")
                    args._dataItem.Id = data;
                    //sender.get_itemsGrid().executeCommand("edit", args._dataItem, [data], args._itemElement, null, null);
 
                    // Or call the line below instead to just refresh the grid
                    sender.get_itemsGrid().dataBind();
                
            ,
            error: function (data)
        );
    
 
function frontendPagesListLoaded(sender, args)
    sender.add_itemCommand(duplicateXCommandHandler);

and i added the required entry in
Setting->Advanced->ContentView->Controls->FrontendPages->Views->FrontendPagesListView->Scripts
with ~/FrontendPagesAdditions/FrontendPagesAddition.js and frontendPagesListLoaded in the fields.

So, as i said, when i click on the DuplicateX action nothing happens (no js errors).
Additionally i would like to know how can i make this action entry appear on group/redirect pageNodes.

Regards, Alexander Savvas

Posted by Community Admin on 21-Jun-2012 00:00

So getting back to the page duplication problems, the above code did not resolve the issues.  in fact it created a new one.  the original problem was that we were getting errors that looked like:

Row not found: GenericOID@f6f496e4 PageTemplate id=f669d9a7-009d-4d83-bbbb-000000000003
UPDATE [sf_page_templates] SET [last_modified]=?, [voa_version]=? WHERE [id] = ? AND [voa_version]=?
or we would get similar errors that mentioned the PageNode instead of PageTemplate.
The new code seems to have resolved the PageNode errors but not the PageTemplate errors. These errors happen when building the child pages.  we have several levels of sub-pages and sub-pagegroups that need to be copied.  all pages currently have the same template assigned to them.

my code:
PageNode rootNode = manager.GetPageNode(SiteInitializer.FrontendRootNodeId);
            if (NodeToCreateUnder == Guid.Empty && rootNode != null)
                NodeToCreateUnder = rootNode.Id;
 
            if (rootNode != null && NodeToCopyFrom != Guid.Empty && NodeToCreateUnder != Guid.Empty)
            
                PageNode copyFromNode = manager.GetPageNode(NodeToCopyFrom);
                newRootNode = manager.GetPageNode(NodeToCreateUnder);
                try
                
                    newPageNode = App.WorkWith().Page(copyFromNode.Id).Duplicate().Do(p =>
                    
                        if (p.Page != null)
                        
                            p.Page.Title = NewRoot_Title;
                            p.Page.Description = NewRoot_Description;
                            p.Page.HtmlTitle = NewRoot_HTMLTitle;
                        
                        p.Name = NewRoot_Title;
                        p.Description = NewRoot_Description;
                        p.Title = NewRoot_Title;
                        p.ParentId = NodeToCreateUnder;
                        p.Ordinal = copyFromNode.Ordinal;
                        p.AllowMultipleUrls = false;
                        p.Urls.Clear();
                        p.UrlName = Regex.Replace(NewRoot_Title.ToLower(), @"[^\w\-\!\$\'\(\)\=\@\d_]+", "-");
                        p.DateCreated = DateTime.UtcNow;
                        p.LastModified = DateTime.UtcNow;
                    ).SaveAndContinue().Get();
 
                    if (newPageNode != null)
                    
                        if (newPageNode.NodeType != NodeType.Group)
                            WorkflowManager.MessageWorkflow(newPageNode.Id, typeof(PageNode), null, "Publish", false, new Dictionary<string, string>());
                    
                
                catch newPageNode = null;
                if (newPageNode != null)
                    _BuildChildNodes(newPageNode, NodeToCopyFrom, newPartner);
            
and the _buildchildnodes() code:
_BuildChildNodes(PageNode rootNode, Guid NodeToCopyFrom, PartnerItem newPartner)
           List<PageNode> nodesToCopyList = App.WorkWith().Pages().ThatArePublished().Where(p => p.ParentId == NodeToCopyFrom).Get().ToList();
 
            List<Guid> NewPages = new List<Guid>();
            List<Guid> OldPages = new List<Guid>();
            foreach (PageNode pn in nodesToCopyList)
            
                try
                
                    PageNode myDuplicatedPage = App.WorkWith().Page(pn.Id).Duplicate().Do(p =>
                    
                        p.ParentId = rootNode.Id;
                        p.Ordinal = pn.Ordinal;
                        p.AllowMultipleUrls = false;
                        p.Urls.Clear();
                        p.UrlName = Regex.Replace(pn.Title.ToLower(), @"[^\w\-\!\$\'\(\)\=\@\d_]+", "-");
                        p.DateCreated = DateTime.UtcNow;
                        p.LastModified = DateTime.UtcNow;
                    ).SaveAndContinue().Get();
                    if (myDuplicatedPage.NodeType != NodeType.Group)
                        WorkflowManager.MessageWorkflow(myDuplicatedPage.Id, typeof(PageNode), null, "Publish", false, new Dictionary<string, string>());
                    NewPages.Add(myDuplicatedPage.Id);
                    OldPages.Add(pn.Id);
                
                catch
            
            for (int i = 0; i < NewPages.Count; i++)
            
                PageNode newnode = App.WorkWith().Pages().ThatArePublished().Where(p => p.Id == NewPages[i]).Get().FirstOrDefault();
                if (newnode != null)
                    _BuildChildNodes(newnode, OldPages[i], newPartner);
            

the new problem is very strange.  now, after duplicating a bunch of pages, using the above code the pages will sometimes not display properly in the pages list.  
To duplicate the problem:
- create your new pages using the above code then go to the pages page to view them.
- expand all levels of your new page tree so you can see all the pages, pagegroups, etc.
- refresh the page
- what you should now see is on the root node are some of the newly created pages.  but these pages are from the middle of the tree i just duplicated.  their properties prove it.  but they show up on the root.  the pages do also show up in their correct spot in the newly created tree so these specific pages are duplicates of the new duplicates. this only happens if the newly duplicated tree is expanded when refreshing.

Everytime you refresh, if the newly copied page group is expanded, you get these junk pages in the list.  if you restart the application, the problem goes away permanently but that's not a valid solution for a production system.

Any ideas Boyan?  its pretty frustrating and disappointing to realize that after so much time just copying a bunch of pages is still so problematic.

Posted by Community Admin on 21-Jun-2012 00:00

UPDATE

ok i think the provided code has also resolved the issue with the template id error. that was related to refreshing issues. so thats great.

but the extra pages that show up in the list are a problem that cant be ignored.  this to me seems more like a bug in the system.  any thoughts?

Posted by Community Admin on 25-Jun-2012 00:00

UPDATE

this issue seems related to having PageGroups in the file structure that is getting copied. with no page groups, this issue does not occur.  add page groups and we get this problem.

any suggestions?

This thread is closed