Skip to content

Instantly share code, notes, and snippets.

@pc-pdx
Forked from kamsar/SubcontentField.cs
Last active July 5, 2018 23:42
Show Gist options
  • Save pc-pdx/622228da307a56453647e03064b26f4c to your computer and use it in GitHub Desktop.
Save pc-pdx/622228da307a56453647e03064b26f4c to your computer and use it in GitHub Desktop.
Subcontent Computed Field
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.FinalLayoutField]);
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)
{
dataSource.Fields.ReadAll();
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; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment