Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
Experience Sitecore! | All posts tagged 'Unicorn'

Experience Sitecore!

Martin Miles on Sitecore

Separating content items from definition using Unicorn's NewItemsEvaluator

The vast majority of my readers are already familiar with Unicorn (if not - please take your time to familiarize with it by this link) and understand the principles of how it works. In few words, it serializes your Sitecore items into text files so that you can store them under source control along with the rest of your solution code.Then you can sync these files back into Sitecore, either manually from its admin page, or automatically by PowerShell or deployment script on CI / CD pipeline.  If the item has was changed, Unicorn automatically modifies its serialization file (so that changed file goes to source control to all other developers) and the reverse - newer items from source control will update those in Sitecore. So far, so good.

Problem: your solution infrastructure has numerous environments from lower (Dev) to higher (Prod) where the actual site is running. But not just the site itself - Sitecore also is there. Your content editors will be using Sitecore on prod, bringing plenty changes. But with next deployment all that new content will be automatically overwritten by older serialized items. What is good - now we have Helix principles, that classifies two types of Sitecore items - definition items to be passed along with the rest of solution code and actual content item. For Content items source of truth is Production, while for definition items source of truth is Development. But how do we actually define and set up content items?

Solution: the best automated approach also comes with Unicorn, however almost not documented and very little people know about it. It is called NewItemsEvaluator. Let's take a look at how it works:

By default, Unicorn predicate runs with Master Evaluator, which always overwrites Sitecore item with whatever comes from serialization. Because of Master Evaluator, content items on production will be overwritten by serialization with each deployment's sync unless actions are taken. NewItemsEvaluator also creates an item in Sitecore, but only if that item does not (yet) exist in the target environment. But if the item with such ID already exists there - it won't be affected and overwritten.

Firstly, we need to define what content items are. That typically will be all the items underneath /sitecore/YourProjectName/Home including Home item itself. Also, that will be all items within /sitecore/media library/Project/YourProjectName and items within /sitecore/content/YourProjectName/Global including Global item itself and its folder-based children that have insert options assigned.

Secondly, we need to create a new unicorn predicate for those content items identified. That predicate should be driven by New Item Evaluator:

<evaluator type="Unicorn.Evaluators.NewItemOnlyEvaluator, Unicorn" singleInstance="true" />
Thirdly, we need to exclude content items from the default website predicate driven by Master Evaluator. Luckily, Unicorn comes with handy exclusion syntax (more examples can be found at this link):
<include name="Some children" database="master" path="/sitecore/content/YourWebsite">
  <exclude children="true">
    <except name="Settings" />
    <except name="Global" />
  </exclude>
</include>

Finally, your website project layer serialization configuration file will have two predicate configurations similar to one below:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:localenv="http://www.sitecore.net/xmlconfig/localenv/">
    <sitecore role:require="Standalone or ContentManagement">
        <unicorn>
            <configurations>
                <configuration 
                    name="Project.YourProjectName.Website" 
                    description="YourProjectName content" 
dependencies="Foundation.*,Feature.*,Project.Common" extends="Helix.Project"> <predicate> <include name="Project.YourProjectName.Layouts" database="master" path="/sitecore/layout/layouts/Project/YourProjectName" />
<include name="Project.YourProjectName.PlaceholderSettings" database="master" path="/sitecore/layout/placeholder settings/Project/YourProjectName" />
<include name="Project.YourProjectName.Content" database="master" path="/sitecore/content/YourProjectName">
<exclude path="/sitecore/content/YourProjectName/Home" />
<exclude childrenOfPath="/sitecore/content/YourProjectName/Global/Button Styles" />
<exclude childrenOfPath="/sitecore/content/YourProjectName/Global/Font Styles" />
<exclude childrenOfPath="/sitecore/content/YourProjectName/Global/Image Container Css" />
<exclude childrenOfPath="/sitecore/content/YourProjectName/Global/Landing Css Classes" />
<exclude childrenOfPath="/sitecore/content/YourProjectName/Global/Links/Footer Menu" />
<exclude childrenOfPath="/sitecore/content/YourProjectName/Global/Links/Header Menu" />
<exclude childrenOfPath="/sitecore/content/YourProjectName/Global/Links/Social Media" />
</include> <include name="Project.YourProjectName.Media" database="master" path="/sitecore/media library/Project/YourProjectName">
<exclude children="true" /> </include> <include name="Project.YourProjectName.ExperienceEditor" database="core" path="/sitecore/client/Applications/ExperienceEditor/Pipelines/InitializePageEdit" />
</predicate> <!-- roles and user data stores skipped here --> </configuration> <configuration name="Project.YourProjectName.Website.AuthoredContent"
description="Sample site content (New Item Provider)" dependencies="Foundation.*,Feature.*,Project.YourProjectNamev.Website"
patch:after="configuration[@name='Project.YourProjectName.Website']"
extends="Helix.Project"> <targetDataStore physicalRootPath="$(sourceFolder)\$(layer)\$(module)\serialization\Content" type="Rainbow.Storage.SerializationFileSystemDataStore, Rainbow" useDataCache="false" singleInstance="true" /> <evaluator type="Unicorn.Evaluators.NewItemOnlyEvaluator, Unicorn" singleInstance="true" /> <dataProviderConfiguration enableTransparentSync="false" type="Unicorn.Data.DataProvider.DefaultUnicornDataProviderConfiguration, Unicorn" /> <predicate type="Unicorn.Predicates.SerializationPresetPredicate, Unicorn" singleInstance="true"> <include name="Project.YourProjectName.Home" database="master" path="/sitecore/content/YourProjectName/Home" />
<include name="Project.YourProjectName.Global.ButtonStyles" database="master" path="/sitecore/content/YourProjectName/Global/Button Styles" />
<include name="Project.YourProjectName.Global.FontStyles" database="master" path="/sitecore/content/YourProjectName/Global/Font Styles" />
<include name="Project.YourProjectName.Global.HeroCss Classes" database="master" path="/sitecore/content/YourProjectName/Global/Hero Css Classes" />
<include name="Project.YourProjectName.Global.HeroMobile Background Image" database="master" path="/sitecore/content/YourProjectName/Global/Hero Mobile Background Image" />
<include name="Project.YourProjectName.Global.ImageContainerCss" database="master" path="/sitecore/content/YourProjectName/Global/Image Container Css" />
<include name="Project.YourProjectName.Global.LandingCssClasses" database="master" path="/sitecore/content/YourProjectName/Global/Landing Css Classes" />
<include name="Project.YourProjectName.Global.Recruiters" database="master" path="/sitecore/content/YourProjectName/Global/Recruiters" />
<include name="Project.YourProjectName.Global.HigllightCssClasses" database="master" path="/sitecore/content/YourProjectName/Global/Higllight Css Classes" />
<include name="Project.YourProjectName.Global.TabsCssClasses" database="master" path="/sitecore/content/YourProjectName/Global/Tabs Css Classes" />
<include name="Project.YourProjectName.Global.Leaders" database="master" path="/sitecore/content/YourProjectName/Global/Leaders" />
<include name="Project.YourProjectName.Global.Links.FooterMenu" database="master" path="/sitecore/content/YourProjectName/Global/Links/Footer Menu" />
<include name="Project.YourProjectName.Global.Links.HeaderMenu" database="master" path="/sitecore/content/YourProjectName/Global/Links/Header Menu" />
<include name="Project.YourProjectName.Global.Links.SocialMedia" database="master" path="/sitecore/content/YourProjectName/Global/Links/Social Media" />
<include name="Project.YourProjectName.Media.Content" database="master" path="/sitecore/media library/Project/YourProjectName" />
</predicate> </configuration> </configurations> </unicorn> </sitecore> </configuration>

