Unicorn serialization for Sitecore SXA

Getting started with Unicorn serialization for Sitecore Experience Accelerator (SXA) – part 2

In this article, I will show you my approach to setup Unicorn serialization for Sitecore Experience Accelerator (SXA) 1.8 using Sitecore 9.1.0 and Unicorn 4.0.7. This is the second part of the series of posts about Unicorn serialization. If you would like to start from the very beginning and read an introduction to Unicorn have a look at part 1. If you do not feel comfortable with Helix principles please check the documentation because I assumed that understanding of basic concepts is a prerequisite for the rest of the article.

Sitecore structure

For the demo purpose, I created a single-tenant solution with one shared site and one not shared site. To make it very generic I used “TenantName” as the name of the tenant, “YourSiteName” as the name of the site that is not shared and “SharedSiteName” for the shared site.

Sitecore SXA structure

I made a few assumptions:

  • Shared Site is going to be changed only by developers – this means we want to deploy it always. The Shared Site will be our centralised repository for styles, data sources, page designs, partial designs, and rendering variants with other sites inside of the same tenant.
  • Your Site is going to be changed both by authors and by developers – we have to be careful to do not overwrite content. In my setup, I included root items like Home, Media, Data, Presentation and Settings but excluded anything underneath Home and Data folder. I considered also another approach to deploying only items that do not currently exist in your Sitecore instance but I did not cover this in here.

Visual Studio solution structure

For the Visual Studio solution, I created a regular Helix structure. There are three layers which contain projects inside, let’s have a brief overview of what we have in each of the project’s configurations before we will dive into details.

  • Foundation
    • Serialization – This project will be serialized first because everything else depends on it. It contains Unicorn setup (Unicorn NuGet package was installed in here) and has all the root items for particular layers (Project, Feature, Foundation) serialized.
  • Feature – we will talk about that later.
  • Project
    • Common – Sitecore items that are shared between the sites e.g. tenant root folders, languages, workflows etc.
    • SharedSite – Items related to the Shared Site.
    • YourSite – Content for the particular site.

SXA project solution structure

 

Creating a generic configuration

Considering that in a few months there will be lots of different projects in the solution I wanted to prepare as generic configuration as possible so the developers in my team can just extend it and we can reduce the amount of code and possibility of forgetting about something that actually has to be included.

If you had a look at Sitecore Habitat you can see a file called Unicorn.Helix.config used with base configurations for each layer of the solution. If you add this file to your configuration, in your projects you can extend each of the predefined configurations: Helix.Base, Helix.Foundation, Helix.Feature, Helix.Project.

Unicorn.Helix.config:

<!-- ******************************************************************** Unicorn Helix configurations Defines standard configurations for modules in all layers ******************************************************************** See Unicorn.config for commentary on how configurations operate, or https://github.com/kamsar/Unicorn/blob/master/README.md -->

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
    <sitecore role:require="Standalone or ContentManagement">
        <unicorn>
            <configurations>
                <!-- Base configuration for all modules -->
                <configuration name="Helix.Base" abstract="true">
                    <predicate type="Unicorn.Predicates.SerializationPresetPredicate, Unicorn" singleInstance="true" />

                    <targetDataStore physicalRootPath="$(sourceFolder)\$(layer)\$(module)\serialization" useDataCache="false" singleInstance="true" />
                    <roleDataStore type="Unicorn.Roles.Data.FilesystemRoleDataStore, Unicorn.Roles" physicalRootPath="$(sourceFolder)\$(layer)\$(module)\serialization\Roles" singleInstance="true" />
                    <rolePredicate type="Unicorn.Roles.RolePredicates.ConfigurationRolePredicate, Unicorn.Roles" singleInstance="true">
                        <!-- Include an invalid predicate or all roles will be synced -->
                        <include domain="invaliddomain" pattern="none" />
                    </rolePredicate>
                </configuration>

                <!-- Foundation modules -->
                <configuration name="Helix.Foundation" abstract="true" extends="Helix.Base">
                    <predicate>
                        <include name="Templates" database="master" path="/sitecore/templates/$(layer)/$(module)" />
                    </predicate>
                </configuration>

                <!-- Feature modules -->
                <configuration name="Helix.Feature" abstract="true" extends="Helix.Base">
                    <predicate>
                        <include name="Templates" database="master" path="/sitecore/templates/$(layer)/$(module)" />
                        <include name="Renderings" database="master" path="/sitecore/layout/renderings/$(layer)/$(module)" />
                        <include name="Media" database="master" path="/sitecore/media library/$(layer)/$(module)" />
                    </predicate>
                </configuration>

                <!-- Project modules -->
                <configuration name="Helix.Project" abstract="true" extends="Helix.Base">
                    <predicate>
                        <include name="Templates" database="master" path="/sitecore/templates/$(layer)/$(module)" />
                        <include name="Renderings" database="master" path="/sitecore/layout/renderings/$(layer)/$(module)" />
                    </predicate>
                </configuration>
                <syncConfiguration type="Unicorn.Loader.DefaultSyncConfiguration, Unicorn" singleInstance="true" updateLinkDatabase="true" updateSearchIndex="true" maxConcurrency="1" />
                <userDataStore type="Unicorn.Users.Data.FilesystemUserDataStore, Unicorn.Users" physicalRootPath="$(sourceFolder)\$(layer)\$(module)\serialization\Users\" singleInstance="true" />
            </configurations>
        </unicorn>
    </sitecore>
