Long lived Sitecore solutions tend to build up unused renderings and sublayouts as design, features and functions evolve. Finding those unused sublayouts it not just a matter of checking the Sitecore Link Database for sublayouts with no references because:
- You will get false positives because __Standard Values of unused templates link to your sublayout.
- Compatible renderings from other unused sublayouts leaves a web of references that is hard to decipher.
- The link database could be broken.
The problem seems easy at first: 1) Find all sublayots. 2) Find all pages using sublayots. 3) Those sublayouts not used on any pages are unused. And that’s what this code will check.
STEP 1: FIND ALL SUBLAYOUTS:
This repository returns every sublayout in your solution from a specified path:
using System.Collections.Generic; using Sitecore.Data; using Sitecore.Data.Items; namespace MyCode { public class SublayoutRepository { private readonly Database _database; private readonly List<SublayoutItem> _sublayouts = new List<SublayoutItem>(); public SublayoutRepository(Database database) { _database = database; } public IEnumerable<SublayoutItem> Get(string rootPath) { _sublayouts.Clear(); Item rootItem = _database.GetItem(rootPath); if (rootItem == null) return _sublayouts; Iterate(rootItem); return _sublayouts; } private void Iterate(Item item) { if (item.TemplateID == Sitecore.TemplateIDs.Sublayout) _sublayouts.Add(item); if (!item.HasChildren) return; foreach (Item child in item.Children) { Iterate(child); } } } }
STEP 2: ITERATE ALL PAGES IN THE SOLUTION:
Finding used sublayouts are a little more tricky. Each item have a Visualization property and you need to iterate this to get the sublayouts from a specific device. In this example I have hard coded the device to “default“.
using System; using System.Collections.Generic; using System.Linq; using PT.Project.Maintenance.Model.Repositories; using Sitecore.Configuration; using Sitecore.Data; using Sitecore.Data.Items; namespace MyCode { public class FindUnusedSublayouts { private IEnumerable<SublayoutItem> _sublayouts; private List<SublayoutItem> _usedSublayouts = new List<SublayoutItem>(); protected void Find() { _sublayouts = new SublayoutRepository(WebDatabase).Get("/sitecore/layout"); _usedSublayouts.Clear(); Item root = WebDatabase.GetItem("/sitecore/content"); Iterate(root); var unusedSublayouts = _sublayouts.Where(s => !_usedSublayouts.Any(s2 => s2.ID == s.ID)); foreach (var unusedSublayout in unusedSublayouts) { // Write the unused sublayout: // unusedSublayout.ID => The GUID // unusedSublayout.InnerItem.Paths.FullPath => The sublayout path // unusedSublayout.FilePath => The path to the .ascx file } } private void Iterate(Item root) { if (root.Visualization.Layout != null) { foreach (var reference in root.Visualization.GetRenderings(DefaultDevice, false)) { if (reference.RenderingItem != null) { try { SublayoutItem item = reference.RenderingItem.InnerItem; if (_usedSublayouts.All(s => s.ID != item.ID)) _usedSublayouts.Add(reference.RenderingItem.InnerItem); } catch (Exception ex) { // Handle the exception, but do not // stop the execution } } } } if (!root.HasChildren) return; foreach (Item child in root.Children) Iterate(child); } private Database WebDatabase { get { return Factory.GetDatabase("web"); } } private DeviceItem _device; private DeviceItem DefaultDevice { get { return _device ?? (_device = WebDatabase.Resources.Devices.GetAll().First(d => d.Name.ToLower() == "default")); } } } }
MORE TO READ:
- Sitecore find unused templates by briancaos
- Get the Sitecore Sublayout from your .aspx page (Usercontrol) by briancaos
- All About Sitecore Renderings by Mark Ursino
END NOTE:
I know that WebForms, .aspx and .ascx are dying technologies, and I encourage everyone to switch to Sitecore MVC. But a lot of older Sitecore solutions cannot switch to MVC for many reasons. Therefore it is important to help those who are maintaining large, long running Sitecore solutions.