こんにちは、Sitecore技術担当の森です。

Sitecoreのアイテムをバケット化すると、以下のように階層構造を持ちます。

バケット化したアイテムのURLは以下のように階層構造部分(2022/11/11/01/15/)を含んだ形で生成されます。

https://samplesc.dev.local/BucketTest/2022/11/11/01/15/createItemTest1

下記の実装を行うことで、階層構造部分を省略したURLでアクセスすることができるようになります。
この記事では、これらの実装方法について説明します。

  • 階層構造部分を省略したURLでページを表示する方法
  • URLを生成するときに階層構造部分を省略する方法

階層構造部分を省略したURLでアイテムを表示する方法

要求されたURLでアイテムが見つからなかった場合に、URLの最後の部分(「/」で区切ったときの最後の単語)とアイテム名が一致するアイテムを探して表示するように処理を書きます。

using System;
using System.Linq;
using Sitecore.ContentSearch.Linq;
using Sitecore.ContentSearch.SearchTypes;
using Sitecore.Diagnostics;
using Sitecore.Pipelines.HttpRequest;
using Sitecore.ContentSearch;

namespace Testproject.Feature.CommonParts.Pipelines
{
    public class CustomItemResolver : HttpRequestProcessor
    {
        public override void Process(HttpRequestArgs args)
        {
            try
            {
                Assert.ArgumentNotNull(args, "args");

                // Sitecore アイテムがマッピングした場合は何もせず戻る
                // (要求されたURLのままアクセスができた場合の対応)
                if(Sitecore.Context.Item != null ||
                   Sitecore.Context.Database == null ||
                   args.Url.ItemPath.Length == 0)
                {
                    return;
                }

                // 検索対象のフォルダ(バケット化したフォルダ)以外の場合何もせず戻る
                var localUrl = args.LocalPath.ToLower();
                if (!localUrl.StartsWith("/buckettest"))
                {
                    return;
                }

                // パスの最後の部分を取得する(一番後ろの '/' 以降の文字列を取得)
                var itemPath = args.Url.ItemPath;
                if (string.IsNullOrEmpty(itemPath))
                {
                    return;
                }

                // URLの末尾がスラッシュの場合を考慮
                itemPath.TrimEnd('/');
                var itemPathParts = itemPath.Split('/');
                if (itemPathParts.Length == 0)
                {
                    return;
                }

                var ItemName = itemPathParts[itemPathParts.Length - 1].ToLower();
                if (string.IsNullOrEmpty(ItemName))
                {
                    return;
                }

                // Sitecoreアイテムから検索対象のインデックスを取得
                var startPath = Sitecore.Context.Site?.StartPath;
                if (string.IsNullOrEmpty(startPath))
                {
                    return;
                }
                var startItem = Sitecore.Context.Database.GetItem(startPath);
                if (startItem == null)
                {
                    return;
                }
                using (var searchContext = 
                    ContentSearchManager.CreateSearchContext(new SitecoreIndexableItem(startItem)))
                {
                    // アイテム名と取得した文字列が一致するアイテムを取得する
                    var query = searchContext
                        .GetQueryable<SearchResultItem>()
                        .Where(item => item.Name == ItemName && item.TemplateId == "テンプレートID");
                    var result = query.GetResults().FirstOrDefault();
                    if (result == null)
                    {
                        return;
                    }
                    Sitecore.Context.Item = Sitecore.Context.Database.GetItem(result.Document.ItemId);
                }
            }
            catch
            {
                return;
            }
        }
    }
}

URLを生成するときに階層構造部分を省略する方法

他のページ(アイテム)へのリンクを生成する際に、階層構造部分を取り除いたURLを生成します。
このリンクをクリックすると、先ほど記載した処理を通ってページが表示されます。

using System.Web;
using Sitecore.Data.Items;
using Sitecore.Links.UrlBuilders;

namespace Testproject.Feature.CommonParts.Pipelines
{
    public class CustomItemUrlBuilder : ItemUrlBuilder
    {
        public CustomItemUrlBuilder(DefaultItemUrlBuilderOptions defaultOptions) : base(defaultOptions)
        {
        }
        public override string Build(Item item, ItemUrlBuilderOptions options)
        {
            // 対象のアイテムかどうかを判別
            var contentPath = "/sample/Home/BucketTest";
            if (item.TemplateID == "テンプレートID" &&
                item.Paths.ContentPath.ToLower().StartsWith(contentPath.ToLower()))
            {
                // 生成するURLを設定
                var url = $"{HttpContext.Current.Request.Url.Scheme}://" +
                    $"{HttpContext.Current.Request.Url.Host}/BucketTest/{item.Name}";

                return url;
            }

            return base.Build(item, options);
        }
    }
}

コンフィグファイルの作成と配置

実装した内容を適用するために、下記内容を記載したコンフィグファイルを作成して App_config/include に配置します。

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <httpRequestBegin>
        <processor
          patch:after="*[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']"
          type="Testproject.Foundation.SitecoreExtension.Pipelines.CustomItemResolver,
                Testproject.Foundation.SitecoreExtension"/>
      </httpRequestBegin>
    </pipelines>
    <links>
      <itemUrlBuilder
          type="Testproject.Foundation.SitecoreExtension.Pipelines.CustomItemUrlBuilder,
                Testproject.Foundation.SitecoreExtension"
          patch:instead="*[@type='Sitecore.Links.UrlBuilders.ItemUrlBuilder, Sitecore.Kernel']">
        <param desc="defaultOptions"
               type="Sitecore.Links.UrlBuilders.DefaultItemUrlBuilderOptions, Sitecore.Kernel">
          <alwaysIncludeServerUrl ref="links/urlBuilder/alwaysIncludeServerUrl" />
          <languageEmbedding ref="links/urlBuilder/languageEmbedding" />
          <languageLocation ref="links/urlBuilder/languageLocation" />
          <lowercaseUrls ref="links/urlBuilder/lowercaseUrls" />
          <encodeNames ref="links/urlBuilder/encodeNames" />
          <useDisplayName ref="links/urlBuilder/useDisplayName" />
          <addAspxExtension>false</addAspxExtension>
          <siteResolving>true</siteResolving>
          <shortenUrls>true</shortenUrls>
        </param>
      </itemUrlBuilder>
    </links>
  </sitecore>
</configuration>

おわりに

アイテム数が多くバケットを使わなければならない、けれどもURLを複雑にしたくないときなど、この記事が参考になれば幸いです。

お問い合わせはコチラ

参照リンク