Using voice commands to add items to Sitecore. IFTTT: Complete walk through

Having purchased a few Google Home devices my mind turned to getting them to work with Sitecore. Wouldn’t it be cool to tell your Google Home or mobile device to interact with the Sitecore environment?! So I setup a POC to do just that, by using a custom route in an API controller we can create Sitecore items by asking Google Home to “Create Sitecore item [ItemName]“:

First visit the IFTTT Platform where we can add our Applet. By selecting ‘New Applet’ we’re first asked to create a Trigger, for this we select ‘Google Assistant’

Google assistant

This will present us with some options:

google trigger

We’ll be using a phrase with a text ingredient, this allows us to say something like “Hey Google, add [ingredient] to my request”. For the POC this ingredient will be an item name which will be used to add an item to Sitecore under /sitecore/content/Home/Google Home

Now we’ll tell Google that our phrase will be “Create Sitecore item [ItemName]:

google assitant sitecore

And we need a reply from the device we’re speaking to:

google assistant sitecore response

Great, so we’ve got an “if this”, now it’s time for a “then that”. Our devices know what we’re going to say and know how to respond, so we need to create our API controller in Sitecore that’s going to create the item for us. The rough example I used is below:

    public class GoogleTestController: SitecoreController
        public ActionResult IFTTT(string itemName)
            using (new Sitecore.SecurityModel.SecurityDisabler())
                var masterDb = Sitecore.Data.Database.GetDatabase("master");

                var template = masterDb.GetItem("/sitecore/templates/System/Templates/Standard template");

                var parentItem = masterDb.GetItem("/sitecore/content/Home/Google Home");

                parentItem.Add(itemName, new Sitecore.Data.Items.TemplateItem(template));

                return Content($"{itemName} added");

And we’ll need our custom route

        public void Process(PipelineArgs args)
            RouteTable.Routes.MapRoute("Feature.GoogleTest", "GoogleTest/{itemName}",
                new { controller = "GoogleTest", action = "IFTTT" });

That’s our Sitecore code setup, now we need to add a webhook so that Google Assistant can talk to our Sitecore API. Under ‘then’ we select ‘Add action’ and select ‘Webhooks’:

ifttt then

This presents us with a dropdown and we can select ‘Make a web request’. These fields should be self explanatory, so the one I’ll focus on is the URL. In the below I have used a sample URL but obviously this needs to be a publicly accessible server with the Sitecore item Web API enabled:

Sitecore google api

Now we’re calling our Sitecore API controller, and sending in the name of the item that the user has asked to create. We could stop there and deploy but let’s select ‘Add action’ again and choose ‘notifications’. We want a phone notification when an item has been added to Sitecore:

ifttt notification sitecore

Give the Applet a title and description and save it. The final step is to enable this Applet on our IFTTT devices, simply select ‘Turn on’:

sitecore ifttt applet.png

Once it’s on we can talk to any of the Google devices on our account. I tested this by saying the following to my Google Home… “Ok Google, create Sitecore item test item” I hear the response “Ok, creating item test item on your Sitecore instance”, you can hear her response on this recording. We can then confirm that our device has added the item to Sitecore:

test item sitecore

We also get a nice phone notification:


The possibilities for this one are endless – Sitecore, it’s invading our homes!

Using the OData Item Service in Sitecore 9 – Step by step

Pre Sitecore 9 if we wanted to retrieve Item data we could make use of RESTful services easily with a simple GET HTTP Request. If for example we wanted to get children of an item we could call an endpoint such as:


In Sitecore 9 we also have the introduction of the  OData Item Service so I thought I’d take us through a step by step.

First go to the following item in the Core database:

/sitecore/system/Settings/Services/API Key

Right click the API Key folder and insert an ‘OData Item API Key’. An explanation of the fields for this item can be found in the documentation but here’s my setup with an explanation:


Database – fairly self explanatory, the Sitecore database you’re retrieving an item from.

Search Filter – we can apply search options using an OData filter format, I’ve left this as the default which will return the latest version of items.

