1-888-365-2779
+1-888-365-2779
Try Now
More in this section

Forums / Developing with Sitefinity / Copying a Page, programatically

Copying a Page, programatically

9 posts, 0 answered
  1. Travis
    Travis avatar
    86 posts
    Registered:
    15 Oct 2008
    29 May 2012
    Link to this post
    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?
  2. Boyan Barnev
    Boyan Barnev avatar
    1429 posts
    Registered:
    16 Aug 2017
    04 Jun 2012
    Link to this post
    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
  3. Alexander
    Alexander avatar
    1 posts
    Registered:
    30 May 2012
    06 Jun 2012
    Link to this post
    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.

  4. Boyan Barnev
    Boyan Barnev avatar
    1429 posts
    Registered:
    16 Aug 2017
    11 Jun 2012
    Link to this post
    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
  5. Alexander
    Alexander avatar
    2 posts
    Registered:
    07 Jun 2012
    12 Jun 2012
    Link to this post
    Thanks a lot, i'll check it out
  6. Alexander
    Alexander avatar
    2 posts
    Registered:
    07 Jun 2012
    12 Jun 2012
    Link to this post
    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
  7. Rory
    Rory avatar
    44 posts
    Registered:
    22 Mar 2012
    21 Jun 2012
    Link to this post
    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.
  8. Rory
    Rory avatar
    44 posts
    Registered:
    22 Mar 2012
    21 Jun 2012
    Link to this post
    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?
  9. Rory
    Rory avatar
    44 posts
    Registered:
    22 Mar 2012
    25 Jun 2012
    Link to this post
    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?
9 posts, 0 answered