LibrarySites.Banner

Render Content Editor Fields Read-Only in the Sitecore ASP.NET CMS

This blog post explains how you control whether fields appear in the browser-based Content Editor application in the Sitecore ASP.NET web Content Management System. This is just a simple example of a technique that you can use to alter fields and field labels in the Content Editor.

You can use field security to control whether and how Sitecore renders fields in the Content Editor. Specifically, you can restrict the field:read and field:write access rights. By default, the effective access rights for an item apply to its fields, but you can further restrict access rights using field:read and field:write. But because Sitecore administrators effectively have item:read, field:read, item:write, and field:write for all items, you cannot use access rights to make fields read-only for adminstrators. Sitecore APIs do not enforce field:read and field:write access; each individual user interface must apply these rights explicitly.

To deny the field:write access right to all CMS users, you can add this to the raw value of the Security field in the Security section defined by the standard template:

ar|sitecore\Everyone|pe|-field:write|

To deny both field:read and field:write access rights to all CMS users:

ar|sitecore\Everyone|pe|-field:write|-field:read|

If you frequently manipulate access to fields, you can create security presets under the /sitecore/system/Settings/Security/Presets to define commands that will in the Presets group on the Security tab to apply these rights automatically.

The Content Editor and other user interfaces use the __Read Only checkbox field in the Appearance section of the standard template to determine whether to make items read-only. The Protect Item and Unprotect Item commands in the Attribute group on the Configure tab abstract access to the __Read Only field. You can use the __Read Only field in field definition items to determine whether to render a field as read-only even for Sitecore administrators.

This untested prototype involves three components: a class to override the default Sitecore.Shell.Applications.ContentEditor.EditorFormatter, a renderContentEditor pipeline processor to apply that class, and a Web.config include file to add that processor to that pipeline.

The EditorFormatter override adds the ShouldMakeReadOnly() method and overrides all three signatures of the RenderField() method to call ShouldMakeReadOnly() when calling the corresponding signatures in the base class:

namespace Sitecore.Sharedsource.Shell.Applications.ContentEditor
{
  using System.Web.UI;
 
  using Assert = Sitecore.Diagnostics.Assert;
 
  using SC = Sitecore;
 
  public class EditorFormatter :
    SC.Shell.Applications.ContentEditor.EditorFormatter
  {
    public override void RenderField(
      Control parent,
      SC.Shell.Applications.ContentManager.Editor.Field field,
      bool readOnly)
    {
      base.RenderField(parent, field, readOnly || this.ShouldMakeReadOnly(field));
    }
 
    public new void RenderField(
      Control parent,
      SC.Shell.Applications.ContentManager.Editor.Field field,
      SC.Data.Items.Item fieldType,
      bool readOnly)
    {
      base.RenderField(
        parent,
        field,
        fieldType,
        readOnly || this.ShouldMakeReadOnly(field));
    }
 
    public override void RenderField(
      Control parent,
      SC.Shell.Applications.ContentManager.Editor.Field field,
      SC.Data.Items.Item fieldType,
      bool readOnly,
      string value)
    {
      base.RenderField(
        parent,
        field,
        fieldType,
        readOnly || this.ShouldMakeReadOnly(field),
        value);
    }
 
    private bool ShouldMakeReadOnly(
      SC.Shell.Applications.ContentManager.Editor.Field field)
    {
      Assert.ArgumentNotNull(field, "field");
      Assert.IsNotNull(
        SC.Context.ContentDatabase,
        "Sitecore.Context.ContentDatabase");
      SC.Data.Items.Item fieldItem = SC.Context.ContentDatabase.GetItem(
        field.TemplateField.ID);
      Assert.IsNotNull(fieldItem, "fieldItem " + field.TemplateField.ID);
      return fieldItem.Appearance.ReadOnly;
    }
  }
}

The pipeline processor is relatively straightforward:

namespace Sitecore.Sharedsource.Shell.Applications.ContentEditor.Pipelines
{
  using SC = Sitecore;
 
  public class SetEditorFormatter
  {
    public void Process(
      SC.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor.RenderContentEditorArgs args)
    {
        args.EditorFormatter =
          new SC.Sharedsource.Shell.Applications.ContentEditor.EditorFormatter();
        args.EditorFormatter.Arguments = args;
    }
  }
}

The Web.config include file adds the custom processor before all others:

<configuration xmlns:patch="https://www.sitecore.com/xmlconfig/">
  <sitecore>
    <pipelines>
      <renderContentEditor>
       <processor patch:before="processor[1]" type="Sitecore.Sharedsource.Shell.Applications.ContentEditor.Pipelines.SetEditorFormatter,Sitecore.Sharedsource" />
      </renderContentEditor>
    </pipelines>
  </sitecore>
</configuration>

Resources