Sitecore – Revisiting token substitutions with Snippets

A previous post, token substitutions in the Rich Text Editor using IFormattable , shows an elegant way to replace tokens with Dictionary entries.

As promised, I’ll show a quick and dirty way to make it easy for the content editor to add these new tokens, via snippets.

Instead of populating the snippets drop down in the rich text editor, you could certainly add your own drop down list within the rich text editor but it has a few more steps.  Here’s a great post from jammykam for that: Adding custom drop down list to rich text editor in Sitecore .

This is a bit simpler and lines up with the previous post.

Roll your own EditorConfiguration

Override the SetupSnippets method in your custom EditorConfiguration class that inherits from Sitecore.Shell.Controls.RichTextEditor.EditorConfiguration.

(You can choose to show or not show the snippets for the rich text editor created in the core database: /sitecore/system/Settings/Html Editor Profiles/[your RTE]/Snippets

namespace Sample821.Shell.Controls.RichTextEditor
{
 public class EditorConfiguration 
           : Sitecore.Shell.Controls.RichTextEditor.EditorConfiguration
 {
 public EditorConfiguration(Sitecore.Data.Items.Item profile) : base(profile){}

  protected override void SetupSnippets()
 {
 // allow the base to set up the snippet structure
 base.SetupSnippets();

 // If you don't want to use any of the snippets that are in the core db ...
 Editor.Snippets.Clear();

 // add your snippets based on your custom template
 Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");

 Sitecore.Data.Items.Item parentDictionary =
 master.GetItem("/sitecore/content/SampleSite/Token Dictionary");

 if ((parentDictionary == null) || (!parentDictionary.HasChildren)) return;

 foreach (Sitecore.Data.Items.Item folder in
 parentDictionary.Children)
 {
 //if u have a folder structure ... less expensive than .GetDescendants()
 if (!folder.HasChildren) continue;

 foreach (Sitecore.Data.Items.Item entry in folder.Children)
   {
      if (string.IsNullOrEmpty(entry["Key"])) continue;

      var snippet = string.Format("{{0:{0}}}",entry["Key"]);

      Editor.Snippets.Add(entry["Key"], snippet);
    }
 }
 }
 }
}

Add a new patch configuration file and change the EditorConfiguration in Sitecore.config to your new one

<setting name="HtmlEditor.DefaultConfigurationType">
  <patch:attribute name="value">
      Sample821.Shell.Controls.RichTextEditor.EditorConfiguration,Sample821
  </patch:attribute>
 </setting>

Test the result

The content editor experience is now much easier to handle the tokens.

snippet2

You may ask .. why not use the snippet to replace the text with the value in the dictionary entry?  That is certainly possible but defeats the purpose of having the dictionary entry in one place … to easily change it … in. one. place.

Combine this with the previous post and you’ll add reusable functionality for your content editing staff.

 

Advertisements

Sitecore – Revisiting token substitutions with IFormattable

Most CMSs offer a form of token replacement for commonly used words and phrases within the text that the content editor controls. Sitecore doesn’t deliver this out of the box; it requires some customizations.  This post is extending on the Token Substitution section of Reusing and Sharing Data using a Sitecore 8.2 example site.

Summary:

  • Add a processor to the RenderField pipeline
  • Make use of multiple Dictionary Domains
  • Use IFormattable for token replacement functionality

IFormattable utility

The IFormattable interface provides a way of formatting the value of an object into a string representation. The method, IFormattable.ToString(string, IFormatProvider) must be implemented.  It supplies formatting services for the implementing type.  Inside here, we can plug in some code to perform replacements against the dictionary domain.

Below, the constructor is providing an argument for bringing in the dictionary domain name.

The ToString() method requests the string to format and the formatProvider, which returns a formatting object that has defined the symbols used in converting an object to its string representation.  In this case, it is an instance of the class.  It calls the GetDictionaryDomainValue() method which takes advantage of Sitecore’s Translate.TextByDomain() functionality.

TextByDomain() takes two arguments.  The first is the dictionary domain name and the second is the replacement text to replace.

 public class ContentFieldFormattable : IFormattable
 {
  private readonly string _dictionaryDomain;

  public ContentFieldFormattable(string dictionaryDomain)
  {
     _dictionaryDomain = dictionaryDomain;
  }

  public string ToString(string format, IFormatProvider formatProvider)
  {
     return GetDictionaryDomainValue(format);
  }

  public string GetDictionaryDomainValue(string replacementText)
  {
   return Sitecore.Globalization.Translate
            .TextByDomain(_dictionaryDomain, replacementText);
   }
 }

RenderField pipeline

Configuration file

The GetTokenDictionaryReplacements processor is patched in to the RenderField pipeline.  It contains a <DictionaryDomain> child item which provides the processor with the name of the Sitecore dictionary domain to use.

token-replacement-config

Pipeline processor

The processor has a property, DictionaryDomain, which accepts the child node from the configuration file renderField entry.

The ContentFieldFormattable class is instantiated, passing along the DictionaryDomain; this object serves as the format provider in the string.Format method.

public class GetTokenDictionaryReplacements
 {
    public string DictionaryDomain { get; set; }
    public virtual void Process(RenderFieldArgs args)
    {
      Assert.ArgumentNotNull((object)args, "args");

      if (Sitecore.Context.Site == "shell") return;

      if (Sitecore.Context.PageMode.IsExperienceEditor) return;

      ContentFieldFormattable cff = new ContentFieldFormattable(DictionaryDomain);

      args.Result.FirstPart = (args.Result.FirstPart == null) 
                 ? null 
                 : string.Format(args.Result.FirstPart, cff);
      args.Result.LastPart = (args.Result.LastPart == null) 
                 ? null 
                 : string.Format(args.Result.LastPart, cff);
     }
 }

Token Dictionary setup

A separate dictionary domain is recommended.  Inherit from  /sitecore/templates/System/Dictionary/Dictionary Domain when creating the top node.

sitecore-content-tree
Token Dictionary Domain

Example

The rich text field below has three tokens defined.  With a single call to the IFormattable ToString() method, all values are replaced.

sitecore-rtf-example

Rich text field with tokens

website-sample-page

Site after replacements

Fallback domain dictionary

You can also set a fallback domain on the dictionary domain.  In the event that the value is not defined as a dictionary entry in the initial dictionary domain, a Fallback Domain dictionary may be queried.

sitecore-fallback-dictionary

In the next blog post, I’ll show how to provide the Content Editor with an easy ability to add these to the Rich Text Editor.

References:

https://sitecorecontextitem.wordpress.com/2014/06/06/you-should-probably-start-using-sitecore-dictionary-domains/