How to extend Sitecore indexing to render datasource items

Posted 11/30/2014 by Debabrata Biswas

We all know that Sitecore can index an item's fields and that we can then search content on those values. As a best practice Sitecore pages are now built using the page editor and placeholders, and hence involve rendering multiple items on a single page. So what if the user is expecting search to crawl through the entire page content (as would a web crawler for instance)?. That would mean extending the Sitecore search indexer to not only index the context item's fields but also all the other items that could be reached through the data sources of rendering sublayouts. The following steps achieve just that:

1. You will need to create a new Sitecore computed field and hence a class for it. Please find the sample code below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Sitecore.ContentSearch;
using Sitecore.ContentSearch.SearchTypes;

using Sitecore.ContentSearch.ComputedFields;
using Sitecore.Data.Items;
using Sitecore.Data;
using Sitecore.Data.Fields;

namespace your_namespace
{
    public class RenderPageContent : IComputedIndexField
    {
        public Database DB
        {
            get
            {
                return Sitecore.Configuration.Factory.GetDatabase("web");
            }
        }

        public DeviceItem Device { get; set; }

        public object ComputeFieldValue(IIndexable indexable)
        {
            var indexableItem = indexable as SitecoreIndexableItem;

            if (indexableItem == null)
            {
                return null;
            }


            StringBuilder sb = new StringBuilder();

            try
            {
                Device = DeviceItem.ResolveDevice(DB);

                Sitecore.Layouts.RenderingReference[] renderings = GetListOfSublayouts(indexableItem.Item);
                if (renderings != null && renderings.Length != 0)
                {
                    List<Item> ListOfDataSource = GetListOfDataSource(renderings)
                        .Where(i => !string.IsNullOrEmpty(i))
                        .Select(i => DB.GetItem(i))
                        .Where(i => i != null)
                        .ToList();

                    foreach (Item dataSourceItem in ListOfDataSource)
                    {
                        foreach (Sitecore.Data.Fields.Field field in dataSourceItem.Fields)
                        {
                            sb.Append(string.Format("{0}|", field.Value));
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                Sitecore.Diagnostics.Log.Error("%%%%%%%%%%%%%%%%%%%%%%%%%%%% " + "NO RENDERINGS FOUND FOR " + indexableItem.Item.Paths.FullPath + " %%%%%%%%%%%%%%%%%%%%%%%", ex, this);
            }

            return sb.ToString();
        }

        private Sitecore.Layouts.RenderingReference[] GetListOfSublayouts(Item item)
        {
            Sitecore.Layouts.RenderingReference[] renderings = null;
            if (item != null)
            {
                if (item.Fields[Sitecore.FieldIDs.LayoutField] != null
                            && !String.IsNullOrEmpty(item.Fields[Sitecore.FieldIDs.LayoutField].Value))
                {
                    renderings = item.Visualization.GetRenderings(Device, false);
                }
            }

            return renderings;
        }

        private List<string> GetListOfDataSource(Sitecore.Layouts.RenderingReference[] renderings)
        {
            List<string> ListOfDataSource = new List<string>();
            foreach (Sitecore.Layouts.RenderingReference rendering in renderings)
            {
                ListOfDataSource.Add(rendering.Settings.DataSource);
            }
            return ListOfDataSource;
        }

        public string FieldName { get; set; }
        public string ReturnType { get; set; }
    }
}

2. The next step is to configure this computed field in the config file. In our case it was Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config:
Add the following under <fieldNames hint="raw:AddFieldByFieldName">
<field fieldName="RenderPageContent" storageType="YES" indexType="TOKENIZED"    vectorType="NO" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
<Analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
      </field>
      
And add the following under <fields hint="raw:AddComputedIndexField">:
<field fieldName="RenderPageContent" storageType="yes">your_namespace.RenderPageContent,your_assembly</field>
3. Now you can index the database using the index manager.
4. Once indexing is complete you can have code like the following in order to search through the pages:
 query = context.GetQueryable<SearchResultItem>()
                            .Where(prod => prod.Language == Sitecore.Context.Language.Name)
                            .Where(prod => prod["_latestversion"] == "1")
                            .Where(prod => prod.Content.Contains(searchTerm)||prod["renderpagecontent"].Contains(searchTerm));

Share:

Archive

Syndication