Tuesday, October 13, 2020

Cloning a SXA site (in another folder)

Cloning a Sitecore SXA site

Part 7 already in my series of blog posts related to a multisite project where we wanted to make it as easy as possible to create a new site - with the premise that all the sites can share almost all settings. As you might have read in the previous posts we are really doing this - and keeping it all flexible. It's not because we share (all) things, we cannot configure or overrule some parts if needed.

Anyway - we do have a setup with a shared site and a base "master" site within a tenant (as recommended by SXA). As I did not want these sites to be amongst all the other created sites, I placed those two in a Sites Folder within the tenant. We have (at least) one other Sites Folder where we want to place the actual sites - and we might even want to split those sites over different folders.

We use SXA site cloning to create a new site. This is a very easy and rapid process. The "Clone Site" Powershell (SPE) script that is used can be found by a right click on a site item in the Scripts section. It will ask the name of the new destination site and copy everything from the master site. Note that:
  • it will also copy media items within the sites media folder - really useful if you have a standard folder setup there
  • it will not copy any forms - a new empty folder is created though within Forms
  • it will change all links towards the newly created items

The script works fine and it is a very fast way to create a site. But.. it will create a site next to the master site. Of course, we can move all items after the creation - but it would be faster to just ask a preferred location and created the site there. So that's what I did...

The solution provided here is only tested with one level of site folders - it probably could work with a tree of those folders with a few more adjustments though. 

The Powershell scripts to clone a site

Show-CloneSiteDialog

First script to take care of is the dialog script. We want the user that clones a site to be able to choose the site folder where the destination site should be created. I created a copy of the ootb script "/sitecore/system/Modules/PowerShell/Script Library/SXA/SXA - Multisite/Functions/Site cloning/Show-CloneSiteDialog" and adjusted that one (you could also opt to change the original one). The changes to the original script are not that big so I will not put the entire script here to keep focus.  

In the beginning of the script process the dialogParameters are defined. We add one more parameter there (siteLocation):
$dialogParameters.Add(@{ Name = "siteLocation"; 
  Title = [Sitecore.Globalization.Translate]::Text([Sitecore.XA.Foundation.Multisite.Texts]::Path); 
  Editor = "droplist"; Source="query:$($SourceSite.Parent.Paths.Path)/ancestor-or-self::*[@@templatename='Tenant']/*[@@templatename='Site Folder']"; 
  Tab = [Sitecore.Globalization.Translate]::Text([Sitecore.XA.Foundation.Multisite.Texts]::CloneSiteDialogGeneralTab); Mandatory=$true })  | Out-Null  
I am using a droplist here with a datasource query that finds my tenant and takes the children of type Site Folder. (note we are only supporting one level here - this customization would need to be changed to support a tree).
To keep it simple I used an existing text as label. The selection is marked as mandatory to make sure a choice is made.

The next (and final) change to this script is all the way at the bottom where the results are captured:
@{
    siteName              = $siteName
    siteDefinitionmapping = $mapping
    parent                = $siteLocation
}
We add a "parent" here that will contain the chosen location of the new site.

Clone-Site

Next script to adjust is the main one: "/sitecore/system/Modules/PowerShell/Script Library/SXA/SXA - Multisite/Content Editor/Context Menu/Clone Site". This is the script that gets called from the context menu and we need to adjust it so we can use the parent from our dialog:
$ctx = Get-Item .
    
Import-Function Copy-Site
Import-Function Show-CloneSiteInParentDialog
    
$dialogResult = Show-CloneSiteInParentDialog $ctx
$cloneSiteName = $dialogResult.siteName
$mapping = $dialogResult.siteDefinitionmapping

#custom    
 $parent = $dialogResult.parent
 if (!$parent) {
     $parent = $ctx.Parent
  }
#endcustom

$destinationSite = Copy-Site $ctx $parent $cloneSiteName $mapping
$destinationSiteID = $destinationSite.ID.ToString()
$host.PrivateData.CloseMessages.Add("item:load(id=$destinationSiteID)")

Run-SiteManager
I am just showing the main part here (within the "try") to keep it clear. So we changed the call to Show-CloneSite to the one we created, we fetch the parent (with a fallback scenario although that is probably not needed) and pass it to the Copy-Site function.

And that's it. Well, that's what we thought so we tested this. The site was indeed created in the correct folder. So was the forms folder. But the media folder was still next to our master. 

Copy-Site

Let's take a look at the "/sitecore/system/Modules/PowerShell/Script Library/SXA/SXA - Multisite/Functions/Site cloning/Copy-Site" script. The site creation was fine with our new parent. We noticed that creating the Forms folder was done as it would be for a new site and that script uses the paths to determine where to create a new (empty) folder - this works fine in our version as well.

So we need to take a look at the copy process for the media folder. Somewhere in the middle of the Copy-Site script you'll find the media part and let's customize that a bit:
if ($Site.SiteMediaLibrary) {
  $SiteMediaLibrary = $Site.Database.GetItem($Site.SiteMediaLibrary) | Wrap-Item

#custom
  if ($SiteMediaLibrary.Parent.Name -ne $destinationSite.parent.Name) {
    $SiteMediaRoot = $ctx.Database.GetItem($SiteMediaLibrary.Parent.Paths.Path.Replace($($SiteMediaLibrary.Parent.Name),$($destinationSite.parent.Name)))
    if (!$SiteMediaRoot) {
      $SiteMediaRoot = $ctx.Database.GetItem($ctx.SiteMediaLibrary).Parent
    }
  }
  else {
    $SiteMediaRoot = $SiteMediaLibrary.Parent
  }
#end custom

  $NewSiteMediaLibrary = Copy-RootAndFixReference $SiteMediaLibrary $SiteMediaRoot $destinationSite.Name

  Set-NewLinkReference $Site $destinationSite $SiteMediaLibrary.Paths.Path $NewSiteMediaLibrary.Paths.Path
  $destinationSite.SiteMediaLibrary = $NewSiteMediaLibrary.ID
}
Instead of copying the media tree to the parent of the master media tree, we use string replacement and the paths to determine the location we want. Note that we do need a folder structure corresponding to the Site Folders structure, otherwise this part will fail. We could expand the script to create the necessary folders if needed.


Conclusion

With that last change we managed it. Our new site cloning script will ask us where to create the destination site - of course within the same tenant and in our one-level Site Folder structure. Combined with all the stuff from my previous posts - and the ootb features - creating a site is becoming really fast.




No comments:

Post a Comment