Last active
September 10, 2018 07:53
-
-
Save kamsar/d6bfcdd2f3ee7163f0f9 to your computer and use it in GitHub Desktop.
Subcontent Computed Field
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Linq; | |
using Blade.Utility; | |
using Sitecore; | |
using Sitecore.ContentSearch; | |
using Sitecore.ContentSearch.ComputedFields; | |
using Sitecore.Data.Fields; | |
using Sitecore.Data.Items; | |
using Sitecore.Layouts; | |
namespace Foo.ContentSearch.ComputedFields | |
{ | |
/// <summary> | |
/// Computed field that contains all textual content of items that are rendering data sources on the current item's layout details | |
/// </summary> | |
public class SubcontentField : IComputedIndexField | |
{ | |
public object ComputeFieldValue(IIndexable indexable) | |
{ | |
var sitecoreIndexable = indexable as SitecoreIndexableItem; | |
if (sitecoreIndexable == null) return null; | |
// find renderings with datasources set | |
var customDataSources = ExtractRenderingDataSourceItems(sitecoreIndexable.Item); | |
// extract text from data sources | |
var contentToAdd = customDataSources.SelectMany(GetItemContent).ToList(); | |
if (contentToAdd.Count == 0) return null; | |
return string.Join(" ", contentToAdd); | |
} | |
/// <summary> | |
/// Finds all renderings on an item's layout details with valid custom data sources set and returns the data source items. | |
/// </summary> | |
protected virtual IEnumerable<Item> ExtractRenderingDataSourceItems(Item baseItem) | |
{ | |
string currentLayoutXml = LayoutField.GetFieldValue(baseItem.Fields[FieldIDs.LayoutField]); | |
if (string.IsNullOrEmpty(currentLayoutXml)) yield break; | |
LayoutDefinition layout = LayoutDefinition.Parse(currentLayoutXml); | |
// loop over devices in the rendering | |
for (int deviceIndex = layout.Devices.Count - 1; deviceIndex >= 0; deviceIndex--) | |
{ | |
var device = layout.Devices[deviceIndex] as DeviceDefinition; | |
if (device == null) continue; | |
// loop over renderings within the device | |
for (int renderingIndex = device.Renderings.Count - 1; renderingIndex >= 0; renderingIndex--) | |
{ | |
var rendering = device.Renderings[renderingIndex] as RenderingDefinition; | |
if (rendering == null) continue; | |
// if the rendering has a custom data source, we resolve the data source item and place its text fields into the content to add | |
if (!string.IsNullOrWhiteSpace(rendering.Datasource)) | |
{ | |
// DataSourceHelper is a component of Blade | |
var dataSource = DataSourceHelper.ResolveDataSource(rendering.Datasource, baseItem); | |
if (dataSource != baseItem) | |
{ | |
yield return dataSource; | |
} | |
} | |
} | |
} | |
} | |
/// <summary> | |
/// Extracts textual content from an item's fields | |
/// </summary> | |
protected virtual IEnumerable<string> GetItemContent(Item dataSource) | |
{ | |
foreach (Field field in dataSource.Fields) | |
{ | |
// this check is what Sitecore uses to determine if a field belongs in _content (see LuceneDocumentBuilder.AddField()) | |
if (!IndexOperationsHelper.IsTextField(new SitecoreItemDataField(field))) continue; | |
string fieldValue = (field.Value ?? string.Empty).StripHtml(); | |
if (!string.IsNullOrWhiteSpace(fieldValue)) yield return fieldValue; | |
} | |
} | |
public string FieldName { get; set; } | |
public string ReturnType { get; set; } | |
} | |
} |
Doesn't iterating over all devices run the risk of duplicating some/most of the text? Would it be better to choose the one that gives the best text for indexing. Which one would be implementation dependent.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
you rock. thanks.
not sure there's a better way to propose a gist update, but in interest of extending lessons learned back to the blog (also updated a fork if my lousy note-patch is unclear):
40-
var currentLayoutXml = LayoutField.GetFieldValue(baseItem.Fields[FieldIDs.LayoutField]);
40+
var currentLayoutXml = LayoutField.GetFieldValue(baseItem.Fields[FieldIDs.FinalLayoutField]);
-> Updates currentLayoutXml to use FinalLayoutField (where the datasources are!)
80+
dataSource.Fields.ReadAll();
-> ensures dataSource FieldCollection._fields is populated with all fields