For an internal project at Sitecore, we wanted to make it as easy as possible for users to create a SXA site using modules. For example, if they wanted pages and page designs for blog posts, they would select the “Blog” module.
I discovered that having a truly automated module is more difficult than it seems. Fortunately, I was able to address many of these issues through Powershell scripts. In this post, I will walk you through creating an example Blog module. I assume basic knowledge of Sitecore Experience Accelerator (SXA) and SXA modules.
First, I created templates for a Blog Landing Page and Blog Page. These would be mapped to corresponding Page Designs. The Page Design for Blog Landing Page contains a Search Results rendering, and the Blog Page a Page Content rendering. The rendering variants and partial designs for these lived within a Global shared site, whereas the page designs were on the local site.
If all the partial designs live in the Global site, this presents a unique challenge for the Search Results rendering. How do we define the search scope? We can’t use the location query to restrict the search to a specific parent item’s children, as in a branch that path doesn’t exist yet. Fortunately, there is another query to address this: “sxa:UnderCurrentPage”. This will ensure the search is restricted to the children on the item the Search Results rendering lives on. We can also specify a template to restrict the search- in this case, the Blog Page. This can all go on a search scope under the Global site instead of locally. Now no need to add it to a branch on our module.
We also had another issue- we wanted the user to be able to easily edit the Header and Footer. That meant they couldn’t live on the Global site. More on how I solved that problem later.
To initially create the module for Blog, I navigated to /sitecore/system/Settings/Feature and inserted a Module. Under system areas, I only checked off Settings and Branches.
I found the Branch for my new module under /sitecore/templates/Branches. Here I inserted two items: Blog Pages and Blog Page Designs. Blog Pages held the pages that would go under the Home item. Blog Page Designs contained Page Designs.
Here, we see another problem: there is nothing under Partial Designs, because this Page Design does not live under a site. To address this, I had to view the raw value for Partial Designs. I copied in the Partial Design GUIDs from the Global Partial Designs for Blog.
We are left with two problems: 1) How to insert the header and footer and 2) How to map the page designs to the Page Designs item. The second may seem like an easy post-step for the user. However, this quickly becomes a hindrance the more Page Designs you create.
In a separate module, I built out the header and footer partials. For every module, I then added a Powershell script to add this header and footer to all the page designs.
Import-Function Get-SiteItem
$SiteItem = Get-SiteItem $Site
$header = Get-Item -Path “master://$($SiteItem.Paths.Path)/Presentation/Partial Designs/Header”
$metadata = Get-Item -Path “master://$($SiteItem.Paths.Path)/Presentation/Partial Designs/Metadata”
$footer = Get-Item -Path “master://$($SiteItem.Paths.Path)/Presentation/Partial Designs/Footer”
$pageDesigns = Get-Item -Path “master://$($SiteItem.Paths.Path)/Presentation/Page Designs”
$items = $pageDesigns.Children
foreach ($item in $items) {
$item.Locking.Unlock()
$item.Editing.BeginEdit()
if(!$item.Fields[‘PartialDesigns’].Value.Contains($header.ID)) {
$item.Fields[‘PartialDesigns’].Value = “$($item.Fields[‘PartialDesigns’].Value)|$($header.ID)|$($metadata.ID)|$($footer.ID)”
}
$item.Editing.EndEdit()
}
Mapping the page designs took another Powershell script, which required slight variations to each module. I added this as a “Post Setup Step”.
Import-Function Get-SiteItem
$SiteItem = Get-SiteItem $Site
$value = “”
$blogPageID = “{9E655297-B109-4673-ACB8-D661C9007736}”
$blogLandingPageID = “{066C976E-5E05-46DB-BC09-AC8008B5C776}”
$blogPageDesign = Get-Item -Path “master://$($SiteItem.Paths.Path)/Presentation/Page Designs/Blog Page”
$blogPageDesignID = [System.Web.HttpUtility]::UrlEncode($blogPageDesign.ID)
$blogLandingPageDesign = Get-Item -Path “master://$($SiteItem.Paths.Path)/Presentation/Page Designs/Blog Landing Page”
$blogLandingPageDesignID = [System.Web.HttpUtility]::UrlEncode($blogLandingPageDesign.ID)
$value = “$value&$blogPageID=$blogPageDesignID”
$value = “$value&$blogLandingPageID=$blogLandingPageDesignID”
#get Page Designs Item
$pageDesigns = Get-Item -Path “master://$($SiteItem.Paths.Path)/Presentation/Page Designs”
#set templates to design mapping
$pageDesigns.Locking.Unlock()
$pageDesigns.Editing.BeginEdit()
$pageDesigns.Fields[‘TemplatesMapping’].Value = $pageDesigns.Fields[‘TemplatesMapping’].Value + [System.Web.HttpUtility]::UrlEncode($value)
$pageDesigns.Editing.EndEdit()
With these steps, you should now have a module that on site creation, instantaneously sets up everything needed for a site to have a Blog Landing Page with Blog Pages.
Shout out to Mark Van Alst in Technical Marketing and Alan Plocieniak on the SXA team for steering me in the right direction!