Take the community feedback survey now.

Per Magne Skuseth
Jan 27, 2016
  4355
(0 votes)

EPiServer Find: Index blocks in XhtmlString

Many users use blocks in their XhtmlString properties. However, when an XhtmlString field is being indexed by EPiServer Find, the block content does not get included in the field value. This could lead to users not getting relevant search hits if the term they are searching for resides in a block inside an XhtmlString field.
Below you will find an example on how you could include the block text content to the XhtmlString field value in the EPiServer Find index.

I have written an extension method for XhtmlStrings that returns a string with both block text content and the static text content. It loops through each fragment of the property and appends the values using a StringBuilder

   1: public static string ToBlocksIncludedString(this XhtmlString xhtmlString)
   2: {
   3:     var sb = new StringBuilder();
   4:     if (xhtmlString != null && xhtmlString.Fragments.Any())
   5:     {
   6:         var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
   7:         foreach (IStringFragment fragment in xhtmlString.Fragments.GetFilteredFragments(PrincipalInfo.AnonymousPrincipal))
   8:         {
   9:             // the content fragments contains the referenced blocks
  10:             if (fragment is ContentFragment)
  11:             {
  12:                 var contentFragment = fragment as ContentFragment;
  13:                 if (contentFragment.ContentLink != null &&
  14:                     contentFragment.ContentLink != ContentReference.EmptyReference)
  15:                 {
  16:                     var referencedContent = contentLoader.Get<IContent>(contentFragment.ContentLink);
  17:                     sb.Append(referencedContent.SearchText() + " ");
  18:                 }
  19:             }
  20:             else if (fragment is StaticFragment)
  21:             {
  22:                 // ... and the static fragments contains the static text in the XhtmlString
  23:                 var staticFragment = fragment as StaticFragment;
  24:                 sb.Append(staticFragment.InternalFormat + " ");
  25:             }
  26:         }
  27:     }
  28:     return sb.ToString();
  29: }

 

Include the value in the SearchText field

If you are using Unified Search, you should add the new value to the SearchText field. For IContent, the SearchText field is a combination of all string-based properties from the current content that has not been marked with [Searchable(false)], and will automatically added to the index by standard conventions.
Override the field by adding a property named SearchText on your content type.

   1: public class StandardPage : SitePageData
   2: {
   3:     [Searchable(false)]
   4:     public virtual XhtmlString MainBody { get; set; }
   5:  
   6:     [RemoveHtmlTagsWhenIndexing]
   7:     public string SearchText => this.SearchText() + " " +  MainBody.ToBlocksIncludedString();
   8: }

Make sure that the original XhtmlString property has “Searchable” set to false, or you’ll get both the ToBlocksIncludedString value and the standard value of the XhtmlString property added to the SearchText field.

 

Changing the default indexing behavior for all XhtmlStrings

If you always want to include the block content for you XhtmlStrings, you could do this by adding a few conventions in an initializable module. In the example below, the standard value, named “AsViewedByAnonymous” in the index, is replaced by the new value.

   1: [InitializableModule]
   2: [ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
   3: public class FindFieldInitialization : IInitializableModule
   4: {
   5:     public void Initialize(InitializationEngine context)
   6:     {
   7:         SearchClient.Instance.Conventions.ForType<XhtmlString>().ExcludeField(x => x.AsViewedByAnonymous());
   8:         SearchClient.Instance.Conventions.ForType<XhtmlString>().IncludeField(x => x.ToBlocksIncludedString());
   9:         SearchClient.Instance.Conventions.ForType<XhtmlString>().Field(x => x.ToBlocksIncludedString()).Modify(x => x.PropertyName = "AsViewedByAnonymous" + TypeSuffix.String);
  10:     }
  11:  
  12:     public void Uninitialize(InitializationEngine context){}
  13: }
Jan 27, 2016

Comments

Please login to comment.
Latest blogs
A day in the life of an Optimizely OMVP - Opticon London 2025

This installment of a day in the life of an Optimizely OMVP gives an in-depth coverage of my trip down to London to attend Opticon London 2025 held...

Graham Carr | Oct 2, 2025

Optimizely Web Experimentation Using Real-Time Segments: A Step-by-Step Guide

  Introduction Personalization has become de facto standard for any digital channel to improve the user's engagement KPI’s.  Personalization uses...

Ratish | Oct 1, 2025 |

Trigger DXP Warmup Locally to Catch Bugs & Performance Issues Early

Here’s our documentation on warmup in DXP : 🔗 https://docs.developers.optimizely.com/digital-experience-platform/docs/warming-up-sites What I didn...

dada | Sep 29, 2025

Creating Opal Tools for Stott Robots Handler

This summer, the Netcel Development team and I took part in Optimizely’s Opal Hackathon. The challenge from Optimizely was to extend Opal’s abiliti...

Mark Stott | Sep 28, 2025

Integrating Commerce Search v3 (Vertex AI) with Optimizely Configured Commerce

Introduction This blog provides a technical guide for integrating Commerce Search v3, which leverages Google Cloud's Vertex AI Search, into an...

Vaibhav | Sep 27, 2025

A day in the life of an Optimizely MVP - Opti Graph Extensions add-on v1.0.0 released

I am pleased to announce that the official v1.0.0 of the Opti Graph Extensions add-on has now been released and is generally available. Refer to my...

Graham Carr | Sep 25, 2025