Unicorn serialization for Helix Multisite Sitecore Solution

Unicorn is a very dynamic tool which provides a way to serialize items even with multisite structure. In Unicorn 4, you can create Tokens/Variables of you own conventions like Feature, Project and Foundation for Helix/Habitat.

In this blog I’ll take you through the steps to serialize multisite (Helix Based) items using Tokens.

In multi-site structure settings, media and data-store are defined on site and as well as global level. In the example shown in the screenshot below I have defined Data-Store on Global and Sites (Website A and B) level.

multisitesitecore-multi-site

 

Data-Store folders have features/modules data items on Site and Global level. In this example I’m considering Teasers items to be serialized.

Let’s first take a look on the abstract tokenized unicorn configuration

<configuration name="Helix.Feature" abstract="true" extends="Helix.Base">
   <include name="Templates" database="master" path="/sitecore/templates/$(layer)/$(module)" children="true" />
   <include name="Renderings" database="master" path="/sitecore/layout/renderings/$(layer)/$(module)" children="true" />
   <include name="Media" database="master" path="/sitecore/media library/$(layer)/$(site)/$(module)" children="true" />
   <include name="Module" database="master" path="/sitecore/content/$(site)/Data-Store/$(module)" children="true" />
   <include name="Module-Global" database="master" path="/sitecore/content/Data-Store/$(module)" children="true" />
</configuration>

If you’re wondering what these $ tokens are doing in the Unicorn configuration then first check Kamsar blog on tokens/convention support and then come back.

There are three tokens defined in the above configuration.

$(layer):  It is the Helix Layer. (e.g Feature, Project, Foundation)

$(module): It is the Helix Feature. (In our case Teaser)

$(site): It would replace the name of the Site. (In our case WebsiteA, WebsiteB)

Please note that the above configuration also extends the Helix.Base where I have defined the Physical Root Path of the serialization folder path.

<configuration name="Helix.Base" abstract="true">
   <predicate type="Unicorn.Predicates.SerializationPresetPredicate, Unicorn" singleInstance="true" />
   <targetDataStore physicalRootPath="$(sourceFolder)\$(layer)\$(module)\serialization\$(site)" useDataCache="false" singleInstance="true" />
</configuration>

Next step is to define unicorn none—abstract configuration which will extend above configuration and replaces the tokens.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
   <unicorn>
     <configurations>
      <configuration name="Feature.WebsiteA.Teasers" description="Feature Teaser for Website A" dependencies="Foundation.*" extends="Helix.Feature">
      </configuration>
      <configuration name="Feature.WebsiteB.Teasers" description="Feature Teaser for Website B" dependencies="Foundation.*" extends="Helix.Feature">
      </configuration>
     </configurations>
   </unicorn>
  </sitecore>
</configuration>

 

Unicorn, while executing the configuration, uses the name of the none-abstract configuration to replace the tokens defined in the abstract configuration.

This is how unicorn will generate the final configuration for itself to serialize the items of Website A.

<include name="Templates" database="master" path="/sitecore/templates/Feature/Teasers" children="true" />

<include name="Renderings" database="master" path="/sitecore/layout/renderings/Feature/Teasers" children="true" />

<include name="Media" database="master" path="/sitecore/media library/Feature/WebsiteA/Teasers" children="true" />

<include name="Module" database="master" path="/sitecore/content/WebsiteA/Data-Store/Teasers" children="true" />

<include name="Module-Global" database="master" path="/sitecore/content/Data-Store/Teasers" children="true" />

Now to make it in action, variables or tokens support needs to be added in Unicorn and for that a pipeline is required.

 

public class CustomConventionVariablesReplacer : ContainerDefinitionVariablesReplacer, IUnicornExpandConfigurationVariablesProcessor
  {

   public void Process(UnicornExpandConfigurationVariablesPipelineArgs args)
     {
      ReplaceVariables(args.Configuration);
     }

   public override void ReplaceVariables(ContainerDefinition definition)
     {
      if (definition.Name == null) throw new ArgumentException("Configuration without a name was used. Add a name attribute to all configurations.", nameof(definition));
      var variables = GetVariables(definition.Name);
      ApplyVariables(definition.Definition, variables);
     }
   public virtual Dictionary<string, string> GetVariables(string name)
     {
      var pieces = name.Split('.');
      if (pieces.Length < 2) return new Dictionary<string, string>();
      var vars = new Dictionary<string, string>
      {
        {"layer", pieces[0]},
        {"site", pieces[1]},
        {"module", pieces[2]}
      };
      if (pieces.Length >= 4)
      {
        vars.Add("moduleConfigName", pieces[3]);
      }
      else
      {
        vars.Add("moduleConfigName", "Dev");
      }
     return vars;
     }
  }

Note that I have created tokens layer, site and module in GetVariable function. These tokens are unique for entire unicorn configuration and cannot be redefined again in the variable pipeline. Here you can create tokens of your own conventions.

Next thing is to add this pipeline in the Unicorn.config pipelines.

 

  <unicornExpandConfigurationVariables>
   <processor type=" Foundation.Serialization.Pipelines.UnicornExpandConfigurationVariables.CustomConventionVariablesReplacer, Foundation.Serialization" />
  </unicornExpandConfigurationVariables>

Finally on serializing items from unicorn.aspx, you will get the files at the location of

PhysicalRootPath\Fearure\Teasers\Serialization\WebsiteA

PhysicalRootPath\Fearure\Teasers\Serialization\WebsiteB

Happy configurations!

Let me know if you have any suggestion, query and better way of doing that.

Leave a Reply

Your email address will not be published. Required fields are marked *

rfwbs-slide