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:

sitecore-item-created-ifttt

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:

http://YourInstance/sitecore/api/ssc/item/Some_Guid/children?fields=ItemId,ItemName,TemplateName

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:

ODataItemAPIKey

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:

http://demo.helixbase/sitecore/api/ssc/aggregate/content/Items(‘/sitecore/content/Home’)?sc_apikey=1234

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

SitecorePostman

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:

sitecore_rocket

“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.”

amazon-appsstore-us-black-v2Get_it_on_iBooks_Badge_US_1114google-play-badge

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:
TBC
Profile Cards:
TBC
Tracking:
Sitecore.Analytics.Data.TrackingField

‘Simple Types’ fields:

Checkbox:
Sitecore.Data.Fields.CheckboxField
Date:
Sitecore.Data.Fields.DateField
Datetime:
Sitecore.Data.Fields.DateField
File:
Sitecore.Data.Fields.FileField
Image:
Sitecore.Data.Fields.ImageField
Integer:
TBC
Multi-Line Text:
Sitecore.Data.Fields.TextField
Number:
TBC
Password:
TBC
Rich Text:
Sitecore.Data.Fields.HtmlField
Single-Line Text:
Sitecore.Data.Fields.TextField
Word Document:
Sitecore.Data.Fields.WordDocumentField

‘Social’ fields:

Accounts Multilist:
Sitecore.Data.Fields.MultilistField
Campaign Tree:
Sitecore.Data.Fields.ReferenceField
Countable Edit:
Sitecore.Data.Fields.TextField

‘List Types’ fields:

Checklist:
Sitecore.Data.Fields.MultilistField
Droplist:
Sitecore.Data.Fields.ValueLookupField
Grouped Droplink:
Sitecore.Data.Fields.GroupedDroplinkField
Grouped Droplist:
Sitecore.Data.Fields.GroupedDroplistField
Multilist:
Sitecore.Data.Fields.MultilistField
Multilist with Search:
Sitecore.Data.Fields.MultilistField
Name Lookup Value List:
Sitecore.Data.Fields.NameValueListField
Name Value List:
Sitecore.Data.Fields.NameValueListField
Treelist:
Sitecore.Data.Fields.MultilistField
TreelistEx:
Sitecore.Data.Fields.MultilistField

‘Link Types’ fields:

Droplink:
Sitecore.Data.Fields.LookupField
Droptree:
Sitecore.Data.Fields.ReferenceField
General Link:
Sitecore.Data.Fields.LinkField
General Link with Search:
Sitecore.Data.Fields.LinkField
Version Identity:
TBC
Version Link:
Sitecore.Data.Fields.VersionLinkField

‘Developer Types’ fields:

Icon:
TBC
IFrame:
TBC
Tristate:
TBC
Sitecore User:
TBC

‘System Types’ fields:

Attachment:
TBC
Custom:
Sitecore.Data.Fields.CustomCustomField
Datasource:
Sitecore.Data.Fields.DatasourceField
File Drop Area:
Sitecore.Data.Fields.FileDropAreaField
Internal Link:
Sitecore.Data.Fields.InternalLinkField

Page Preview:
Sitecore.Data.Fields.PagePreviewField
Query Builder:
TBC
Query Datasource:
TBC
Rendering Datasource:
Sitecore.Data.Fields.RenderingDatasourceField
Rules:
Sitecore.Data.Fields.RulesField
Security:
Sitecore.Data.Fields.TextField
Template Field Source:
Sitecore.Data.Fields.TemplateFieldSourceField
Thumbnail:
Sitecore.Data.Fields.ThumbnailField
VisitorFilterRules:
TBC

‘Deprecated Types’ fields:

html:
Sitecore.Data.Fields.HtmlField
link:
Sitecore.Data.Fields.LinkField
lookup:
Sitecore.Data.Fields.LookupField
memo:
Sitecore.Data.Fields.TextField
reference:
Sitecore.Data.Fields.ReferenceField
server file:
TBC
text:
Sitecore.Data.Fields.TextField
tree:
Sitecore.Data.Fields.ReferenceField
tree list:
Sitecore.Data.Fields.MultilistField
Treelist with Search:
Sitecore.Data.Fields.MultilistField
valuelookup:
Sitecore.Data.Fields.ValueLookupField
Single-Line Text:
Sitecore.Data.Fields.WordDocumentField

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.AutoMap();
                config.TemplateId(Templates.IDerived.TemplateId);
                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:

helix

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="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <contentSearch>
      <indexConfigurations>
        <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" />
            </typeMatches>
            <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"/>
            </fieldNames>
          </fieldMap>
          <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>
          </fields>
        </defaultSolrIndexConfiguration>
      </indexConfigurations>
    </contentSearch>
  </sitecore>
</configuration>

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

Sitecore.Commerce.Products.Solr.Index.Common.config
Sitecore.Commerce.Products.Solr.Index.Master.config
Sitecore.Commerce.Products.Solr.Index.Webconfig
Sitecore.Commerce.Products.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!