</configuration>

I think that idea to have some base configurations defined in this way is brilliant, so… why do not create something similar for SXA? To do so you have to understand basic SXA concepts pretty well and a few things may not be obvious when you are just starting with your first SXA project.

Before I have decided which Sitecore item goes to which configuration I needed to answer a very important question:

What should be treated as a feature project in SXA?

When I started working on the first SXA project, I felt really confused what should be treated as a feature in SXA. Single component? Or components category? Or module? Is module the actual category from the toolbox or can be a different one? How about features that are not SXA components, but require some sitecore templates to be created? Or fully functional requirements that need to be created as features?

After the analysis, I decided to distinguish three types of features configurations I will have:

  1. SXA modules – A group of renderings with a similar purpose. I decided to create a new module for each toolbox category and for each module create a new feature project.
  2. Non-SXA modules – Contain only some templates that are not really the SXA modules e.g. some settings items.
  3. Purely functional features – Do not require any sitecore items in configuration or require a completely custom configuration, so the generic configuration is not needed here.

The analysis above allowed me to divide the configurations in the following way:

Unicorn SXA Helix base configuration:

  • Helix.Base – base configuration for all the other generic configurations or for custom configurations, defines the path on disk where the Unicorn serialized items are stored (targetDataStore).
  • Helix.Foundation – configuration for Foundation projects which are not SXA modules, contains only /sitecore/templates.
  • Helix.Feature – configuration for Feature projects which are not SXA modules, contains only /sitecore/templates.
  • Helix.Project – my project layer had three quite different projects inside so I cleaned this one up.
  • Helix.XA.Module – this is the biggest difference comparing to the Habitat Unicorn.Helix.config. This contains configuration including all of the items that are automatically created when you add a new SXA module. This does not contain a layer in the name because it is allowed to create SXA modules in Feature and Foundation. You can use this configuration in both cases.

Why do we need Helix.XA.Module configuration?

When SXA module is created you can notice that it creates also:

  • /sitecore/templates/Feature/TenantName/ModuleName
  • /sitecore/templates/Branches/Feature/TenantName/ModuleName
  • /sitecore/system/Settings/Feature/TenantName/ModuleName
  • /sitecore/layout/Renderings/Feature/TenantName/ModuleName
  • /sitecore/media library/Feature/TenantName/ModuleName
  • /sitecore/layout/Placeholder Settings/Feature/TenantName/ModuleName
  • /sitecore/layout/Layouts/Feature/TenantName/ModuleName

Because all of the items are created automatically I cannot see a reason why we should add them all manually to every feature when we create one. So these items will be automatically included if in your foundation/feature project you will extend Helix.XA.Module configuration.

So when finally when we have a look at my version of Unicorn.Helix.config, it looks like below and will be added in the Foundation.Serialization project.

Unicorn.Helix.config:
<!-- ******************************************************************** Unicorn Helix configurations Defines standard configurations for modules in all layers ******************************************************************** See Unicorn.config for commentary on how configurations operate, or https://github.com/kamsar/Unicorn/blob/master/README.md -->

