Searching for content

ContentReference vs PageReference

I use ContentReference since I think it's good practice to implement with the most general type for properties. I'm sure this can be debated, but that is my opinion.

In my current project there is a property for the article page called Author. This should be a reference to an employee page. It was implemented using ContentReference with the AllowedTypesAttribute set to the the employee page type. So far, so good. The editors however, found it difficult to locate the correct employee out of about 5 500 different pages. Surely these pages are structured in a hierachy according to the first two letters in the name of each employee. But even so, it wasn't very user friendly.

Now, how can we solve this? This is were a key difference between ContentReference and PageReference comes into play. Take a look at the picture below. The content selector for ContentReference is on the left, while the selector for PageReference is on the right.

ContentReference vs. PageReference
ContentReference vs. PageReference

Spot the difference (except for the difference in content)? I'm sure you do. When using PageReference, Episerver adds a search field at the top of the dialog. This enables the editor to search for a page using the configured search engine. Exactly what the editor was looking for in my case.

What about a list of pages?

In the same project we have another page that has a property called Authors, meaning potentially more than one. What then? Luckily Episerver has a built-in property of type IList<ContentReference>. But wait, we need PageReference. Hoping for consistency we try IList<PageReference>, but that results in YSOD (Yellow Screen of Death). Episerver has unfortunately not implemented this property type. Does than mean that we are stuck with the editors scrolling through the site's page hierachy?

Well, there is a way. It requires some DOJO scripting, but it's quite simple. It turns out that the content selector dialog for ContentReference and PageReference is exactly the same widget, but with a minor difference in configuration. And the IList<ContentReference> also ends up using the same widget when the editor clicks to add more content.

The widget in the latter case is called ContentReferenceListEditor. It contains a function called _createItemEditor which is called when the content selector dialog is opened. The solution to our "problem" is to extend this list editor and make a minor change in this function:

define([
    "dojo/_base/declare",

    "epi-cms/contentediting/editors/ContentReferenceListEditor"
],
    function (
        declare,

        ContentReferenceListEditor
    ) {
        return declare([ContentReferenceListEditor], {
            _createItemEditor: function () {
                return new this.itemEditorType({
                    canSelectOwnerContent: false,
                    showButtons: false,
                    roots: this.roots,
                    allowedTypes: this.allowedTypes,
                    restrictedTypes: this.restrictedTypes,
                    showAllLanguages: true,
                    disableRestrictedTypes: false,
                    searchArea: 'cms/pages'
                });
            }
        });
    });

The only difference is searchArea, which is set to 'cms/pages'. And to make sure our custom editor is loaded, we can for instance add the ClientEditorAttribute to our property with the correct value. Other attributes as AllowedTypesAttribute still work as normal.

[Display(Order = 255, GroupName = SystemTabNames.Content)]
[AllowedTypes(typeof(EmployeePage))]
[ClientEditor(ClientEditingClass = "editors/PageReferenceListEditor")]
public virtual IList<ContentReference> Authors { get; set; }

Läs mer om