CORS Origins – which origins are allowable? Add your required origins separated with a semicolon. As I’m testing this on Helix Base I have added the relevant origin.

AllowedControllers – you may wish to restrict this API Key to certain controllers and can list those here separated with a semicolon. I’m allowing all so have opted for the wildcard *

Impersonation User – you could leave this blank in which case Sitecore will use the default from your Sitecore.Services.AnonymousUser setting. The default is most likely sitecore\ServicesAPI but I’ve added this to the field anyway.

Once we’ve saved the item it’s time to copy the item Id which we can then use in our request headers, or on the endpoint. For example if my item Id is 1234 I could use a Key of sc_apikey  and value 1234 in my headers, or apply it to the endpoint as follows:


Using either approach we can then see the fruits of our labour…


To see a list of endpoints for the OData Item Service see the Sitecore documentation

The Little Book of Sitecore® Tips volume 1 now available

sitecore_netI’m pleased to announce the launch of volume 1 of The Little Book of Sitecore® Tips

The book was created after converting a rather large amount of notes (that were created during my day to day workings with Sitecore) into an initial book, and what will soon become an ongoing series of books.

The main purpose of The Little Book of Sitecore Tips is a light-hearted look at some useful Sitecore tips. These tips are targeted at all levels of user but whethersitecore_book you’re recapping or learning, I hope you find the material either useful, or at least of some entertainment value.

ALL royalties are donated to worthy causes, so if you take nothing from the book at least you’ll know that your purchase wasn’t in vain. So have some fun, support some charity and order yourself a paperback copy from the likes of Amazon or Barnes & Noble – The book is also available as an eBook on the iBooks Store, and Google Play.

Thanks is due to the technical reviewers Adam Conn and Radosław Kozłowski – and a big thanks to Tamas Varga who also supplied a great deal of help, support, and the following review:


“This is the book I should have written 5 years ago! Having a book with tips is something we haven’t got so far in the Sitecore community. It goes beyond just Sitecore tips, but some of the best practices the community created and collected during the last couple of years. It not only helps your daily work with Sitecore, but also demonstrates the power and flexibility of it. All the tips in this book is really helpful and the nice illustrations helps you remember them.”


Full list of Sitecore field types and their C# type mapping

I thought it would be useful to have a list of Sitecore fields and their relevant C# Sitecore.*.Type mapping. I couldn’t find a list so have created one below:

‘Analytics’ fields:

Profile Card Value:
Profile Cards:

‘Simple Types’ fields:

Multi-Line Text:
Rich Text:
Single-Line Text:
Word Document:

‘Social’ fields:

Accounts Multilist:
Campaign Tree:
Countable Edit:

‘List Types’ fields:

Grouped Droplink:
Grouped Droplist:
Multilist with Search:
Name Lookup Value List:
Name Value List:

‘Link Types’ fields:

General Link:
General Link with Search:
Version Identity:
Version Link:

‘Developer Types’ fields:

Sitecore User:

‘System Types’ fields:

File Drop Area:
Internal Link:

Page Preview:
Query Builder:
Query Datasource:
Rendering Datasource:
Template Field Source:

‘Deprecated Types’ fields:

server file:
tree list:
Treelist with Search:
Single-Line Text:

Glass fluent configuration and composite reuse principle

If you’re a fan of the flat structure of composition, rather than the hierarchy of inheritance you will be looking to make an implementation on your Glass Sitecore models and you can read more information about the composition pattern with Glass. However, previously Glass could only handle this by using attribute mapping. For those of us who prefer fluent configuration I created a pull request.

So what does this allow us to do? Let’s look at a very basic example using inheritance, below you can see IBase implemented by IDerived:

using Glass.Mapper.Sc.Fields;
using Helixbase.Foundation.Models.BaseItem;

namespace Helixbase.Feature.Test.Models
    public interface IDerived : IBase
        Image SomeImage { get; set; }

This class could now make use of composition:

using Glass.Mapper.Sc.Fields;
using Helixbase.Foundation.Models.BaseItem;

namespace Helixbase.Feature.Test.Models
    public interface IDerived
        IBase BaseComposition { get; set; }
        Image SomeImage { get; set; }