<!-- ******************************************************************** I changed this file to fit SXA purposes ******************************************************************** -->

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
  <sitecore role:require="Standalone or ContentManagement">
    <unicorn>
      <configurations>
        <!-- Base configuration for all modules -->
        <configuration name="Helix.Base" abstract="true">
          <predicate type="Unicorn.Predicates.SerializationPresetPredicate, Unicorn" singleInstance="true" />
          <targetDataStore physicalRootPath="$(sourceFolder)\$(layer)\$(module)\serialization" useDataCache="false" singleInstance="true" />
        </configuration>

        <!-- Foundation non-SXA modules -->
        <configuration name="Helix.Foundation" abstract="true" extends="Helix.Base">
          <predicate>
            <include name="Templates" database="master" path="/sitecore/templates/$(layer)/TenantName/$(module)" />
          </predicate>
        </configuration>

        <!-- Foundation/Feature SXA modules -->
        <configuration name="Helix.XA.Module" abstract="true" extends="Helix.Base">
          <predicate>
            <include name="Templates" database="master" path="/sitecore/templates/$(layer)/TenantName/$(module)" />
            <include name="Renderings" database="master" path="/sitecore/layout/renderings/$(layer)/TenantName/$(module)" />
            <include name="System.Settings" database="master" path="/sitecore/system/Settings/$(layer)/TenantName/$(module)" />
            <include name="Templates.Branches" database="master" path="/sitecore/templates/Branches/$(layer)/TenantName/$(module)" />
            <include name="PlaceholderSettings" database="master" path="/sitecore/layout/Placeholder Settings/$(layer)/TenantName/$(module)" />
            <include name="Layouts" database="master" path="/sitecore/layout/Layouts/$(layer)/TenantName/$(module)" />
          </predicate>
        </configuration>
        
        <!-- Feature non-SXA modules -->
        <configuration name="Helix.Feature" abstract="true" extends="Helix.Base">
          <predicate>
            <include name="Templates" database="master" path="/sitecore/templates/$(layer)/TenantName/$(module)" />
          </predicate>
        </configuration>

        <!-- Project modules -->
        <configuration name="Helix.Project" abstract="true" extends="Helix.Base">
          <predicate>
            <!-- This will be configured individually because Project layer is a bit different than the rest. -->
          </predicate>
        </configuration>
        <syncConfiguration type="Unicorn.Loader.DefaultSyncConfiguration, Unicorn" singleInstance="true" updateLinkDatabase="true" updateSearchIndex="true" maxConcurrency="1" />
        <userDataStore type="Unicorn.Users.Data.FilesystemUserDataStore, Unicorn.Users" physicalRootPath="$(sourceFolder)\$(layer)\$(module)\serialization\Users\" singleInstance="true" />
      </configurations>
    </unicorn>
  </sitecore>
</configuration>

Foundation.Serialization

In this project, the Unicorn 4.0.7 NuGet package has been installed, which created the Unicorn folder with all the default configurations.

Unicorn configuration in “Foundation” folder contains the root items for Project, Feature and Foundation items and root folders for e.g. Workflows and Tasks. This project will be synchronised as a first one and any other configuration depends on that.

“z.Unicorn” folder contains customizations to Unicorn, because they are prefixed with “z” they will be patched after the base Unicorn files. In our case, there is the base configuration (Unicorn.Helix.config) and shared secret.


SXA Foundation.Serialization configuration

 

