1731081068
2024-11-07 06:19:00
導入
Optimizely CMS では、ゴミ箱に移動されたコンテンツは、 IsDeleted のプロパティ IContent。この動作により、特に「削除された」コンテンツにアクセスすべきでないときにアクセス可能なままになっている場合、検索結果が乱雑になり、ユーザー エクスペリエンスが混乱する可能性があります。残念ながら、Optimizely のドキュメントには、ゴミ箱に入れられたコンテンツをフィルタリングして除外する簡単な方法が欠けているため、検索結果からゴミ箱に入れられたアイテムを除外するカスタム ソリューションを開発しました。
このソリューションは、Optimizely Content Events を利用して、コンテンツがゴミ箱に移動されたとき、またはゴミ箱から移動されたときを検出し、 IsDeleted を継承するカスタム ページ テンプレートにフラグを設定します。 SitePageData、プロジェクトの基本ページクラス。これらのイベントを使用することで、検索インデックスがリアルタイムで更新され、一貫性のある明確な検索エクスペリエンスがユーザーに提供されます。
Optimizely Content イベントの概要
Optimizely コンテンツ イベントは、作成、更新、移動、削除などのコンテンツ ライフサイクル アクションを管理するために不可欠です。これらのイベントを使用すると、開発者はコンテンツの変更に応じて特定のアクションをトリガーでき、他のシステムと統合したり、特定のコンテンツ タイプの特別なタスクを処理したりできるようになります。
Optimizely の一般的なコンテンツ イベントの概要を次に示します。
- 作成されたコンテンツ: 新しいコンテンツが作成されるときに発生します。
- 公開コンテンツ: コンテンツが公開されるとトリガーされます。
- 削除されたコンテンツ: コンテンツが CMS から完全に削除されるときに発生します。
- 移動されたコンテンツ: コンテンツが新しい場所またはゴミ箱に移動されるとアクティブになります。
- コンテンツの保存: コンテンツが保存される前に発生し、検証やデフォルト値の設定によく使用されます。
コンテンツ イベントの詳細については、以下をご覧ください。 ダニエル オバスカさんの ブログ の上 コンテンツ イベント。
ソリューションの概要
当社のカスタム ソリューションには、 OnMovedContentToTrash 次のイベント ハンドラー:
- コンテンツがゴミ箱に移動されたとき、またはゴミ箱から移動されたときを検出します。
- を設定します
IsDeletedを継承するカスタム ページ タイプのフラグSitePageData。 - Optimizely Find のコンテンツ インデックスを更新して、検索結果を正確に保ちます。
以下では、このソリューションの各部分を詳しく説明します。これには、 SitePageData を効率的に適用し、 IsDeleted フラグ。
実装
ステップ 1: のセットアップ OnMovedContentToTrash イベントハンドラー
私たちの中で OnMovedContentToTrash この方法では、コンテンツがゴミ箱に移動されたかゴミ箱から移動されたかどうかを監視します。その位置に基づいて、 IsDeleted フラグを true (ゴミ箱にある場合) または false (復元された場合) に設定します。この更新された情報は CMS に保存され、Optimizely Find でインデックスが再作成され、検索結果に現在のコンテンツの状態が確実に反映されます。
ステップ 2: 各ページ タイプのプロセッサ アクションを作成する
申請するには IsDeleted 実行時に反映されずに各ページ タイプで、式ツリーを使用して各タイプのアクションを作成します。このアプローチにより、実行時のパフォーマンスのオーバーヘッドが回避され、リフレクションに関する潜在的な問題が防止されます。
ステップ 3: の定義 ProcessContent 方法
このメソッドは、 IsDeleted 特定のコンテンツ タイプにフラグを設定し、Optimizely Find でインデックスを再作成して、そのステータスに基づいて検索結果に表示または非表示になるようにします。
上記の手順のコードは次のとおりです。
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule), typeof(EPiServer.Commerce.Initialization.InitializationModule))]
public class ContentEventInitialization : IInitializableModule
{
private IClient _findClient { get; set; }
private Injected _cmsContentService;
private IContentTypeRepository _contentTypeRepository { get; set; }
private static readonly Injected _httpContextAccessor;
private static readonly Injected _configuration;
private static readonly Injected _environment;
private static readonly ILogger _logger = LogManager.GetLogger(typeof(ContentEventInitialization));
public void Initialize(InitializationEngine context)
{
_findClient = SearchClient.Instance;
_contentTypeRepository = context.Locate.Advanced.GetInstance();
var contentEventsService = _contentEvents.Service;
contentEventsService.MovedContent += OnMovedContentToTrash;
contentEventsService.PublishedContent += OnContentPublished;
contentEventsService.CheckedInContent += OnCheckedInContent;
}
public void Uninitialize(InitializationEngine context)
{
var contentEventsService = _contentEvents.Service;
contentEventsService.MovedContent -= OnMovedContentToTrash;
contentEventsService.PublishedContent -= OnContentPublished;
contentEventsService.CheckedInContent -= OnCheckedInContent;
}
///
/// Handles the event when content is moved to or from the trash. Updates the IsDeleted property
/// of specific custom page types and re-indexes the content in Optimizely Find.
///
/// The event sender.
/// The content event arguments containing details about the moved content.
private void OnMovedContentToTrash(object sender, ContentEventArgs e)
{
_logger.Information($"Moved content to trash fired for content {e.ContentLink.ID}");
if (e is MoveContentEventArgs eventArgs)
{
var contentRepository = ServiceLocator.Current.GetInstance();
// Dictionary to store processors for each custom page type
var contentProcessors = new Dictionary>();
var sitePageDataType = typeof(SitePageData);
// Get all types that inherit from SitePageData in the current assembly
var pageTypes = _contentTypeRepository
.List()
.Where(x => x.ModelType != null)
.Select(x => x.ModelType)
.Where(x => sitePageDataType.IsAssignableFrom(x) && x.IsClass && !x.IsAbstract);
// Populate the dictionary with actions for each page type
foreach (var pageType in pageTypes)
{
var processor = CreateProcessorAction(pageType);
contentProcessors[pageType] = processor;
}
// Determine if content is moved to or from the trash, setting IsDeleted accordingly
bool isDeleted = eventArgs.TargetLink.ID == ContentReference.WasteBasket.ID;
bool isRestored = eventArgs.OriginalParent.ID == ContentReference.WasteBasket.ID;
if (isDeleted || isRestored)
{
var contentType = e.Content.GetType().BaseType;
if (contentProcessors.TryGetValue(contentType, out var processor))
{
processor.Invoke(e.Content, isDeleted);
}
}
}
}
///
/// Creates a strongly-typed action for processing a specific page type when content is moved
/// to or from the trash. This avoids the need for reflection at runtime.
///
/// The type of the page for which to create the processor action.
/// An action that processes the page type when content is moved to or from the trash.
private Action CreateProcessorAction(Type pageType)
{
// Define parameters for the lambda: (IContent content, bool isDeleted)
var contentParam = Expression.Parameter(typeof(IContent), "content");
var isDeletedParam = Expression.Parameter(typeof(bool), "isDeleted");
// Cast content to the specific page type
var castContent = Expression.Convert(contentParam, pageType);
// Create method call for ProcessContent using the specific page type
var method = typeof(ContentEventInitialization)
.GetMethod(nameof(ProcessContent), BindingFlags.NonPublic | BindingFlags.Instance)
.MakeGenericMethod(pageType);
// Call ProcessContent((T)content, isDeleted)
var body = Expression.Call(Expression.Constant(this), method, castContent, isDeletedParam);
// Compile into a lambda expression: (IContent content, bool isDeleted) => ProcessContent((T)content, isDeleted)
var lambda = Expression.Lambda>(body, contentParam, isDeletedParam);
return lambda.Compile();
}
///
/// Updates the IsDeleted property for a specific content type and re-indexes it in Optimizely Find.
/// This method is intended to be called by actions generated for each page type.
///
/// The type of the content to process, which must inherit from PageData.
/// The content to be processed.
/// A boolean indicating whether the content is marked as deleted (true) or restored (false).
private void ProcessContent(IContent content, bool isDeleted) where T : PageData
{
var contentRepository = ServiceLocator.Current.GetInstance();
if (contentRepository.Get(content.ContentLink).CreateWritableClone() is T writableContent)
{
writableContent.IsDeleted = isDeleted;
if (isDeleted)
{
writableContent.Deleted = DateTime.Now;
writableContent.DeletedBy = PrincipalInfo.CurrentPrincipal.Identity.Name;
}
else
{
writableContent.Deleted = null;
writableContent.DeletedBy = null;
}
contentRepository.Save(writableContent, SaveAction.SkipValidation, AccessLevel.NoAccess);
_findClient.Index(writableContent);
}
}
}
ExcludeDeleted() の使用:
var detailPageQuery = _searchClient.Search()
.ExcludeDeleted()
.FilterForVisitor()
.FilterOnCurrentSite()
.CustomFilterForVisitor()
.Take(PAGINATION);
結論
Optimizely Content Events を使用して汎用ソリューションを作成することで、コンテンツ タイプの変更を動的に検出し、 IsDeleted フラグを設定し、リアルタイムで検索インデックスを更新します。このアプローチにより、ゴミ箱に入れられたコンテンツを検索結果から簡単に除外できるだけでなく、実行時のリフレクションのオーバーヘッドを発生させずに、コードベースをクリーンかつ効率的に保つことができます。
このソリューションは、から継承する任意のカスタム ページ タイプに適用できます。 SitePageDataにより、Optimizely CMS での検索の可視性をより適切に制御する必要があるプロジェクトに多用途に使用できます。
PS ご意見や代替案がございましたら、よろしくお願いいたします。
2024 年 11 月 7 日
#ゴミ箱に入れられたコンテンツが #Searc #に表示されないようにする