Insert options, and their proper configuration is the crucial part of the solution development. It is the only way how to provide a way to the content editors to create new content.

Unfortunately, regardless that Helix is the current buzzword, still, there are some areas, where Sitecore does not provide out-of-the-box support for the stricter following of Helix principles.

One of them are Insert options configuration.

Generally, there are two ways how to configure Insert options for the specific item (or its template):

template standard values

item rules

Template standard values are a good place for Insert options definition, but in a dynamical, modular and multisite solution it is not enough and we need a more dynamic way provided by item rules.

So, how the rule-based insert options look? Let’s look on the /sitecore/system/Settings/Rules/Insert Options item:

There is a flat structure, without any separation of owning modules. And if you try to create some subfolders and put rules inside of them, nothing will happen. It is not supported. And it makes a comfortable way to configure structured serializing configuration in Unicorn very hard.

But, fortunately, there is a solution and way how to extend the searching logic and add some structure into.

uiGetMasters pipeline

When Sitecore needs to get a list of the insert options for any item, it internally calls the uiGetMasters pipeline. And this is the place, which we can extend to add support Helix structure in insert options.

Following code represents the sample code of uiGetMasters pipeline:

/// <summary> /// <see cref="HelixInsertOptionsRules"/> allows using Helix principles also in insert options rules. /// </summary> public class HelixInsertOptionsRules { /// <summary> /// Gets or sets a collection of folders where insert options will be executed. /// </summary> public List<string> InsertOptionsFolders { get; set; } = new List<string>(); /// <summary> /// Executes processor. /// </summary> /// <param name="args">Pipeline arguments.</param> public void Process(GetMastersArgs args) { var rulesList = new List<Item>(); foreach (var insertOptionFolder in this.InsertOptionsFolders) { rulesList.AddRange(this.GetInsertOptionsRules(args.Item.Database, insertOptionFolder)); } var rules = RuleFactory.GetRules<InsertOptionsRuleContext>(rulesList, "Rule"); if (rules == null) { return; } var insertOptionsContext = new InsertOptionsRuleContext { Item = args.Item, InsertOptions = args.Masters }; rules.Run(insertOptionsContext); } /// <summary> /// Gets a collection of insert options in <paramref name="rootPath"/>. /// </summary> /// <param name="database">Database where insert options will be searched.</param> /// <param name="rootPath">Root path where insert options will be searched.</param> /// <returns>Collection of insert options.</returns> protected IEnumerable<Item> GetInsertOptionsRules(Database database, string rootPath) { return database.SelectItems("{rootPath}//*[@@templateid='{664E5035-EB8C-4BA1-9731-A098FCC9127A}']"); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 /// <summary> /// <see cref="HelixInsertOptionsRules"/> allows using Helix principles also in insert options rules. /// </summary> public class HelixInsertOptionsRules { /// <summary> /// Gets or sets a collection of folders where insert options will be executed. /// </summary> public List < string > InsertOptionsFolders { get ; set ; } = new List < string > ( ) ; /// <summary> /// Executes processor. /// </summary> /// <param name="args">Pipeline arguments.</param> public void Process ( GetMastersArgs args ) { var rulesList = new List < Item > ( ) ; foreach ( var insertOptionFolder in this . InsertOptionsFolders ) { rulesList . AddRange ( this . GetInsertOptionsRules ( args . Item . Database , insertOptionFolder ) ) ; } var rules = RuleFactory . GetRules < InsertOptionsRuleContext > ( rulesList , "Rule" ) ; if ( rules == null ) { return ; } var insertOptionsContext = new InsertOptionsRuleContext { Item = args . Item , InsertOptions = args . Masters } ; rules . Run ( insertOptionsContext ) ; } /// <summary> /// Gets a collection of insert options in <paramref name="rootPath"/>. /// </summary> /// <param name="database">Database where insert options will be searched.</param> /// <param name="rootPath">Root path where insert options will be searched.</param> /// <returns>Collection of insert options.</returns> protected IEnumerable < Item > GetInsertOptionsRules ( Database database , string rootPath ) { return database . SelectItems ( "{rootPath}//*[@@templateid='{664E5035-EB8C-4BA1-9731-A098FCC9127A}']" ) ; } }

Code is pretty straightforward – it just traverses a collection of pre-configured folders and adds their insert options rules into the collection for processing.

To make everything working, just a small configuration patch needs to be added into the Sitecore configuration:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <processors> <uiGetMasters> <processor mode="on" type="HelixInsertOptionsRules, Assembly" patch:before="processor[@type='Sitecore.Pipelines.GetMasters.CheckSecurity, Sitecore.Kernel']"> <InsertOptionsFolders hint="list"> <InsertOptionsFolder >/sitecore/system/Settings/Rules/Insert Options/Rules/Foundation</InsertOptionsFolder> <InsertOptionsFolder>/sitecore/system/Settings/Rules/Insert Options/Rules/Feature</InsertOptionsFolder> <InsertOptionsFolder>/sitecore/system/Settings/Rules/Insert Options/Rules/Project</InsertOptionsFolder> </InsertOptionsFolders > </processor> </uiGetMasters> </processors> </sitecore> </configuration> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 < configuration xmlns : patch = "http://www.sitecore.net/xmlconfig/" > < sitecore > < processors > < uiGetMasters > < processor mode = "on" type = "HelixInsertOptionsRules, Assembly" patch : before = "processor[@type='Sitecore.Pipelines.GetMasters.CheckSecurity, Sitecore.Kernel']" > < InsertOptionsFolders hint = "list" > < InsertOptionsFolder > / sitecore / system / Settings / Rules / Insert Options / Rules / Foundation < / InsertOptionsFolder > < InsertOptionsFolder > / sitecore / system / Settings / Rules / Insert Options / Rules / Feature < / InsertOptionsFolder > < InsertOptionsFolder > / sitecore / system / Settings / Rules / Insert Options / Rules / Project < / InsertOptionsFolder > < / InsertOptionsFolders > < / processor > < / uiGetMasters > < / processors > < / sitecore > < / configuration >

And now, we can organize our Insert options in a structured way, with easy configuration of Unicorn serialization.