SitecoreExamples.Foundation.Serialization.Serialization.config:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
  <sitecore role:require="Standalone or ContentManagement">
    <unicorn>
      <configurations>
        <configuration name="Foundation.Serialization" description="Root items" extends="Helix.Base">
          <predicate>
            <!-- Templates -->
            <include name="Templates.Foundation" database="master" path="/sitecore/templates/Foundation">
              <exclude children="true" />
            </include>
            <include name="Templates.Feature" database="master" path="/sitecore/templates/Feature">
              <exclude children="true" />
            </include>
            <include name="Templates.Project" database="master" path="/sitecore/templates/Project">
              <exclude children="true" />
            </include>

            <!-- Branches -->
            <include name="Branches.Foundation" database="master" path="/sitecore/templates/Branches/Foundation">
              <exclude children="true" />
            </include>
            <include name="Branches.Feature" database="master" path="/sitecore/templates/Branches/Feature">
              <exclude children="true" />
            </include>
            <include name="Branches.Project" database="master" path="/sitecore/templates/Branches/Project">
              <exclude children="true" />
            </include>

            <!-- Layouts -->
            <include name="Layouts.Foundation" database="master" path="/sitecore/layout/layouts/Foundation">
              <exclude children="true" />
            </include>
            <include name="Layouts.Feature" database="master" path="/sitecore/layout/layouts/Feature">
              <exclude children="true" />
            </include>
            <include name="Layouts.Project" database="master" path="/sitecore/layout/layouts/Project">
              <exclude children="true" />
            </include>

            <!-- Models -->
            <include name="Models.Foundation" database="master" path="/sitecore/layout/models/Foundation">
              <exclude children="true" />
            </include>
            <include name="Models.Feature" database="master" path="/sitecore/layout/models/Feature">
              <exclude children="true" />
            </include>
            <include name="Models.Project" database="master" path="/sitecore/layout/models/Project">
              <exclude children="true" />
            </include>

            <!-- Placeholder Settings -->
            <include name="PlaceholderSettings.Foundation" database="master" path="/sitecore/layout/placeholder settings/Foundation">
              <exclude children="true" />
            </include>
            <include name="PlaceholderSettings.Feature" database="master" path="/sitecore/layout/placeholder settings/Feature">
              <exclude children="true" />
            </include>
            <include name="PlaceholderSettings.Project" database="master" path="/sitecore/layout/placeholder settings/Project">
              <exclude children="true" />
            </include>

            <!-- Renderings -->
            <include name="Renderings.Foundation" database="master" path="/sitecore/layout/renderings/Foundation">
              <exclude children="true" />
            </include>
            <include name="Renderings.Feature" database="master" path="/sitecore/layout/renderings/Feature">
              <exclude children="true" />
            </include>
            <include name="Renderings.Project" database="master" path="/sitecore/layout/renderings/Project">
              <exclude children="true" />
            </include>

            <!--Settings-->
            <include name="Settings.Foundation" database="master" path="/sitecore/system/Settings/Foundation">
              <exclude children="true" />
            </include>
            <include name="Settings.Feature" database="master" path="/sitecore/system/Settings/Feature">
              <exclude children="true" />
            </include>
            <include name="Settings.Project" database="master" path="/sitecore/system/Settings/Project">
              <exclude children="true" />
            </include>

            <!--System-->
            <include database="master" path="/sitecore/system/Tasks">
              <exclude path="Schedules" />
            </include>
            <include database="master" path="/sitecore/system/Workflows" >
              <exclude children="true" />
            </include>

            <!-- Media -->
            <include name="Media.Foundation" database="master" path="/sitecore/media library/Foundation">
              <exclude children="true" />
            </include>
            <include name="Media.Feature" database="master" path="/sitecore/media library/Feature">
              <exclude children="true" />
            </include>
            <include name="Media.Project" database="master" path="/sitecore/media library/Project">
              <exclude children="true" />
            </include>

            <!--Content-->
            <include name="Content" database="master" path="/sitecore/content">
              <exclude children="true" />
            </include>

            <!-- Core templates -->
            <include name="Core.Templates.Feature" database="core" path="/sitecore/templates/Feature">
              <exclude children="true" />
            </include>
            <include name="Core.Templates.Foundation" database="core" path="/sitecore/templates/Foundation">
              <exclude children="true" />
            </include>
            <include name="Core.Templates.Project" database="core" path="/sitecore/templates/Project">
              <exclude children="true" />
            </include>

          </predicate>
          <dataProviderConfiguration enableTransparentSync="false" />
          <syncConfiguration updateLinkdatabase="false" updateSearchIndex="false" />
        </configuration>
      </configurations>
    </unicorn>
  </sitecore>
</configuration>

Project.Common

It contains all of the items that are common between different sites e.g. the tenant related root folders, workflows, languages, SXA templates created with a tenant. I added here also Media library items but I excluded items created by Asset Optimizer (in case you switched it on) because they are created dynamically.