Hope this helps!

Adding Unicorn icon to Sitecore Launchpad

Seriously, I cannot understand why no one hasn't done that earlier before myself!

Recently, yet another time bookmarking a unicorn.aspx for another specific environment, I caught myself on why not to have Unicorn icon as a standard launchpad tile icon. Benefits of having it there against bookmarking:

  • it becomes available not only for myself but for the rest of admin users in particular environment
  • yes, by saying admin, I want to say that you can customize security for that shortcut
  • if serialized, this icon shortcut becomes available on all the environments it is being deploys

So please welcome Unicorn Launchpad icon. You may download the installation package at the bottom of this blog post.


So, as you might know, all the Launchpad icons are taken from core database and you may find them by the following path:/sitecore/client/Applications/Launchpad/PageSettings/Buttons. So you may add a new icon by simply creating an item called Unicorn (of the template /sitecore/client/Applications/Launchpad/PageSettings/Templates/LaunchPad-Button) as a child of any LaunchPad-Group items (for example, Tools, along with Content Editor).


The much better option would be to duplicate already existing item that is available to admins only - in such case you'll also inherit permissions set) - AppCenter for instance. Once done, adjusts all the fields correspondingly. The most important field to set is Link, so make it pointing to /unicorn.aspx (but remember you may also include parameters, such as unicorn.aspx?verb=sync).

The next challenge is to set an icon. Unicorn is not a part of Sitecore, obviously, Sitecore won't have icon packs for it. Let's create our own icon pack for Unicorn.


Each of these drops down values above (Applications, Apps, Business, Controls etc.), in fact, is a zip archive underneath folder<SITE_ROOT>\sitecore\shell\Themes\Standard.


The structure of archive is the following - unicorn.zip\Unicorn\32x32\Unicorn.png - you may have icons for the other resolutions but I am referencing this one:


That's all the job and it took a couple of minutes!

Download ready to use package (19.7kb, keep in mind that Unicorn icon will be shown to admin users only).

Unicorn - the simplest way to share Sitecore items in the soure control along with your code

Annoyed of the necessity of creating packages with recent items in order to share that with your colleagues? Tired of items' versioning? Why not to version those items in source control then?


My favorite tool for achieving that is Unicorn. It does exactly what it suppose to - syncs certain Sitecore items (recursively with children) within a directory, as configured, so that you are able to check-in the folder with all serialized items, so that your colleagues can sync that changes into their database; that means new features / fixes deliver items deltas simultaneously with their code counterparts.

Here is the example of configuration, whatever sits under mentioned paths (recursively) will be serialized:

    





The greatest thing I love about Unicorn is simplicity - as simple as the following:

  • It installs as NuGet package.
  • Consists of 2 DLLs and a config patch file.
  • Just one control page at the web root to perform sync / revert
  • Simple configuration file.

From limitations I would only mention recursiveness - specifying an item in config processes it will all child items and that cannot be overridden. Of course, this is not a problem in more advanced solution - TDS, but are we here about simplicity?


Installation from NuGet Package Manager Console:

PM> Install-Package Unicorn

See also: GitHub source code

Update: now version 3 has been released with great, even revolutionary, changes and it became more friendly. So, please read: