Thursday, March 17, 2016

Sitecore Lucene serach indexing sublayout or rendering data sources

Most Sitecore sites will use renderings or sublayouts in Sitecore as a method to display data, and more often than not the data is a custom template assigned via data source. It's this sort of logic which could then be extended to personalize or A/B test which content works best. The only trouble is ensuring that this content is able to be added to the Lucene search index against the correct item (that which the rendering/sublayout is assigned to).

The following computed index field can be used to index the templates used as datasources against renderings or sublayouts. You may also be interested in indexing child content against an item.

The code will need modification to work in your implementation, but how it works is as follows:
  1. Get all renderings/sublayouts for the item
  2. Filter down to renderings/sublayouts of a desired type (and which have a datasource)
  3. For each datasource, concatenate the desired field to a string and return this string for indexing
The result here is a field in the index which contains the datasource content ready for indexing. It can also be modified to index datasources of multiple types along with multiple fields.
namespace MyProject
{
    /// <summary>
    /// Index rendering/sublayout datasource
    /// </summary>
    public class IndexDataSource : IComputedIndexField
    {
        /// <inheritdoc />
        public string FieldName { get; set; }
        /// <inheritdoc />
        public string ReturnType { get; set; }

        /// <inheritdoc />
        public object ComputeFieldValue(IIndexable indexable)
        {
            Item item = indexable as SitecoreIndexableItem;

            if (item != null && !item.Paths.IsMediaItem) // Don't use this custom field on media items (PDFs)
            {
                var db = item.Database; // Can't use Sitecore.Context in searhc index
                var indexedContent = string.Empty;

                try
                {
                    var allRenderings = item.Visualization.GetRenderings(Sitecore.Context.Device, true);
                    var filteredRenderings = allRenderings.Where(x => x.RenderingItem.Name == "Rich Text" && !string.IsNullOrEmpty(x.Settings.DataSource)); // Filter the renderings

                    if (filteredRenderings.Any())
                    {
                        foreach (var rendering in filteredRenderings)
                        {
                            var datasource = db.GetItem(new Sitecore.Data.ID(rendering.Settings.DataSource)); // Get the datasource

                            if (datasource != null)
                            {
                                var indexField = datasource.Fields["Text"]; // Field to index

                                if (indexField.HasValue)
                                {
                                    indexedContent = indexedContent + Sitecore.StringUtil.RemoveTags(indexField.Value); // Concatenate content without HTML tags
                                }
                            }
                        }

                        return indexedContent;
                    }
                }
                catch (Exception)
                {
                    return null;
                }
            }
           
            return null; // Return null if nothing to index
        }
    }
}
Please note the code would need to be extended to handle rending/sublayout changes based on device along with personalization and A/B multivariate testing.

No comments:

Post a Comment