The following code can be setup as a scheduled task in Sitecore or added to a custom admin page to be run as needed. It will recursively move down the content tree and find items which have a layout, it then checks the renderings on those items with datasources and ensures the datasource exists. If a rendering with a broken datasource is found, it is removed from the item.
using Sitecore.Layouts; using Sitecore.Data.Fields; using Sitecore.Diagnostics; public partial class DatasourceFix : System.Web.UI.Page { private static Database database = Sitecore.Configuration.Factory.GetDatabase("master"); private static string StartPath = "/sitecore/content/"; // Start path to enumerate private static string DefaultDevice = "{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}"; // Default device ID protected void btnRun_Click(object sender, EventArgs e) { var startItem = database.Items.GetItem(StartPath); CheckItem(startItem); } private Item CheckItem(Item mainItem) { RenderingRemover(mainItem); if (mainItem.HasChildren) { foreach (var myInnerItem in mainItem.Children.ToList()) { CheckItem(myInnerItem); } } return null; } private void RenderingRemover(Item item) { if (item.Fields[Sitecore.FieldIDs.LayoutField] != null && !String.IsNullOrEmpty(item.Fields[Sitecore.FieldIDs.FinalLayoutField].Value)) { // If item has a layout LayoutField layoutField = new LayoutField(item.Fields[Sitecore.FieldIDs.LayoutField]); LayoutDefinition layout = LayoutDefinition.Parse(layoutField.Value); DeviceDefinition device = device = layout.GetDevice(DefaultDevice); // Get the default device // Get renderings for the device var d = layout.GetDevice(device.ID.ToString()); var ren = d.Renderings; // Query the renderings for those with a datasource var withDatasource = from RenderingDefinition renDef in ren where !string.IsNullOrEmpty(renDef.Datasource) select renDef; bool itemEdited = false; // item edited flag // Find missing datasources foreach (RenderingDefinition rendering in withDatasource.ToList() ?? Enumerable.Empty()) { var datasource = database.GetItem(new Sitecore.Data.ID(rendering.Datasource)); // Get the datasource if (datasource == null) { // if datasource is broken, flag an item edit and remove the rendering itemEdited = true; d.Renderings.Remove(rendering); Log.Info(string.Format("Removing rendering {0} from item {1} due to datasource not being found.", rendering.ItemID.ToString(), item.Paths.Path), ""); } } // edit the item if rendering(s) were removed if(itemEdited) { item.Editing.BeginEdit(); layoutField.Value = layout.ToXml(); item.Editing.EndEdit(); } } } }
It can be quite an expensive operation as it will go through an entire content tree, so be careful when/how it is run.
No comments:
Post a Comment