Searching on module content on pages in Sitecore

When developing search implementation for a Sitecore site, we usually do an index search on the internal _content field which is an accumulation of all the string fields on the current item. Often the pages have a lot of important data on module datasources as opposed to be on the context item itself. We also have reference fields on the context item which might warrant updating the search results based on the business importance of such data.

To ensure that your search functionality also takes into account this additional data while retrieving results, we added a couple of computed fields to account for this data.

  • ModuleContent – This computed field accesses the presentation of an item and finds the renderings with datasources on them. It then adds all the string content on these datasource items to the computed field.
  • ReferenceContent – This computed field accesses all the fields on the context item which are reference fields and iterates through the referenced items to add into the index, the string fields of all these referenced items.
  • Now, while we can create new computed fields, we could also append to _content, which will let the search code unchanged. Writing to the _content field from the computed index field code simply appends the data into the existing field, thus extending it.

    public class ModuleContent : IComputedIndexField
        {
            public string FieldName { get; set; }
            public string ReturnType { get; set; }
    
            public object ComputeFieldValue(IIndexable indexable)
            {
                Item obj = indexable as SitecoreIndexableItem;
                if (obj?.Template == null)
                    return null;
    
                if (obj.Paths.IsContentItem)
                {
                    try
                    {
                        LayoutDefinition layout = LayoutDefinition.Parse(LayoutField.GetFieldValue(obj.Fields["__Renderings"]));
    
                        if (layout.Devices != null && layout.Devices.Count > 0)
                        {
                            DeviceDefinition dev = (DeviceDefinition)layout.Devices[0];
                            ArrayList renderings = dev?.Renderings;
                            if (renderings != null)
                            {
                                IEnumerable<RenderingDefinition> renderingDefinitions = renderings.Cast<RenderingDefinition>();
    
                                foreach (RenderingDefinition renderingDefinition in renderingDefinitions)
                                {
                                    if (renderingDefinition.ItemID != null)
                                    {
                                        if (!string.IsNullOrWhiteSpace(renderingDefinition.Datasource))
                                        {
                                            Item datasource = SitecoreHelper.GetItemByID(renderingDefinition.Datasource);
    
                                            if (datasource != null)
                                            {
                                                return datasource.Fields.Where(f => !f.Name.StartsWith("__")
                                                    && f.Name != IBase_Rendering_AssetsConstants.Rendering_ScriptsFieldName
                                                    && f.Name != IBase_Rendering_AssetsConstants.Rendering_StylesheetsFieldName
                                                    && (f.Type == "Single-Line Text" || f.Type == "Multi-Line Text" || f.Type == "Rich Text"))
                                                    .Select(f => datasource.Fields[f.ID]?.Value).Where(v => !string.IsNullOrWhiteSpace(v));
                                            }
                                        }
                                    }
                                }
                            }
                        }
    
                        return new List<string>();
                    }
                    catch (Exception ex)
                    {
                        Log.Error("Site.Project._classes.Computed_Fields.ModuleContent", ex, this);
                    }
                }
    
                return string.Empty;
            }
        }
    

    In the configuration, we include the computed field:

    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
      <sitecore>
        <contentSearch>
          <indexConfigurations>
            <defaultLuceneIndexConfiguration type="Sitecore.ContentSearch.LuceneProvider.LuceneIndexConfiguration, Sitecore.ContentSearch.LuceneProvider">
              <fields hint="raw:AddComputedIndexField">
                <field fieldName="_content" returnType="stringCollection" storageType="YES">
                  Site.Domain._classes.Computed_Fields.ModuleContent,Site.Domain
                </field>
              </fields>
            </defaultLuceneIndexConfiguration>
          </indexConfigurations>
        </contentSearch>
      </sitecore>
    </configuration>
    

    In a similar manner, we could include the reference item string fields, except we would filter by link / list field tyes like Multilist / Treelist / Droptree / Droplink etc in the code, to get the guids, then items and then string fields on them, to include in the index for the current item.

    When time comes for the search, we would simply do a free text index search on the _content field to get results.

    Hope this helps!

    Advertisements

2 thoughts on “Searching on module content on pages in Sitecore

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 )

Google+ photo

You are commenting using your Google+ 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 )

Connecting to %s