Extending 'Quick Info' section of the Sitecore Content Editor
Posted 14 Jan 2025 by Marek Musielak
Recently, one of our clients asked for an option to extend the Quick Info section of the Sitecore Content Editor. I was sure that someone had already done that and that there would be a dozen blog posts explaining how implement this in Sitecore. To my surprise, I only found this Stack Overflow article stating that it wouldn't be easy and that you could hack it with JavaScript if needed.
I wrote this blog post while working for Blastic, a company that delivers great Sitecore solutions and much more.
I decided to investigate Sitecore pipelines more deeply and found that I can add a custom processor to the renderContentEditor
pipeline and inject additional information into the Quick Info section. The first thing is a Sitecore config patch file, which adds an extra processor at the end of that pipeline:
<configuration xmlns:role="http://www.sitecore.net/xmlconfig/role/">
<sitecore role:require="Standalone or ContentManagement">
<pipelines>
<renderContentEditor>
<processor
type="MyAssembly.MyNamespace.ExtendQuickInfoSection, MyAssembly"
/>
</renderContentEditor>
</pipelines>
</sitecore>
</configuration>
Next, let's create a Process
method using the RenderContentEditorArgs
parameter. This parameter contains two properties which we can use to extend the Quick Info section:
args.Item
, which contains Sitecore item which is rendered in the Content Editor,args.Parent
, which contains the HTML control element with the root of the Content Editor right-hand side panel.
After validating the argument let's try to find the Quick Info section inside args.Parent
and if it's there, let's extend it:
public class ExtendQuickInfoSection { public void Process(RenderContentEditorArgs args) { if (args.Item == null || args.Parent == null) return; try { LiteralControl quickInfoSection; if (FindQuickInfo(args.Parent, "QuickInfo_" + args.Item.ID.ToShortID(), out quickInfoSection)) { ExtendQuickInfo(args, quickInfoSection); } } catch (Exception exc) { Log.Error("Exception in 'ExtendQuickInfoSection.Process' of item " + args.Item.ID, exc, this); } } }
The implementation of FindQuickInfo
requires searching for a LiteralControl
with an id attribute containing the QuickInfo_
prefix, followed by the short id of the current item. This has to be executed recursively within the args.Parent
element:
private static bool FindQuickInfo(Control control, string sectionId, out LiteralControl quickInfoSection)
{
var literalControl = control as LiteralControl;
if (literalControl != null)
{
if (literalControl.Text != null && literalControl.Text.Contains($"id=\"{sectionId}\""))
{
quickInfoSection = literalControl;
return true;
}
}
else
{
foreach (Control child in control.Controls)
{
if (FindQuickInfo(child, sectionId, out quickInfoSection))
return true;
}
}
quickInfoSection = null;
return false;
}
The last part involves extending the HTML of the Quick Info section with extra table rows. I use the HtmlAgilityPack
library to parse the HTML of the table, add 2 rows with Last Updated
and Last Updated By
information, and replace original HTML with the new one:
private static void ExtendQuickInfo(RenderContentEditorArgs args, LiteralControl quickInfoSection)
{
var text = quickInfoSection.Text;
var startIndex = text.IndexOf(QuickInfoStartTag, StringComparison.CurrentCulture);
if (startIndex > -1)
{
var endIndex = text.IndexOf(QuickInfoEndTag, startIndex + QuickInfoStartTag.Length, StringComparison.CurrentCulture);
if (endIndex > -1)
{
var doc = new HtmlDocument();
var originalHtml = text.Substring(startIndex, endIndex + QuickInfoEndTag.Length - startIndex);
doc.LoadHtml(originalHtml);
var tableElement = doc.DocumentNode.ChildNodes[0];
AddExtraRowToQuickInfoTable(tableElement, "Last Updated", args.Item.Statistics.Updated.ToString("yyyy-MM-dd HH:mm"));
AddExtraRowToQuickInfoTable(tableElement, "Last Updated By", args.Item.Statistics.UpdatedBy);
quickInfoSection.Text = text.Replace(originalHtml, doc.DocumentNode.OuterHtml);
}
}
}
Now, deploy the new code and configuration to your Sitecore Content Management server and open the Content Editor to see the extended Quick Info section:
The final version of the processor is:
using System;
using Sitecore.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor;
using System.Web.UI;
using HtmlAgilityPack;
using Sitecore.Diagnostics;
using Sitecore.StringExtensions;
public class ExtendQuickInfoSection
{
private const string QuickInfoStartTag = "<table class='scEditorQuickInfo'>";
private const string QuickInfoEndTag = "</table>";
private const string AdditionalRowTemplate = "<tr><td>{0}:</td><td>{1}</td></tr>";
public void Process(RenderContentEditorArgs args)
{
if (args.Item == null || args.Parent == null)
return;
try
{
LiteralControl quickInfoSection;
if (FindQuickInfo(args.Parent, "QuickInfo_" + args.Item.ID.ToShortID(), out quickInfoSection))
{
ExtendQuickInfo(args, quickInfoSection);
}
}
catch (Exception exc)
{
Log.Error("Exception in 'ExtendQuickInfoSection.Process' of item " + args.Item.ID, exc, this);
}
}
private static void ExtendQuickInfo(RenderContentEditorArgs args, LiteralControl quickInfoSection)
{
var text = quickInfoSection.Text;
var startIndex = text.IndexOf(QuickInfoStartTag, StringComparison.CurrentCulture);
if (startIndex > -1)
{
var endIndex = text.IndexOf(QuickInfoEndTag, startIndex + QuickInfoStartTag.Length, StringComparison.CurrentCulture);
if (endIndex > -1)
{
var doc = new HtmlDocument();
var originalHtml = text.Substring(startIndex, endIndex + QuickInfoEndTag.Length - startIndex);
doc.LoadHtml(originalHtml);
var tableElement = doc.DocumentNode.ChildNodes[0];
AddExtraRowToQuickInfoTable(tableElement, "Last Updated", args.Item.Statistics.Updated.ToString("yyyy-MM-dd HH:mm"));
AddExtraRowToQuickInfoTable(tableElement, "Last Updated By", args.Item.Statistics.UpdatedBy);
quickInfoSection.Text = text.Replace(originalHtml, doc.DocumentNode.OuterHtml);
}
}
}
private static void AddExtraRowToQuickInfoTable(HtmlNode tableElement, string header, string value)
{
tableElement.ChildNodes.Append(HtmlNode.CreateNode(AdditionalRowTemplate.FormatWith(header, value)));
}
private static bool FindQuickInfo(Control control, string sectionId, out LiteralControl quickInfoSection)
{
var literalControl = control as LiteralControl;
if (literalControl != null)
{
if (literalControl.Text != null && literalControl.Text.Contains($"id=\"{sectionId}\""))
{
quickInfoSection = literalControl;
return true;
}
}
else
{
foreach (Control child in control.Controls)
{
if (FindQuickInfo(child, sectionId, out quickInfoSection))
return true;
}
}
quickInfoSection = null;
return false;
}
}
Sitecore has accustomed us to the fact that everything is easily expandable and customizable. The Quick Info section is not the easiest to extend, but when you look deep enough, you will always find a way to achieve what you need.