Kontakt oss
Tilbake til bloggen
Development

Improved CategoryList editor descriptor for EPiServer

More than one time I have found myself in the need of a filtered category tree in EPiServer. In large sites there can be a lot of categories and sometimes you just want to force the web editors to choose from a predefined root category. What to do? Create a editor descriptor that replaces the built-in one!

Introduction

Of course, you could easily accomplish a filtered category list with the [SelectOne] or [SelectMany] attribute on a string property together with a ISelectionFactory, but I really don't like having to parse that string into a list of integers. I want a CategoryList! Period. :) My idea was to override the editor descriptor for CategoryList that's built into EPiServer. To be able to configure root category id or name, I created a custom attribute.

L'attribut

I added three root category configuration properties to my attribute, RootCategoryId, RootCategoryName and RootCategoryAppSettingKey. One of them is selected in the following priority:

  1. RootCategoryId
  2. RootCategoryName
  3. RootCategoryAppSettingKey (Name of appSetting key with root category id value)
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] public class CategorySelectionAttribute : Attribute { /// /// ID of the root category. /// public int RootCategoryId { get; set; } /// /// Name of the root category. /// public string RootCategoryName { get; set; } /// /// The appSetting key containing the root category id to use. /// public string RootCategoryAppSettingKey { get; set; } public int GetRootCategoryId() { if (RootCategoryId > 0) { return RootCategoryId; } if (!string.IsNullOrWhiteSpace(RootCategoryName)) { var category = Category.Find(RootCategoryName); if (category != null) { return category.ID; } } if (!string.IsNullOrWhiteSpace(RootCategoryAppSettingKey)) { string appSettingValue = ConfigurationManager.AppSettings[RootCategoryAppSettingKey]; int rootCategoryId; if (!string.IsNullOrWhiteSpace(appSettingValue) && int.TryParse(appSettingValue, out rootCategoryId)) { return rootCategoryId; } } return Category.GetRoot().ID; } }

Editor descriptor

To make things easy I inherited the CategoryListEditorDescriptor in EPiServer and set the EditorDescriptorBehavior to OverrideDefault. What I'm doing in the code is to check if one of the attributes is a CategorySelectionAttribute, and if true, I replace the settings that is passed to the dojo widget (epi-cms.widget.CategorySelector). Lucky for me, the category widget in EPiServer already has support for specifying a root category. :)

[EditorDescriptorRegistration(TargetType = typeof(CategoryList), EditorDescriptorBehavior = EditorDescriptorBehavior.OverrideDefault)] public class CustomCategoryListEditorDescriptor : CategoryListEditorDescriptor { public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable attributes) { base.ModifyMetadata(metadata, attributes); var categorySelectionAttribute = attributes.OfType<CategorySelectionAttribute>().FirstOrDefault(); if (categorySelectionAttribute != null) { metadata.EditorConfiguration["root"] = categorySelectionAttribute.GetRootCategoryId(); return; } var contentTypeCategorySelectionAttribute = metadata.ContainerType.GetCustomAttribute<CategorySelectionAttribute>(true); if (contentTypeCategorySelectionAttribute != null) { metadata.EditorConfiguration["root"] = contentTypeCategorySelectionAttribute.GetRootCategoryId(); } } }

Usage examples

[CategorySelection(RootCategoryId = 123)] public virtual CategoryList MyCategories { get; set; } [CategorySelection(RootCategoryName = "MyRootCategory")] public virtual CategoryList MyCategories { get; set; } [CategorySelection(RootCategoryAppSettingKey = "NewsRootCategoryId")] public virtual CategoryList MyCategories { get; set; }

The last example uses an appSetting to set root category id

<appSettings> <add key="NewsRootCategoryId" value="123" /> </appSettings>

Using the attribute on a content type class

You can also use the CategorySelectionAttribute on a content type class to set root category for all CategoryList properties, including the built-in PageCategory property. Property attribute targets have higher priority than class so you can still override class settings for specific properties.

[CategorySelection(RootCategoryId = 123)] [ContentType] public class StartPage : PageData { // Overrides settings on the class for this property [CategorySelection(RootCategoryId = 321)] public virtual CategoryList MyCategory { get; set; } }

Snakk med oss

Har du et prosjekt vi kan hjelpe med?

Ta en uforpliktende prat med teamet vårt om hvordan vi kan løse din utfordring.

Ta kontakt

Hold deg oppdatert på fremtidens e-handel

Ukentlige analyser, trender og praktiske råd — kun det vi selv ville lest.