SitecoreExamples.Common.Website.Serialization.config:
<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <unicorn>
      <configurations>
        <configuration name="Project.Common" description="Content and settings common between different tenants." extends="Helix.Base" patch:after="configuration[@name='Foundation.Serialization']">
          <predicate>
            <!-- Workflows tenant folders with subitems -->
            <include name="System.Workflows.TenantName" database="master" path="/sitecore/system/Workflows/TenantName" />

            <!-- System languages -->
            <include name="System.Languages" database="master" path="/sitecore/system/Languages" />

            <!-- TenantName tenant root folders -->
            <!-- Templates -->
            <include name="Templates.Foundation.TenantName" database="master" path="/sitecore/templates/Foundation/TenantName">
              <exclude children="true" />
            </include>
            <include name="Templates.Feature.TenantName" database="master" path="/sitecore/templates/Feature/TenantName" >
              <exclude children="true" />
            </include>
            <include name="Templates.Project.TenantName" database="master" path="/sitecore/templates/Project/TenantName" >
              <exclude children="true" >
                <!-- SXA templates added by default with tenant setup -->
                <except name="Home" />
                <except name="Page" />
                <except name="Page Design" />
                <except name="Page Design Folder" />
                <except name="Page" />
                <except name="Page Designs" />
                <except name="Partial Design" />
                <except name="Partial Design Folder" />
                <except name="Partial Designs" />
                <except name="Settings" />
                <except name="Site" />
                <except name="Tenant" />
              </exclude>
            </include>

            <!-- Branches -->
            <include name="Branches.Foundation.TenantName" database="master" path="/sitecore/templates/Branches/Foundation/TenantName" >
              <exclude children="true" />
            </include>
            <include name="Branches.Feature.TenantName" database="master" path="/sitecore/templates/Branches/Feature/TenantName">
              <exclude children="true" />
            </include>
            <include name="Branches.Project.TenantName" database="master" path="/sitecore/templates/Branches/Project/TenantName" >
              <exclude children="true" />
            </include>

            <!-- Layouts -->
            <include name="Layouts.Foundation.TenantName" database="master" path="/sitecore/layout/layouts/Foundation/TenantName" >
              <exclude children="true" />
            </include>
            <include name="Layouts.Feature.TenantName" database="master" path="/sitecore/layout/layouts/Feature/TenantName" >
              <exclude children="true" />
            </include>
            <include name="Layouts.Project.TenantName" database="master" path="/sitecore/layout/layouts/Project/TenantName">
              <exclude children="true" />
            </include>

            <!-- Models -->
            <include name="Models.Foundation.TenantName" database="master" path="/sitecore/layout/models/Foundation/TenantName">
              <exclude children="true" />
            </include>
            <include name="Models.Feature.TenantName" database="master" path="/sitecore/layout/models/Feature/TenantName" >
              <exclude children="true" />
            </include>
            <include name="Models.Project.TenantName" database="master" path="/sitecore/layout/models/Project/TenantName">
              <exclude children="true" />
            </include>

            <!-- Placeholder Settings -->
            <include name="PlaceholderSettings.Foundation.TenantName" database="master" path="/sitecore/layout/placeholder settings/Foundation/TenantName" >
              <exclude children="true" />
            </include>
            <include name="PlaceholderSettings.Feature.TenantName" database="master" path="/sitecore/layout/placeholder settings/Feature/TenantName" >
              <exclude children="true" />
            </include>
            <include name="PlaceholderSettings.Project.TenantName" database="master" path="/sitecore/layout/placeholder settings/Project/TenantName" >
              <exclude children="true" />
            </include>

            <!-- Renderings -->
            <include name="Renderings.Foundation.TenantName" database="master" path="/sitecore/layout/renderings/Foundation/TenantName" >
              <exclude children="true" />
            </include>
            <include name="Renderings.Feature.TenantName" database="master" path="/sitecore/layout/renderings/Feature/TenantName" >
              <exclude children="true" />
            </include>
            <include name="Renderings.Project.TenantName" database="master" path="/sitecore/layout/renderings/Project/TenantName" >
              <exclude children="true" />
            </include>

            <!--Settings-->
            <include name="Settings.Foundation.TenantName" database="master" path="/sitecore/system/Settings/Foundation/TenantName" >
              <exclude children="true" />
            </include>
            <include name="Settings.Feature.TenantName" database="master" path="/sitecore/system/Settings/Feature/TenantName" >
              <exclude children="true" />
            </include>
            <include name="Settings.Project.TenantName" database="master" path="/sitecore/system/Settings/Project/TenantName" >
              <exclude children="true" />
            </include>

            <!--System-->
            <include name="System.Tasks" database="master" path="/sitecore/system/Tasks/Schedules/TenantName" />

            <!-- Media -->
            <include name="Media.Foundation.TenantName" database="master" path="/sitecore/media library/Foundation/TenantName" />
            <include name="Media.Feature.TenantName" database="master" path="/sitecore/media library/Feature/TenantName" />
            <include name="Media.Project.TenantName" database="master" path="/sitecore/media library/Project/TenantName" />
            <include name="Media.TemplateThumbnails" database="master" path="/sitecore/media library/System/Template Thumbnails" />

            <!--Themes-->
            <include name="Media.Themes.TenantName" database="master" path="/sitecore/media library/Themes/TenantName" >
              <!-- Excluding files generated by Asset Optimizer, they are dynamically updated if needed during page requests -->
              <exclude path="TenantName/Scripts/optimized-min" />
              <exclude path="TenantName/styles/optimized-min" />
            </include>

            <!--Content -->
            <include name="Applications.WebEdit.CustomExperienceButtons" database="core" path="/sitecore/content/Applications/WebEdit/Custom Experience Buttons/TenantName" />

            <include name="Content.TenantName" database="master" path="/sitecore/content/TenantName" >
              <exclude children="true" />
            </include>
           </predicate>
          <syncConfiguration updateLinkDatabase="false" updateSearchIndex="true" maxConcurrency="16" type="Unicorn.Loader.DefaultSyncConfiguration, Unicorn" singleInstance="true" />
        </configuration>
      </configurations>
    </unicorn>
  </sitecore>
