By using my Skybrud.Umbraco.GridData package (which introduces a strongly typed model for the Grid), indexing the new Grid in Umbraco 7.2 is quite easy.
At Skybrud.dk we typically create a class named ExamineIndexer that takes care of the Examine related events. This class should be initalized during Umbraco startup like this:
using Umbraco.Core;
namespace FanoeTest {
public class Startup : ApplicationEventHandler {
private static ExamineIndexer _examineIndexer;
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) {
// Register events for Examine
_examineIndexer = new ExamineIndexer();
}
}
}The ExamineIndexer class it self will now look like the example below. The example is very specific, since only certain document types where we know that the content property holds a Grid value are handled.
The example could be modified to use the Content Service for finding all properties that holds a Grid value. But since the Content Service uses the database, it may slow the performance when building your index.
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Examine;
using Examine.Providers;
using Skybrud.Umbraco.GridData;
using Skybrud.Umbraco.GridData.Values;
using Umbraco.Core.Logging;
namespace FanoeTest {
public class ExamineIndexer {
public ExamineIndexer() {
BaseIndexProvider externalIndexer = ExamineManager.Instance.IndexProviderCollection["ExternalIndexer"];
externalIndexer.GatheringNodeData += OnExamineGatheringNodeData;
}
private void OnExamineGatheringNodeData(object sender, IndexingNodeDataEventArgs e) {
try {
string nodeTypeAlias = e.Fields["nodeTypeAlias"];
LogHelper.Info<ExamineIndexer>("Gathering node data for node #" + e.NodeId + " (type: " + nodeTypeAlias + ")");
if (nodeTypeAlias == "Home" || nodeTypeAlias == "LandingPage" || nodeTypeAlias == "TextPage" || nodeTypeAlias == "BlogPost") {
string value;
if (e.Fields.TryGetValue("content", out value)) {
LogHelper.Info<ExamineIndexer>("Node has \"content\" value\"");
GridDataModel grid = GridDataModel.Deserialize(e.Fields["content"]);
StringBuilder combined = new StringBuilder();
foreach (GridControl ctrl in grid.GetAllControls()) {
switch (ctrl.Editor.Alias) {
case "rte": {
// Get the HTML value
string html = ctrl.GetValue<GridControlRichTextValue>().Value;
// Strip any HTML tags so we only have text
string text = Regex.Replace(html, "<.*?>", "");
// Extra decoding may be necessary
text = HttpUtility.HtmlDecode(text);
// Now append the text
combined.AppendLine(text);
break;
}
case "media": {
GridControlMediaValue media = ctrl.GetValue<GridControlMediaValue>();
combined.AppendLine(media.Caption);
break;
}
case "headline":
case "quote": {
combined.AppendLine(ctrl.GetValue<GridControlTextValue>().Value);
break;
}
}
}
e.Fields["content"] = combined.ToString();
} else {
LogHelper.Info<ExamineIndexer>("Node has no \"content\" value\"");
}
}
} catch (Exception ex) {
LogHelper.Error<ExamineIndexer>("MAYDAY! MAYDAY! MAYDAY!", ex);
}
}
}
}
Nice work!
Can you provide an example for extending the Property Converters you've built in - as an example I have a custom headline grid editor that has value.title and value.subhead values - I know I could access them via JObject, but would prefer the strongly typed model approach. One issue I've also seen with custom grid editors is that sometimes value.subhead will actually be null (subhead wont even exist) if the user never enters anything into that textarea, so not sure if your Value Converter approach handles that?
Thanks,
Matt