We then register our mapping using the new ‘Self’ extension method as follows:

using Glass.Mapper.Sc.Maps;
using Helixbase.Feature.Hero.Models;

namespace Helixbase.Feature.Hero.ORM
    public class GlassMappings : SitecoreGlassMap<IDerived>
        public override void Configure()
            Map(config =>
                config.Self(f => f.BaseComposition);
                config.Field(f => f.SomeImage).FieldName("Some Image");

With the new method we can use the composite reuse principle in Sitecore with Glass fluent configuration for our mappings.

Cleaning up your Sitecore Helix webroot with gulp

There’s a common problem when publishing a Sitecore solution whether it’s Helix compliant or not… how we handle old files in our webroot. For example, you may change an assembly name or a view, but both the dll and cshtml files will remain in the webroot which causes obvious problems. Immutable deployments are the answer when deploying to environments other than a localhost, but we need an approach when developing locally.

One way to handle this problem is using a gulp publish and binding a cleanup gulp task to our Visual Studio publish. This is one of the areas that the Helix principles show their worth, if folders are organised on disk we can easily setup a gulp task to delete certain folders rather than using wildcards.

So the first step is to add a cleanup task which will be called by our gulp publish task. The cleanup task should remove the Foundation, Feature, and Project config folders from App_Config before deploying any files. For the dll’s we will need a wildcard:

var cleanProjectFiles = function (layerName) {
    const filesToDelete = [
        gulpConfig.webRoot + '/bin/Helixbase.' + layerName + '.*',
        gulpConfig.webRoot + '/App_Config/Include/' + layerName
    console.log("Removing " + layerName + " configs/binaries");
    return gulp.src(filesToDelete, { read: false })
        .pipe(clean({ force: true }));

The task will clear out the old configs/dll’s before publishing our solution but what about views? Helix doesn’t stipulate that views are organised on disk according to layer or context and the default view engine leaves us with a difficulty. We could use gulp to delete everything except for the Shared folder, but this could be problematic if any view folders change in a future Sitecore update. Another option is to have a whitelist of every view to delete but this isn’t ideal either. While old view files are less problematic it’s a good idea to create a custom multisite View Engine. This would give us options for organising our views on disk in a way that our gulp cleanup task can easily handle, examples being:

Views\Helixbase\SomeModule\Someview.cshtml – then delete the context folder in gulp.

Views\Layer\SomeModule\SomeView.cshtml – then delete the layer folder in gulp.

Finally, when it comes to deploying across environments we need an approach other than transform files if we want to easily use tokens/octopus variables etc. To do this involves adding config files per environment. If we’re following a similar approach we need a way to delete the unwanted config folders using gulp. This can be achieved with a post build cleanup task.

// Note: intended to be called after publishing
gulp.task("Clean-Transform-Configs", function (layerName) {
    const filesToDelete = [
        gulpConfig.webRoot + '/App_Config/Include/' + layerName + '/CD',
        gulpConfig.webRoot + '/App_Config/Include/' + layerName + '/CM'
    console.log("Removing transform configs");
    return gulp.src(filesToDelete, { read: false })
        .pipe(clean({ force: true }));

We would want to call this task after each gulp publish, and can also bind it to the Visual Studio publish:

/// <binding AfterBuild='Clean-Transform-Configs' />

But remember if we’re binding to the Visual Studio publish, we’d need to be able to pass in a layerName. As this cannot be achieved, we could add a condition to the gulp task if the layerName var was empty.

Unicorn config issues – Data at the root level is invalid. Line 1, Position 1.

Strictly speaking this isn’t an issue that relates to the use of Unicorn alone, but as Unicorn uses config files you may notice the following error when creating patch configs on some machines, then trying to access unicorn.aspx:

Data invalid

This issue relates to Byte order mark and can be resolved by opening your config in notepad and saving it in ANSI encoding. Then reopen the config in notepad and you will notice the following:

Data invalid ANSI

Delete the ? character and save your config to resolve the issue.

Helix sketch – package design/SOLID principles in our Sitecore solution

When working on a Sitecore solution we want to follow certain conventions if our product is to be maintainable and reusable. Helix exists to allow us to implement the principles of package design in our solution and obviously the Helix documentation is available to show us how to do this.

It’s not only the conventions of modular design that allow us to decouple and maintain our solution, we should also adhere to the SOLID principles of class design which will allow us to make changes in future with the smallest possible effects on the rest of the code base. If SOLID design prepares us for change, it also allows us to be more Agile.

Taking these two principles into consideration – for my own records I have created a sketch to outline the principles of SOLID design and package design in a Helix solution. No doubt this one will go through some revisions but in case it’s useful to anybody I have shared the diagram with a brief explanation below:


Stable dependencies – packages that are highly stable belong together. Generally a package should only depend on another if it can be considered more stable. When it comes to Helix our Foundation modules can depend upon each other and nothing else. Features cannot depend on each other but can depend on Foundation modules, and anything in Project can depend on any of the other layers.

Stable abstractions – packages should have a dependency based on the direction of how abstract they are. In Helix our Foundation modules are abstract and Project modules are more concrete. As with stable dependencies this presents us with an order of dependency within the solution.

Common closure –  we package modules together to follow common closure which states that classes in a package are closed together against the same types of change. This means that change is limited to the smallest amount of packages possible. In Helix grouping our modules together in our three layers allows us to follow this principle.

SOLID principles – there’s plenty of information about uncle Bob’s principles and we should strive to ensure our classes follow them.

Commerce Connect with Solr causing List Manager errors

If you’re using Solr with Commerce connect (v8.2.326 at time of writing) you could find that it’s no longer possible to add Contacts to a list in the List Manager application. The ribbon error is:

Please note that contacts in the list are currently being indexed, so not all contacts are available to view at this time.

The problem lies in Sitecore.Commerce.Products.Solr.Index.Common.config

In my instance the ‘textCollection’ field type does not contain a field type mapping and will cause List Manager to fail when it tries to re index.

There are two options to resolve the problem, you can either setup a field type mapping in the fieldMap node, something like the following should work (untested):

       <fieldType fieldTypeName="checklist|multilist|treelist|tree list|treelistex|tree list|multilist with search|treelist with search"   returnType="textCollection" />
       <fieldType fieldTypeName="name lookup value list|name value list"                                                                   returnType="textCollection" />
       <fieldType fieldTypeName="droplink|droptree|grouped droplink|tree"                                                                  returnType="textCollection" />

Or the approach I decided upon was to replace all references to ‘textCollection’ with ‘stringCollection’ which has a field mapping in Sitecore.ContentSearch.Solr.DefaultIndexConfiguration.config your Common.config would now appear similar to the following:

<configuration xmlns:patch="">
        <defaultSolrIndexConfiguration type="Sitecore.ContentSearch.SolrProvider.SolrIndexConfiguration, Sitecore.ContentSearch.SolrProvider">
          <fieldMap type="Sitecore.ContentSearch.SolrProvider.SolrFieldMap, Sitecore.ContentSearch.SolrProvider">
            <typeMatches hint="raw:AddTypeMatch">
              <typeMatch typeName="stringCollection" type="System.Collections.Generic.List`1[System.String]" fieldNameFormat="{0}_tm" multiValued="true" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider" />
            <fieldNames hint="raw:AddFieldByFieldName">
              <field fieldName="categoryname"  storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" returnType="stringCollection" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"/>
              <field fieldName="manufacturername"  storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" returnType="stringCollection" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"/>
              <field fieldName="producttypename"  storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" returnType="text" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"/>
              <field fieldName="externalid" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" returnType="stringCollection" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"/>
              <field fieldName="instocklocations" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" returnType="stringCollection" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"/>
              <field fieldName="outofstocklocations" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" returnType="stringCollection" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"/>
              <field fieldName="orderablelocations" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" returnType="stringCollection" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"/>
              <field fieldName="preorderable" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" returnType="text" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"/>
              <field fieldName="productclasses" storageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" returnType="stringCollection" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"/>
          <fields hint="raw:AddComputedIndexField">
            <field fieldName="categoryname" returnType="stringCollection">Sitecore.Commerce.Search.ComputedFields.CategoryName, Sitecore.Commerce</field>
            <field fieldName="manufacturername" returnType="stringCollection">Sitecore.Commerce.Search.ComputedFields.ManufacturerName, Sitecore.Commerce</field>
            <field fieldName="producttypename" returnType="stringCollection">Sitecore.Commerce.Search.ComputedFields.ProductTypeName, Sitecore.Commerce</field>
            <field fieldName="_content" returnType="stringCollection">Sitecore.Commerce.Search.ComputedFields.AddToContent, Sitecore.Commerce</field>
            <field fieldName="instocklocations" returnType="stringCollection">Sitecore.Commerce.Search.ComputedFields.InStockLocations, Sitecore.Commerce</field>
            <field fieldName="outofstocklocations" returnType="stringCollection">Sitecore.Commerce.Search.ComputedFields.OutOfStockLocations, Sitecore.Commerce</field>
            <field fieldName="orderablelocations" returnType="stringCollection">Sitecore.Commerce.Search.ComputedFields.OrderableLocations, Sitecore.Commerce</field>
            <field fieldName="preorderable" returnType="text">Sitecore.Commerce.Search.ComputedFields.PreOrderable, Sitecore.Commerce</field>

Remember to patch the config or it will be overwritten when you update Commerce Connect. You should now be able to add contacts to List Manager but unfortunately we’re not out of the woods just yet:

Any modules you have created that use a search index will not throw an error, instead nothing will be rendered despite a full re-index showing files being added to your core. ‘Sitecore.Commerce’ is executed before ‘Sitecore.ContentSearch’ which will cause this problem.

The following files should be patched in after Sitecore.ContentSearch.Solr.DefaultIndexConfiguration.config


Resolving Helix config file order issues

When using Helix we can experience issues with the order that our config files are loaded. Take the following example:

The file App_Config->Include->Foundation->Foundation.Serialization.Users.config

Would be loaded before App_Config->Include->Unicorn->Unicorn.Users.config

Therefore your Foundation config would be overwritten as the Unicorn folder is patched after the Foundation one. If we use the Helix naming of ‘Foundation’ and ‘Feature’ for our config folders this also means that we can never patch anything in Foundation from a Feature because the Feature folder is loaded first.

Below is one possible solution, we can override the LoadAutoIncludeFiles method:

    public class ConfigReaderHelix : Sitecore.Configuration.ConfigReader
        protected override void LoadAutoIncludeFiles(XmlNode element)
            Assert.ArgumentNotNull((object)element, "element");
            ConfigPatcher configPatcher = GetConfigPatcher(element);
            LoadAutoIncludeFiles(configPatcher, MainUtil.MapPath("/App_Config/Sitecore/Components"));
            LoadAutoIncludeFiles(configPatcher, MainUtil.MapPath("/App_Config/Include"));
            LoadAutoIncludeFiles(configPatcher, MainUtil.MapPath("/App_Config/Include/Foundation"));
            LoadAutoIncludeFiles(configPatcher, MainUtil.MapPath("/App_Config/Include/Feature"));
            LoadAutoIncludeFiles(configPatcher, MainUtil.MapPath("/App_Config/Include/Project"));

We then change the following in the web.config…

<section name=”sitecore” type=”SITE.Foundation.Demo.ConfigReader.ConfigReaderHelix, SITE.Foundation.Demo” />

Our Foundation folder will now be loaded after all other include folders, and before Feature and Project. This solution works but is relatively ‘hacky’ because everything in the Include folder is still loaded before being overwritten by our Foundation/Feature folders. Also our folders will always be loaded last so even if you have a zzFolder in your Include folder it will be loaded before our Helix folders.

A more efficient means could be to override the overloaded LoadAutoIncludeFiles method in the Sitecore Kernel, or there was a suggestion on Sitecore Slack to add our custom configs to a folder outside of the Include folder, and then change the call order as above. Either way it’s food for thought!