</configuration>

Besides that, in the Common project, we have dev settings, where the Unicorn “sourceFolder” path was set. You should update the path so it points to the physical location of your project on disk.

z.Common.Website.DevSettings.config:
<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:env="http://www.sitecore.net/xmlconfig/env/">
  <sitecore>
    <!-- Required for Unicorn -->
    <sc.variable env:require="dev" name="sourceFolder" value="C:\Projects\SitecoreExamples\src" />
  </sitecore>
</configuration>	

The sourceFolder that you set above will be used for the configuration base in:

Unicorn.Helix.config
<targetDataStore physicalRootPath="$(sourceFolder)\$(layer)\$(module)\serialization" useDataCache="false" singleInstance="true" />

SharedSite.Website

In here I added all of the content items that are related to the Shared Site and templates related to this site. Because this configuration includes content items I decided to update the search index and the link database if there are any changes for this configuration.

SitecoreExamples.SharedSiteName.Website.Serialization.config:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
  <sitecore role:require="Standalone or ContentManagement">
    <unicorn>
      <configurations>
        <configuration name="Project.SharedSiteName" description="Shared site specific root folders" dependencies="Foundation.*,Feature.*,Project.Common" extends="Helix.Base" patch:after="configuration[@name='Project.Common']">
          <predicate>
            <include name="Content.TenantName.SharedSiteName" database="master" path="/sitecore/content/TenantName/SharedSiteName" />
            <include name="Templates.Project.TenantName.SharedSiteName" dataSharedSiteName="master" path="/sitecore/templates/Project/TenantName/SharedSiteName" />
          </predicate>
          <dataProviderConfiguration enableTransparentSync="false" />
          <syncConfiguration updateLinkDatabase="false" updateSearchIndex="true" />
        </configuration>
      </configurations>
    </unicorn>
  </sitecore>
</configuration>

YourSite.Website

This configuration is related to the site that is not shared. Because the content will be changed by Authors and Developers I excluded everything underneath Home, Media and Data. Because I assume that the Authors will not be touching the Settings and Presentation I included all the items. The same as for shared site after syncing this configuration we want to rebuild the search index and link database.

