Problem :
Let’s assume that we have callout on our page, this callout has Image, summary and list of Links:
In Sitecore content tree, we will have folder contains this callout, and Links as children:
and we have component to display this callout and we are pointing to that callout by datasource property :
Now when we change anything on the callout item from experience editor like, title “ex:save online time”, and publish, the change will appear to the front end website, but when we change anything related to the links (callout children) under that callout “ex:Activate Tag” from experience editor and publish, the change will not appear to the front end website. If we checked that item from Sitecore content tree, we will see that item changed on Master but it is not published to web.
The reason why the DataSource subitems are not published is that items are second level references. In order to prevent huge amount of items being published, Sitecore doesn’t process references of references, so the DataSource item references are not being processed, and that is how Sitecore publishing currently works.
Solution:
- Create our custom processor based on the
Sitecore.Publishing.Pipelines.GetItemReferences.AddItemLinkReferences one (using .Net Reflector to copy the code of processor ). - Modify the GetReferences() method so that it would recursively process reference references if item is being referenced by the Renderings field (i.e. reference is a data source item).
- Replace predefined processor with our custom one.
Code:
I copied the code from sitecore.kernal, my changes in red color.
public class AddItemLinkReferences : GetItemReferencesProcessor { private static readonly ID RenderingsFieldId = new ID("{F1A1FE9E-A60C-4DDB-A3A0-BB5B29FE732E}"); public AddItemLinkReferences() { } /// <summary> /// Gets the list of item references. /// </summary> /// <param name="context">The publish item context.</param> /// <returns> /// The list of item references. /// </returns> protected override List<Item> GetItemReferences(PublishItemContext context) { Assert.ArgumentNotNull(context, "context"); List<Item> items = new List<Item>(); if (context.PublishOptions.Mode != Sitecore.Publishing.PublishMode.SingleItem) { return items; } switch (context.Action) { case PublishAction.PublishSharedFields: { Item sourceItem = context.PublishHelper.GetSourceItem(context.ItemId); if (sourceItem == null) { return items; } items.AddRange(this.GetReferences(sourceItem, true)); break; } case PublishAction.PublishVersion: { Item versionToPublish = context.VersionToPublish; if (versionToPublish == null) { return items; } items.AddRange(this.GetReferences(versionToPublish, false)); break; } default: { return items; } } return items; } /// <summary> /// Gets the related references. /// </summary> /// <param name="item">The item.</param> /// <param name="sharedOnly">Determines whether to process shared fields only or not.</param> /// <returns> /// The related references. /// </returns> private IEnumerable<Item> GetReferences(Item item, bool sharedOnly) { Assert.ArgumentNotNull(item, "item"); List<Item> items = new List<Item>(); ItemLink[] validLinks = item.Links.GetValidLinks(); validLinks = ( from link in validLinks where item.Database.Name.Equals(link.TargetDatabaseName, StringComparison.OrdinalIgnoreCase) select link).ToArray<ItemLink>(); if (sharedOnly) { validLinks = ((IEnumerable<ItemLink>)validLinks).Where<ItemLink>((ItemLink link) => { Item sourceItem = link.GetSourceItem(); if (sourceItem == null) { return false; } if (ID.IsNullOrEmpty(link.SourceFieldID)) { return true; } return sourceItem.Fields[link.SourceFieldID].Shared; }).ToArray<ItemLink>(); } List<Item> list = ( from link in (IEnumerable<ItemLink>)validLinks select link.GetTargetItem() into relatedItem where relatedItem != null select relatedItem).ToList<Item>(); foreach (Item item1 in list) { items.AddRange(PublishQueue.GetParents(item1)); items.Add(item1); // get all items childrens, if referenced by the __Renderings field. if (Globals.LinkDatabase.GetReferrers(item1).Any(p => p.SourceFieldID == RenderingsFieldId)) { items.AddRange(item1.Axes.GetDescendants()); } } return items.Distinct<Item>(new ItemIdComparer()); } }
Configuration :
In Sitecore.config, we will replace :
<getItemReferences>
<processor type="Sitecore.Publishing.Pipelines.GetItemReferences.AddItemCloneReferences, Sitecore.Kernel"/>
<processor type="Sitecore.Publishing.Pipelines.GetItemReferences.AddFileDropAreaMediaReferences, Sitecore.Kernel"/>
<processor type="Sitecore.Publishing.Pipelines.GetItemReferences.AddItemLinkReferences, Sitecore.Kernel"/>
<processor type="Sitecore.Publishing.Pipelines.GetItemReferences.AddItemAliasReferences, Sitecore.Kernel"/>
</getItemReferences>
with :
<getItemReferences>
<processor type="Sitecore.Publishing.Pipelines.GetItemReferences.AddItemCloneReferences, Sitecore.Kernel"/>
<processor type="Sitecore.Publishing.Pipelines.GetItemReferences.AddFileDropAreaMediaReferences, Sitecore.Kernel"/>
<processor type="YourWebsite.Web.Events.AddItemLinkReferences, YourWebsite.Web"/>
<processor type="Sitecore.Publishing.Pipelines.GetItemReferences.AddItemAliasReferences, Sitecore.Kernel"/>
</getItemReferences>
Great post!
After some tests I noticed that the related items were not always being published. They only get published when you’re working on the Shared Layout.
To fix this I included the Final Rendering ID {04BF00DB-F5FB-41F7-8AB7-22408372A981} as well.
Nele
LikeLiked by 1 person
Thanks Nele!
LikeLike
where exactly was this Final Rendering ID added? Out of curiosity, Is this available as shared module or something?
LikeLike
For me i used rendering id it was working fine, but regarding to Nele’s comment, I think he was using final rendering id instead, i believe both should work fine, and those templates can be found under : /sitecore/templates/System/Templates/Sections/Layout/Layout
And no it’s not available as shared module.
LikeLike