Sitecore publishItem pipeline – handling missing delete when publishing

When publishing items in Sitecore, the publishItem pipeline is called for each item that must be published, or unpublished. Except for children of items that have been deleted. Let’s take this example:

Items To Publish
Items to publish

If I publish the top item, the publishItem pipeline will be called for every child with the PublishAction.PublishVersion property in the context.

If I then delete “Page1” and republish the top item, the publishItem pipeline is run again. This time the “Page1” will be called with PublishAction.DeleteTargetItem property in the context. But there is no publishItem being called for each of the children of “Page1“.

This is because Sitecore assumes that when a parent is being unpublished, it will automatically clean up any child items, because the relationship between parent and child have been broken.

SO THAT IS THE CHALLENGE THEN?

In my solution, we synchronize certain Sitecore items with an external database. This database have no parent-child relation. so when the “Page1” is deleted, the children below is not deleted from the external database, because no one tells the database to do so.

HOW CAN THIS BE FIXED:

My colleague Odin Jespersen helped me fix this issue. He created a new pipeline step for the publishItem pipeline that compares the web database with the master database to find items that have been deleted from the master database but not in the web database. These items are deemed deleteable and we then delete the items from the external database.

ENOUGH TALK, SHOW ME THE CODE:

This is how it looks like:

STEP 1: ADD THE STEP TO THE PUBLISHITEM PIPELINE:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:env="http://www.sitecore.net/xmlconfig/env/">
  <sitecore>
    <pipelines>
      <publishItem>
        <processor patch:before="*[@type='Sitecore.Publishing.Pipelines.PublishItem.DetermineAction, Sitecore.Kernel']" type="MyCode.DeleteFromExternalDatabase, MyDll" />
      </publishItem>
    </pipelines>
  </sitecore>
</configuration>

STEP 2: THE PROCESSOR:

using System.Linq;
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Globalization;
using Sitecore.Publishing;
using Sitecore.Publishing.Pipelines.PublishItem;

namespace MyCode
{
  public class DeleteFromExternalDatabase : PublishItemProcessor
  {
    private readonly MasterDatabaseFactory _sourceDatabaseFactory = Sitecore.Data.Database.GetDatabase("master");
    private readonly WebDatabaseFactory _targetDatabaseFactory = Sitecore.Data.Database.GetDatabase("web");

    public override void Process([CanBeNull] PublishItemContext context)
    {
      if (context == null)
        return;
      if (context.Aborted)
        return;
      if (context?.PublishContext == null)
        return;
      
      Item sourceItem = context.PublishHelper.GetSourceItem(context.ItemId);
      if (sourceItem == null)
        return;
      
      if (!sourceItem.Paths.IsContentItem)
        return;
      
	  // Only do this trick for the items that are being synchronized with the 
	  // external database
	  if (sourceItem.TemplateID != MyTemplate)
        return;
      
	  Item targetFolder = _targetDatabaseFactory.Get().GetItem(sourceItem.ID);
      if (targetFolder == null)
        return;
      
      var targetItems = targetFolder.GetChildrenDerivedFrom(MyTemplate);
      if (targetItems != null)
      {
        foreach (Item targetItem in targetItems)
        {
          if (_sourceDatabaseFactory.Get().GetItem(targetItem.ID) != null)
          {
            continue;
          }
          var items = targetItem.GetChildrenDerivedFrom(MyTemplate);
          if (items == null)
            continue;
          foreach (Item item in items)
          {
            if (_sourceDatabaseFactory.Get().GetItem(item.ID) == null)
            {
              // Do the delete from the external database
            }
          }
        }
      }
    }
  }
}

MORE TO READ:

About briancaos

Developer at Pentia A/S since 2003. Have developed Web Applications using Sitecore Since Sitecore 4.1.
This entry was posted in c#, General .NET, Sitecore 7, Sitecore 8, Sitecore 9 and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.