SitecoreExamples.YourSiteName.Website.Serialization.config:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
  <sitecore role:require="Standalone or ContentManagement">
    <unicorn>
      <configurations>
        <configuration name="Project.YourSiteName" description="Contains all the content items for YourSite" dependencies="Foundation.*,Feature.*,Project.Common,Project.Base" extends="Helix.Base" patch:after="configuration[@name='Project.Base']">
          <predicate>
            <include name="Content.TenantName.YourSiteName" database="master" path="/sitecore/content/TenantName" >
              <exclude path="YourSiteName/Home" />
              <exclude path="YourSiteName/Media" />
              <exclude childrenOfPath="YourSiteName/Data/*" />
            </include>
          </predicate>
          <dataProviderConfiguration enableTransparentSync="false" />
          <syncConfiguration updateLinkDatabase="true" updateSearchIndex="true" />
        </configuration>
      </configurations>
    </unicorn>
  </sitecore>
</configuration>

A feature which is not SXA module

This is an example usage of the configuration for a functional feature which needs only some sitecore templates defined. It seems that this configuration is empty but notice that it extends the Helix.Feature configuration from Unicorn.Helix.config, which means that the templates for this project will be serialized even if you would not include anything extra in this file.

SitecoreExamples.Feature.FeatureWhichIsNotSxaModule.Serialization.config:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
  <sitecore role:require="Standalone or ContentManagement">
    <unicorn>
      <configurations>
        <configuration name="Feature.FeatureWhichIsNotSxaModule" description="Use this project as an example of configuration for feature that is not created as SXA module e.g. for functional requirements." dependencies="Foundation.Serialization" extends="Helix.Feature" patch:after="configuration[@name='Foundation.Serialization']">
          <predicate>
            <!-- By default serializes templates only (if this section is empty), check the base configuration in Unicorn.Helix.config -->
          </predicate>
          <dataProviderConfiguration enableTransparentSync="false" />
          <syncConfiguration updateLinkDatabase="false" updateSearchIndex="false" />
        </configuration>
      </configurations>
    </unicorn>
  </sitecore>
</configuration>

A feature which is SXA module

This is an example of a configuration for the feature that contain SXA module. By default includes:

  • /sitecore/templates/Feature/TenantName/ModuleName
  • /sitecore/templates/Branches/Feature/TenantName/ModuleName
  • /sitecore/system/Settings/Feature/TenantName/ModuleName
  • /sitecore/layout/Renderings/Feature/TenantName/ModuleName
  • /sitecore/media library/Feature/TenantName/ModuleName
  • /sitecore/layout/Placeholder Settings/Feature/TenantName/ModuleName
  • /sitecore/layout/Layouts/Feature/TenantName/ModuleName
SitecoreExamples.Feature.SxaModule.Serialization.config:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
  <sitecore role:require="Standalone or ContentManagement">
    <unicorn>
      <configurations>
        <configuration name="Feature.FeatureWhichIsSxaModule" description="Use this project as an example of configuration for feature that is SXA module." dependencies="Foundation.Serialization" extends="Helix.XA.Feature" patch:after="configuration[@name='Foundation.Serialization']">
          <predicate>
            <!-- By default serializes all items created with SXA module, check the base configuration in Unicorn.Helix.config -->
          </predicate>
          <dataProviderConfiguration enableTransparentSync="false" />
          <syncConfiguration updateLinkDatabase="false" updateSearchIndex="false" />
        </configuration>
      </configurations>
    </unicorn>
  </sitecore>
</configuration>

Summary

In this article I explained my approach to set up Unicorn serialization for Sitecore Experience Accelerator (SXA) project. I hope that this was helpful for you. If you would like to see a different approach to Unicorn setup with SXA, Michael West wrote a great article about that some time ago, check it out!

Please leave a comment if you found the post useful or if you have any suggestions on how to improve it. Any feedback welcome!

2 comments

comments user
betgopa

Awesome !

comments user
Benj Bayfield

This is an excellent article, thanks for posting it! I’m looking to set up something very similar.

In the time since writing this have you had to adapt your approach at all, or is it still sound?

Once again, thanks for sharing this.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.