Validate Media Publishing Status with Sitecore

For the current edition of this blog post, see:

http://www.sitecore.net/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2010/11/Validate-Media-Publishing-Status-with-Sitecore.aspx

You can can use the approach described in this document to validate whether the Sitecore ASP.NET CMS has published the media referenced by an item. You can use validation with workflow to require the user to publish related media before publishing an item that references that media.

You can use this validator in conjunction with a Content Editor Warning to Display Publishing Status.  You can get more information about validation from my post about how to Validate a Sitecore Checklist, Multilist, Treelist, or TreelistEx Field, which contains links to pages, posts, and threads containing much more information about validation, including the Client Configuration Cookbook.

Here is my prototype for the validator:

namespace Sitecore.Sharedsource.Data.Validators.ItemValidators
{
  using System;
  using System.Collections.Generic;
  using System.Runtime.Serialization;
  using Sitecore.Configuration;
  using Sitecore.Data;
  using Sitecore.Data.Items;
  using Sitecore.Data.Validators;
  using Sitecore.Diagnostics;
  using Sitecore.Links;

  [Serializable]
  public class MediaPublishingStatus : StandardValidator
  {
    public MediaPublishingStatus() : base()
    {
    }

    public MediaPublishingStatus(SerializationInfo info, StreamingContext context) : base(info, context)
    {
    }

    public override string Name
    {
      get
      {
        return this.GetType().ToString();
      }
    }

    public static bool IsPublished(Item item, Database targetDatbase)
    {
      Assert.ArgumentNotNull(item, "item");
      Assert.ArgumentNotNull(targetDatbase, "targetDatbase");
      Item targetItem = targetDatbase.GetItem(item.ID, item.Language, item.Version);
      return targetItem != null
             && item.Version.Number == targetItem.Version.Number
             && item.Statistics.Revision == targetItem.Statistics.Revision;
    }

    public static Database[] GetPublishingTargets(Item item)
    {
      Assert.ArgumentNotNull(item, "item");
      Item pubTargets = item.Database.GetItem("/sitecore/system/publishing targets");
      Assert.IsNotNull(pubTargets, "publishing targets");
      List<Database> databases = new List<Database>();

      foreach (Item target in pubTargets.Children)
      {
        if (PublishingTargetApplies(item, target.ID))
        {
          string name = target[FieldIDs.PublishingTargetDatabase];
          Assert.IsNotNull(name, target.Paths.FullPath);
          Database db = Factory.GetDatabase(name);
          Assert.IsNotNull(db, name);
          databases.Add(db);
        }
      }

      return databases.ToArray();
    }

    public static bool PublishingTargetApplies(Item item, ID publishingTarget)
    {
      while (item != null)
      {
        string restricted = item[FieldIDs.PublishingTargets];

        if (!(String.IsNullOrEmpty(restricted) || restricted.Contains(item.ID.ToString())))
        {
          return false;
        }

        item = item.Parent;
      }

      return true;
    }

    protected override ValidatorResult Evaluate()
    {
      Item item = this.GetItem();
      Assert.IsNotNull(item, "GetItem");
      Database[] pubTargets = GetPublishingTargets(item);

      foreach (ItemLink link in item.Links.GetAllLinks())
      {
        if (link.SourceFieldID == Sitecore.Data.ID.Null)
        {
          continue;
        }

        Sitecore.Data.Fields.Field field = item.Fields[link.SourceFieldID];
        Assert.IsNotNull(field, link.SourceFieldID.ToString());
        Item media = link.GetTargetItem();

        if (String.IsNullOrEmpty(field.Value) || media == null || !media.Paths.IsMediaItem)
        {
          continue;
        }

        if (field.Value.Contains(media.ID.ToString()) || field.Value.Contains(ShortID.Encode(media.ID)))
        {
          foreach (Database db in pubTargets)
          {
            if (!IsPublished(media, db))
            {
              this.Text = String.Format(
                "The field {0} references the media item {1}, which is not current in the {2} database.",
                field.Name,
                media.Paths.FullPath,
                db.Name);
              return GetFailedResult(ValidatorResult.Error);
            }
          }
        }
      }

      return ValidatorResult.Valid;
    }

    protected override ValidatorResult GetMaxValidatorResult()
    {
      return ValidatorResult.Error;
    }
  }
}

While iterating the publishing target databases, this validator iterates each link from the current item to any other item. If the link exists in the selected version of the item, and the publishing target database does not contain the referenced media item or contains a different version or revision of that media item, then the validator returns a warning.

You could use this approach to check references other than media, such as presentation components. You could even check the template definition to see if it contains a field definition or standard values change to publish.

To define the item validator:

  1. Add the class to the Visual Studio project and compile.
  2. In the Content Editor, navigate to the /Sitecore/System/Settings/Validation Rules/Item Rules item and insert an item named Media Publishing Status using the System/Validation/Validation Rule data template.
  3. In the Media Publishing Status item, set the value of the Type field in the data section to the type signature of the validator class, such as Sitecore.Sharedsource.Data.Validators.ItemValidators.MediaPublishingStatus,assembly
  4. In the /Sitecore/System/Settings/Validation Rules/Global Rules item, in all four fields in the Validation Rules section, add Media Publishing Status to the selection.

There is clearly some code to factor out into other classes, and as usual, this is not well tested. If I have time, I hope to perform some refactoring while (re)developing a solution to publish related media. Publishing targets, item publishing restrictions, languages versions including restrictions, workflow status, revision identifiers, and probably other factors complicate the challenge of developing generic solutions to automate publishing.

Advertisements
This entry was posted in Obsolete. Bookmark the permalink.

2 Responses to Validate Media Publishing Status with Sitecore

  1. Pingback: Sitecore Fetch Squad » Blog Archive » Validate Media Publishing Status with Sitecore

  2. I’d say there’s a bug in method PublishingTargetApplies ; instead of:

    if (!(String.IsNullOrEmpty(restricted) || restricted.Contains(item.ID.ToString())))

    should be:

    if (!(String.IsNullOrEmpty(restricted) || restricted.Contains(publishingTarget.ToString())))

    (you want to know if the TARGET database id is in PublishingTargets fields)

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 )

Google photo

You are commenting using your Google 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