Sitecore 7 Search – Searching By Inherited Template

After reading a great article this article from a former colleague (Richard Seal – Lead Sitecore Architect @ LightMaker US), I remembered that I to had solved this issue slightly differently some 12 – 18 months back using (originally Lucinq and then) the stock Sitecore 7 search. Non-the less, it fits a lot of what I have been saying in my Don’t Fight The Framework series – in particular – Please Don’t Base Your Code on Exact Templates, so I thought I would cover it again for those who don’t already know.

The problem is that Sitecore doesn’t ( / didn’t) provide a default way of searching for item’s based on their template inheritance hierarchy which means that normally in the out of the box solution you have to search on template (breaking everything I have said in my previous article above). This can be particularly useful for example if we wanted to return ‘All News Articles’ in our Site but you actually have implementations of ‘Press Release News Article’, ‘Industry News Article’ and ‘Budget News Article’

This article describes how I have achieved similar to Richard’s solution has done with Fortis (sorry Richard – I am a Glass fan 😉 ) with the stock Sitecore 7 Search.

I do have to note that I believe Sitecore (at the time I wrote this code originally) provided a similar field in it’s default configuration, but when I wrote this, it was broken (from memory, it only returned the first three levels or something).

The Custom Index Field

In order to index all of the templates that an item inherits from, we need to create ourselves a simple computed index field that gives this information back.


using System.Collections.Generic;

using Sitecore.ContentSearch;
using Sitecore.ContentSearch.ComputedFields;
using Sitecore.ContentSearch.Utilities;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;

namespace xxx.CustomFields
{
    public class TemplatePath : IComputedIndexField
    {
        public string FieldName { get; set; }

        public string ReturnType { get; set; }

        public object ComputeFieldValue(IIndexable indexable)
        {
            return GetAllTemplates(indexable as SitecoreIndexableItem);
        }

        private object GetAllTemplates(Item item)
        {
            Assert.ArgumentNotNull(item, "item");
            Assert.IsNotNull(item.Template, "Item template not found.");
            List<string> list = new List<string> { IdHelper.NormalizeGuid(item.TemplateID) };
            AddTemplateToList(item.Template, ref list);
            return list;
        }

        private void AddTemplateToList(TemplateItem templateItem, ref List<string> list)
        {
            if (templateItem.BaseTemplates == null)
            {
                return;
            }

            foreach (var baseTemplateItem in templateItem.BaseTemplates)
            {
                list.Add(IdHelper.NormalizeGuid(baseTemplateItem.ID));
                AddTemplateToList(baseTemplateItem, ref list);
            }
        }
    }
}

Then to complete this, we obviously need to add this field to our index field configuration.

<field fieldName="_templates" storageType="yes" indexType="untokenized">xxx.CustomFields.TemplatePath, xxx</field>

The search result type

In order to be able to query against the Sitecore 7 search api, we should create ourselves a class to do so, I have inherited from Sitecore’s default SearchResultItem, but you could do this anywhere.

using System.Collections.Generic;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.SearchTypes;
using Sitecore.Data;

namespace xxx
{
    public class ExtendedSearchResultItem : SearchResultItem
    {
        [IndexField("_templates")]
        public IEnumerable<ID> InheritedTemplates { get; set; }
    }
}

Search Code – Sitecore 7

Finally – to search based on the template inheritance, you can simply use:

    using (var context = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
    {
        IQueryable<SearchResultItem> results = context.GetQueryable<ExtendedSearchResultItem>().Where(item => item.InheritedTemplates.Contains(SitecoreIds.MyItemId));
    }

Search Code – Lucinq

Ok – so I couldn’t resist getting this bit in since I had this functionality from Sitecore 6.5 onwards ;), you can read more about this here – Lucinq – Sitecore Querying, but here is a snippet.

ISitecoreQueryBuilder queryBuilder = new SitecoreQueryBuilder();
queryBuilder.TemplateDescendsFrom(SitecoreIds.AdvertTemplateId);
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s