Custom Unicorn Predicate with advanced exclusions

Reading time ~2 minutes

Have you ever wanted to address some custom serialization case but you couldn’t do it with default predicates? That post might help you.

Introduction

By default Unicorn comes with predicate that allows us to use two types of exlusions:

  • PathBasedPresetTreeExclusion
  • ChildrenOfPathBasedPresetTreeExclusion

This post describes how to extend default predicate and write your own custom exclusions.

Background

IPresetTreeExclusion assumes that we want to make a decision based on item’s path only. That limits us from doing something more sophisticated.

1
2
3
4
5
public interface IPresetTreeExclusion
{
    PredicateResult Evaluate(string itemPath);
    string Description { get; }
}

Just before we pass the path to the Evaluate method we have access to the IItemData object

See what else apart from Path you can find in IItemData type to build custom exclusion logic:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace Rainbow.Model
{
    public interface IItemData : IItemMetadata
    {
        string DatabaseName { get; set; }
        string Name { get; }
        Guid BranchId { get; }
        IEnumerable<IItemFieldValue> SharedFields { get; }
        IEnumerable<IItemLanguage> UnversionedFields { get; }
        IEnumerable<IItemVersion> Versions { get; }
        IEnumerable<IItemData> GetChildren();
    }

    public interface IItemMetadata
    {
        Guid Id { get; }
        Guid ParentId { get; }
        Guid TemplateId { get; }
        string Path { get; }
        string SerializedItemId { get; }
    }
}

The main goal is to pass whole IItemData instead and use all properties/methods inside evaluator.

Let’s do this!

Custom Predicate

To levrage all serialization data we have to overwrite the default SerializationPresetPredicate.

I won’t go through this process. You can see the whole code in my Sitecore.Playground repository,

CustomSerializationPresetPredicate commit.

I will just highlight few things:

  • IPresetItemExclusion.cs - replacement for IPresetTreeExclusion. It will provide different Evaluate method signature
  • CustomSerializationPresetPredicate.cs - replacement for SerializationPresetPredicate. It will be responsible for parsing additional config nodes and invoking advanced exlusions
  • CustomPresetTreeRoot - replacement for PresetTreeRoot. It will extend existing class by adding AdvancedExclusions collection to the type
1
public IList<IPresetItemExclusion> AdvancedExclusions { get; set; }

That’s it. Now you can write your custom exclusions. Read next section to see how I used it to exclude items by templateId

Following solution does not overwrite default Unicorn functionality, it just enhances existing features.

Custom Exclusions

As an example, I will show you how I implemented exclusion by templateId

The code is pretty easy. Instead of implementing IPresetTreeExclusion we implement our custom interface: IPresetItemExclusion.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TemplateBasedPresetExclusion : IPresetItemExclusion
{
    private readonly string _excludeChildrenOfTemplate;
    public TemplateBasedPresetExclusion(string getExpectedAttribute, CustomPresetTreeRoot root)
    {
        _excludeChildrenOfTemplate = getExpectedAttribute;
    }
    public string Description => "Exclueds items based on ItemData' template id";
    public PredicateResult Evaluate(IItemData itemData)
    {
        if (itemData.TemplateId.Equals(new Guid(_excludeChildrenOfTemplate)))
        {
            return new PredicateResult(false);
        }
        return new PredicateResult(true);
    }
}

In the Evaluate I check whether current TemplateId is equal to excluded template id from the configuration.

Usage

To use advanced exclusion you just have to do two things:

  • change the type attribute value of predicate node
  • add excludeAdvanced node into your include node (this is how I passed the tempalteid into the code, you can use your own approach)
1
2
3
4
5
<predicate type="Sitecore.Playground.Serialization.Predicates.CustomSerializationPresetPredicate, Sitecore.Playground.Serialization" singleInstance="true">
  <include name="Tasks" database="master" path="/sitecore/media library/Default Website">
    <excludeAdvanced templateid="{5DD87B05-6652-47D2-92D4-1718D77D8FCD}" />
  </include>
</predicate>

Summary

The main goal of this post is to show you how you can extend the default Unicorn predicate. As you can see there are few different properties/methods that you can use to build your own exclusions which should cover your crazy ideas.

Hope you like it ;)

SXA 1.3 hotfix: LookupNameLookupValue field type

How to solve the issue with LookupNameLookupValue field type Continue reading

SXA 1.2 upgrade - extra upgrade script

Published on April 20, 2017

SXA Upgrade Tool

Published on April 12, 2017