Custom settings for link properties in EPiServer CMS

April 1st, 2013

Even though a solution for this is already out there, albeit somewhat incoherent, way too many EPiServer websites lack the ability to limit the selection of pages editors may choose from when selecting a link in Edit mode. Editors cost money, and we need to keep them efficient and happy; that is in fact one of the primary objectives of a CMS system.

Problem description: An editor is expected to select a page, from either a page property or link collection, of a certain pagetype in a certain node of the tree structure. The window opens a view of the entire tree structure, so the editor needs to find the appropriate node and it’s also possible they choose a page based on a pagetype not meant to be linked to. This may cause confusion and irritation at best, or a crashed website at worst. (Is there anything worse than that?)

Desired result: The editor will see a tree starting from a page defined in the startpage, and will only be able to select pages based on pre-configured pagetypes.

Recipe:
– Strongly typed properties, “Page Type Builder
– Custom property “EPiServer Filtered Page Reference
– Salt n pepper

Instructions:
Copy FilteredPageReference.dll to your Lib folder and reference it from your pagetypebuilder project.

Create an attribute setting:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//using PageTypeBuilder;
    //using FilteredPageReference;
 
    public class FilterPagesByMyTypeSettingsAttribute : Attribute, IUpdatePropertySettings<PropertyFilteredPageReferenceSettings>
    {
        public bool OverWriteExistingSettings
        {
            get { return true; }
        }
 
        public int GetSettingsHashCode(PropertyFilteredPageReferenceSettings settings)
        {
            return settings.GetHashCode();
        }
 
        public void UpdateSettings(PropertyFilteredPageReferenceSettings settings)
        {
            settings.RestrictToEPiServerPages = true;
            settings.AllowedPageTypesAndInterfaces = new Type[] { typeof(MyType) };
 
            var startPage = DataFactory.Instance.GetPage(PageReference.StartPage);
            PageReference start = (PageReference)startPage["MyContainer"];
            if (!PageReference.IsNullOrEmpty(start))
            {
                settings.StartFrom = start;
            }
        }
    }

Add the attribute you created to the property definition, and change the type of the property: From PageReference to PropertyFilteredPageReference, and PropertyLinkCollection to PropertyFilteredLinkCollection.

Example:

?View Code CSHARP
1
2
3
[FilterPagesByMyTypeSettings]
    [PageTypeProperty(Type = typeof(PropertyFilteredPageReference), EditCaption = "Link to a page")]
    public virtual PageReference MyLink { get; set; }

That’s it! But.. there’s always a but.. if the reference to the start node container is missing when the property is created, the startnode setting doesn’t seem to work at all on the created property. You could adjust those manually by changing the settings in admin mode, or delete the properties manually and re-compile.
If you dislike manual work, below is a workaround to ensure that the correct startnode is shown anyway.

Edit global.cs:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected void Application_Start(Object sender, EventArgs e)
{
   PropertyFilteredPageReferenceSettings.GetPagePickingStartPage = GetPagePickingStartPage;
}
 
private static void SetPickingStartPage(PagePickingStartPage pagePickingStartPage, Type pageTypeType, PageData startNodeReferenceHolderPage, Type pageType, string pagereferencePropertyName, string limitedPropertyName)
        {
            if (pageTypeType.Equals(pageType) && string.Equals(limitedPropertyName, pagePickingStartPage.PropertyInformation.PropertyName))
            {
                PageReference startNode = (PageReference)startNodeReferenceHolderPage[pagereferencePropertyName];
                if (!PageReference.IsNullOrEmpty(startNode))
                {
                    pagePickingStartPage.StartPage = startNode;
                }
            }
        }
 
private void GetPagePickingStartPage(PagePickingStartPage pagePickingStartPage)
        {
            Type pageTypeType = PageTypeResolver.Instance.GetPageTypeType(pagePickingStartPage.PropertyInformation.PageTypeId);
            if (pageTypeType == null)
                return;
 
            var startPage = DataFactory.Instance.GetPage(PageReference.StartPage);
            SetPickingStartPage(pagePickingStartPage, pageTypeType, startPage, typeof(StartType), "MyContainer", "MyLink"); // Duplicate for other properties
        }

This code was tested using EPiServer CMS 6 R2, PageTypeBuilder 2.0 and EPiServer Filtered Page Reference v1.5.3.

Leave a Reply