Sitecore CMS and everything related RSS 2.0
 Friday, August 08, 2008

(For introduction to the new publishing architecture, read the part 1: New Publishing Pipelines and Events in Sitecore 6)

Today’s example is using the publish:itemProcessed event to publish related media items.

A little background first. Imagine a new item structure being created, and some content items have an image field that uses items from the media library. Neither the content items nor the media items have been published yet. Now if the editor publishes the content item in a “single-item” mode (i.e. selects the publish in the ribbon, and not the incremental, smart or full publishing), the item will get published to the web database, but the media items will not.

The event handler below listens to the publish:itemProcessed event, and if the content item had been published in the single-item mode and has links to media items, they get published too.

public class ItemProcessedHandler {
  public void ItemProcessed(object sender, EventArgs rawArgs) {
    var args = rawArgs as ItemProcessingEventArgs;
    Assert.IsNotNull(args, "args");

    var context = args.Context;
    
    // [1] publish mode check
    if (context.PublishOptions.Mode != PublishMode.SingleItem) {
      return;
    }

    var item = context.PublishHelper.GetSourceItem(context.ItemId);
    if (item == null) {
      return;
    }

    if (!item.Paths.IsContentItem) {
      return;
    }

    // [2] Triggering publishing of the related item by running the publishItem pipeline again
    var options = new PublishOptions(
      context.PublishOptions.SourceDatabase,
      context.PublishOptions.TargetDatabase,
      PublishMode.SingleItem,
      context.PublishOptions.Language,
      context.PublishOptions.PublishDate);

    var relatedMedia = GetRelatedMedia(item);

    foreach(var mediaItem in relatedMedia) {
      PublishItemPipeline.Run(mediaItem.ID, options);
    }
  }

  // [3] related media items are retrieved using the link database
  IList GetRelatedMedia(Item item) {
    var references = Globals.LinkDatabase.GetReferences(item);
    var result = new List();

    foreach(var reference in references) {
      if (reference.SourceDatabaseName != item.Database.Name) {
        continue;
      }

      var referenceItem = item.Database.GetItem(reference.TargetItemID);
      if (referenceItem == null) {
        continue;
      }

      if (referenceItem.Paths.IsMediaItem) {
        result.Add(referenceItem);
      }
    }

    return result;
  }
}

Notes:

  1. Check the publish mode – no need to intervene in the incremental or full publishes, Sitecore will publish everything needed by itself
  2. Programmatically running the publishItem pipeline for each media item. Higher level PublishManager API could have been used as well
  3. Link database is used to retrieve the related media items. Nothing new here.

To activate the event:

<event name="publish:itemProcessed">
  <handler type="Pipelines.Publishing.ItemProcessedHandler, Pipelines" method="ItemProcessed" />
</event>
Friday, August 08, 2008 8:44:30 AM (FLE Standard Time, UTC+02:00)  #    Comments [4] -
Sitecore | Crestone
Saturday, August 09, 2008 12:41:27 PM (FLE Standard Time, UTC+02:00)
What a neat example! :)
One point: why not use List<Item> instead of IList?
Or in this case yield return with an IEnumerable<Item>?

This is just code purism ;)
Sunday, August 10, 2008 12:02:09 PM (FLE Standard Time, UTC+02:00)
I think it supposed to be IList<Item> which I accidentaly edited out, at least this is what I usually use by default. IEnumerable<T> is too restrictive, and List<T> is too revealing. Though I don't this there's anything wrong returning a List<T> from the private method.
Tuesday, August 12, 2008 7:41:44 PM (FLE Standard Time, UTC+02:00)
Awesome example! Thanks!
Just a note that this is applicable to not only the related media items but also to the related content items. For example, a treelist field with the references to the modules appearing on the page or sidebar items.
The only thing I can think of is if the related items are in the workflow. It will make sense to abort the publishing of the particular item and return a friendly message to the user saying that "Sorry, cannot publish the item as some relations are not approved yet". I guess that can be added to the logs.
The approach we currently have for 5.3 is to check for the approved related media in the workflow before pushing it to the final state. If any of such items found, do not move the item to the final state.
Alex Shyba
Thursday, August 14, 2008 3:44:27 PM (FLE Standard Time, UTC+02:00)
Alex,

Good points. Handling all possible conditions here is definitely harder than it looks. Exactly why I decided to keep the example simple :)
Comments are closed.
Archive
<November 2008>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
Blogroll
 Alex de Groot
Few words about SiteCore from Holland
 Alexander Shyba
Sitecore Support
 Anders Dreyer
Anders Dreyer on Sitecore Development
 Jakob Christensen
Sitecore Core Development
 Lars Fløe Nielsen
Lars's ramblings about development and business processes
 Ole Thrane
Sitecore API
 Runi Thomsen
Runi Thomsen Sitecore Toughts
 The Sitecore Experience
The Sitecore Experience
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008
Alexey Rusakov
Sign In
Statistics
Total Posts: 199
This Year: 49
This Month: 3
This Week: 0
Comments: 0
Themes
Pick a theme:
All Content © 2008, Alexey Rusakov
DasBlog theme 'Business' created by Christoph De Baene (delarou)