Multiple item reference indicator in Sitecore Experience Editor

In Sitecore, we build pages adding renderings to a page. Renderings typically have datasources pointing to items carrying the content. Thereby it’s really easy to reuse content. In a scenario where a piece of content is used on multiple pages, it’s maybe not clear to content author that changes to the content will actually affect more pages.

So I wrote a little indicator that will show a warning indicator in the Sitecore Experience Editor (aka Page Editor) when the content of a rendering is being used on other pages as well.

WebEdit warning signThere are probably many ways of doing this, but I just did a simple one by adding a WebEdit button and hide it when there aren’t multiple usages of a referenced item. Using the QueryState method, we can query the LinkDatabase and find items referenced by the LayoutFiled or the FinalLayoutField, and just hide the button if there are other pages than the current one referencing the item.

Below is some sample code that does it. Only the QueryState method is needed for the indicator itself. The code below also fires a dialog that will display a list items referencing the content. But I won’t go into that part now. That’s a future blog post.

using System;
using System.Collections.Specialized;
using System.Linq;
using Sitecore;
using Sitecore.Shell.Applications.WebEdit.Commands;
using Sitecore.Shell.Framework.Commands;
using Sitecore.Text;
using Sitecore.Web.UI.Sheer;

namespace Stendahls.Sc.EditorExtensions.Commands
{
    [Serializable]
    public class MultipleUsagesNotification : WebEditCommand
    {
        public override CommandState QueryState(CommandContext context)
        {
            if (context.Items == null || context.Items.Length != 1)
                return CommandState.Hidden;

            if (context.Parameters == null)
                return CommandState.Hidden;

            var item = context.Items[0];
            var referrers = Sitecore.Globals.LinkDatabase.GetReferrers(item);
            var renderingReferences = referrers.Where(r => r.SourceFieldID == FieldIDs.LayoutField || 
                r.SourceFieldID == FieldIDs.FinalLayoutField).ToList();

            if (renderingReferences.Count() > 1)
            {
                var currentItem = Sitecore.Context.Item;
                var otherPages = renderingReferences.Where(r => r.SourceItemID != currentItem.ID).ToList();

                return otherPages.Count > 0 ? CommandState.Enabled : CommandState.Hidden;
            }
            return CommandState.Hidden;
        }

        public override void Execute(CommandContext context)
        {
            var item = context.Items[0];
            var parameters = new NameValueCollection();
            parameters["id"] = item.ID.ToString();
            parameters["database"] = item.Database.Name;

            Sitecore.Context.ClientPage.Start(this, "Run", parameters);
        }

        protected void Run(ClientPipelineArgs args)
        {
            if (args.IsPostBack)
                return;
 
            var url = new UrlString(UIUtil.GetUri("control:MultipleUsagesNotificationDialog"));
            if (args.Parameters["database"] != null)
            {
                url["database"] = args.Parameters["database"];
            }
            if (args.Parameters["id"] != null)
            {
                url["id"] = args.Parameters["id"];
            }
            SheerResponse.ShowModalDialog(url.ToString(), true);
            args.WaitForPostBack();
        }
    }
}

Here’s how it’s added into the core database:
webedit-button-core-item

Hope you find it useful.