LibrarySites.Banner

Hide Items without Versions from the Content Tree in the Sitecore ASP.NET CMS

This blog post explains an approach that you can use to hide items without versions in the current content language from the content tree in the Sitecore ASP.NET web Content Management System (CMS) and Experience Platform (XP). This specific untested prototype may not be ready for production, but the general approach could be useful when you need to employ custom logic to determine what to show.

In a recent post on the Sitecore Developer Network forums, someone was looking for a way to hide from the content tree items that have no versions in the content language. As stated, such a feature could have some negative effects:

  • Most of the default items (including /sitecore, /sitecore/content, /sitecore/media library, and so forth) have no versions in languages other than the default English, but the system should show those items.
  • A CMS user would not be able to create the first version of an item in a language for which that item does not appear.
  • If the user changes the content language, something should redraw the tree, but I did not implement this as it could be a feature (it allows a user with access to both languages to create the first version in a language for which there are no versions). Anyway, the user can right-click and item in the content tree and select Refresh from the menu to update the view.
  • This only affects content trees (and probably not all of them) for CMS users. Your presentation and any other custom code is still responsible for handling items with no versions in the context language.

So while it is technically possible to achieve this goal by altering the master data view, I am not certain about the implications, and this prototype will certainly require some refinement.

If you look in the /web.config file, it appears that Sitecore.Web.UI.HtmlControls.MasterDataView implements the master data view. If you look at /sitecore/admin/showconfig.aspx, you will see that the Sitecore.Buckets.config file overrides this with Sitecore.Buckets.Forms.BucketDataView, which inherits from that default. This affects the base class from which your implementation should derive. ALWAYS CHECK /sitecore/admin/showconfig.aspx RATHER THAN TRUSTING /web.config!

Here is the prototype, which overrides the GetChildItems() method of the master data view to call the corresponding method in the base class and then (under specific conditions) remove any items without versions in the context language:

namespace SitecoreJohn.Web.UI.HtmlControls
{
  using System;
 
  using Sitecore.Buckets.Forms;
  using Sitecore.Collections;
  using Sitecore.Data.Items;
  using Sitecore.Shell;
 
  public class LanguageVersionFilteredDataView : BucketDataView
  {
    protected override void GetChildItems(
      ItemCollection items,
      Item item)
    {
      base.GetChildItems(items, item);
 
      if (base.Parameters.IndexOf("showhidden", StringComparison.InvariantCulture) > -1
        || UserOptions.View.ShowHiddenItems
        || item.Axes.Level < 2)
      {
        return;
      }
 
      for (int i = items.Count - 1; i >= 0; i--)
      {
        Item temp = items[i].Versions.GetLatestVersion(
          item.Language);
 
        if (temp == null || temp.Version.Number < 1 || temp.Versions.Count < 1)
        {
          items.RemoveAt(i);
        }
      }
    }
  }
}

You can use a Web.config include file such as the following to enable this (be sure that the name of the file follows Sitecore.Buckets.config alphabetically):

<configuration xmlns:patch="https://www.sitecore.com/xmlconfig/">
  <sitecore>
    <dataviews>
      <dataview name="Master" >
        <patch:attribute name="assembly">SitecoreJohn</patch:attribute>
        <patch:attribute name="type">SitecoreJohn.Web.UI.HtmlControls.LanguageVersionFilteredDataView</patch:attribute>
      </dataview>
    </dataviews>
  </sitecore>
</configuration>

In this implementation, the items with no versions appear if the user has selected the Hidden Items checkbox in the View group on the View tab.

Note also that you can cause items to appear in the tree that do not exist in the database. For instance, I copied most of my logic from the default implementation that handles buckets (hence looping in reverse for no reason, and I did not research what the showhidden parameter might be), which (under some configurations) removes bucket definition items and adds an item that hides the bucket. Here is the BucketDataView GetChildItems() method disassembled:

protected override void GetChildItems(ItemCollection items, Item item)
{
    base.GetChildItems(items, item);
    if ((base.Parameters.IndexOf("showhidden", StringComparison.InvariantCulture) < 0) && !View.ShowBucketItems)
    {
        bool flag = false;
        for (int i = items.Count - 1; i >= 0; i--)
        {
            if ((items[i].TemplateID.ToString() == Constants.BucketFolder) && (items[i].ID.ToString() != BucketConfigurationSettings.BucketTemplateStandardValuesId))
            {
                items.RemoveAt(i);
                flag = true;
            }
        }
        if (flag)
        {
            items.Insert(0, this.GetTempItem(item));
        }
    }
}

And here is that GetTempItem() method that creates that dummy item disassembled. showing some API you could use:

private Item GetTempItem(Item parent)
{
    ID newID = ID.NewID;
    ItemDefinition definition = new ItemDefinition(newID, "There are hidden items in this container.", TemplateIDs.Folder, ID.Null);
   FieldList list2 = new FieldList();
    list2.Add(FieldIDs.DisplayName, Translate.Text("There are hidden items in this container."));
    list2.Add(FieldIDs.Icon, Images.GetThemedImageSource("Business/16x16/chest_add.png"));
    list2.Add(FieldIDs.UIStaticItem, "1");
    FieldList fields = list2;
    return new Item(newID, new ItemData(definition, Language.Invariant, Version.Latest, fields), parent.Database) { RuntimeSettings = { Temporary = true } };
}

Resources