LibrarySites.Banner

Use a Checkbox to Control Section Visibility in the Sitecore ASP.NET CMS

This blog post describes a prototype that can hide sections of data templates after the user selects a checkbox in an item in the Sitecore ASP.NET web Content Management System (CMS) and Experience Platform (XP). I developed this solution to address a request raised in the SDN forum thread linked in the Resources section of this page.

In at least the blog post also linked in the Resources section, I had overridden the EditorFormatter used to render fields in the Content Editor. To use this technique, we insert a processor at the beginning of the renderContentEditor pipeline, which sets the EditorFormatter in the arguments passed to remaining processors in the renderContentEditor pipeline to our override of the EditorFormatter class.

The current request has two significant differences from the previous example: the logic depends on a value in the item selected in the Content Editor, and the logic applies to sections of items rather than to individual fields.

Luckily for the first issue, the arguments passed to the renderContentEditor pipeline are available in the Arguments property of the EditorFormatter, including the item to render, which contains the checkbox as well as the fields to show or hide.

To address the second issue, we need to override the RenderSection() method in the EditorFormatter. Unfortunately, the RenderSection() method is not virtual, so we also need to override the RenderSections() method in EditorFormatter. In this version, if the field named Checkbox in the selected item is selected, the section named Data will not appear.

namespace SitecoreJohn.Shell.Applications.ContentEditor
{
  using System;
  using System.Web.UI;
 
  using Sitecore.Diagnostics;
  using Sitecore.Shell.Applications.ContentManager;
 
  public class EditorFormatter : Sitecore.Shell.Applications.ContentEditor.EditorFormatter
  {
    public new void RenderSection(Editor.Section section, Control parent, bool readOnly)
    {
      Assert.ArgumentNotNull(section, "section");
 
      if (this.Arguments.Item["Checkbox"] != "1"
          || !section.Name.Equals("data", StringComparison.InvariantCultureIgnoreCase))
      {
        base.RenderSection(section, parent, readOnly);
      }
    }
 
    public new void RenderSections(Control parent, Editor.Sections sections, bool readOnly)
    {
      Assert.ArgumentNotNull(parent, "parent");
      Assert.ArgumentNotNull(sections, "sections");
      Sitecore.Context.ClientPage.ClientResponse.DisableOutput();
      this.AddLiteralControl(parent, "<div class=\"scEditorSections\">");
      for (int i = 0; i < sections.Count; i++)
      {
        this.RenderSection(sections[i], parent, readOnly);
      }
      this.AddLiteralControl(parent, "</div>");
      Sitecore.Context.ClientPage.ClientResponse.EnableOutput();
    }
  }
}

Because RenderSections() in turn is not virtual, we also need to override the RenderStandardContentEditor pipeline processor to invoke our override thereof.

namespace SitecoreJohn.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor
{
  using Sitecore.Diagnostics;
  using Sitecore.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor;
 
  public class RenderStandardContentEditor
  {
    public void Process(RenderContentEditorArgs args)
    {
      Assert.ArgumentNotNull(args, "args");
      Assert.ArgumentNotNull(args.EditorFormatter, "args.EditorFormatter");
      SitecoreJohn.Shell.Applications.ContentEditor.EditorFormatter editorFormatter =
        args.EditorFormatter as SitecoreJohn.Shell.Applications.ContentEditor.EditorFormatter;
 
      if (editorFormatter != null)
      {
        editorFormatter.RenderSections(args.Parent, args.Sections, args.ReadOnly);
      }
      else
      {
        args.EditorFormatter.RenderSections(args.Parent, args.Sections, args.ReadOnly);
      }
    }
  }
}

Finally, we have our renderContentEditor pipeline processor that applies our EditorFormatter:

namespace SitecoreJohn.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor
{
  using Sitecore.Diagnostics;
  using Sitecore.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor;
 
  public class SetEditorFormatter
  {
    public void Process(RenderContentEditorArgs args)
    {
      Assert.ArgumentNotNull(args, "args");
      args.EditorFormatter =
        new SitecoreJohn.Shell.Applications.ContentEditor.EditorFormatter();
      args.EditorFormatter.Arguments = args;
    }
  }
}

Until I discovered that Sitecore was not invoking my renderContentEditor processor, I did not realize that by default, the RenderSkinedContentEditor (sic) pipeline processor renders the Content Editor and aborts the pipeline, preventing the RenderStandardContentEditor processor (and my replacement therefor) from running. Overriding RenderSkinedContentEditor looks more challenging, so I simply chose to disable this default processor and I have not noticed any resulting changes.

We can use a Web.config include file such as the following to apply the required changes:

<configuration xmlns:patch="https://www.sitecore.com/xmlconfig/">
  <sitecore>
    <pipelines>
      <renderContentEditor>
        <processor patch:before="processor[1]" type="SitecoreJohn.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor.SetEditorFormatter,SitecoreJohn" />
        <processor type="Sitecore.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor.RenderStandardContentEditor, Sitecore.Client">
          <patch:delete />
        </processor>
        <processor type="Sitecore.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor.RenderSkinedContentEditor, Sitecore.Client">
          <patch:attribute name="type">SitecoreJohn.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor.RenderStandardContentEditor,SitecoreJohn</patch:attribute>
        </processor>
      </renderContentEditor>
    </pipelines>
  </sitecore>
</configuration>

Resources