Adding dynamic HTML to property templates in EPiServer

When developing websites, sometimes adding extra attributes to certain HTML tags is needed, in certain situations. It could be data attributes on all tags linking to external URLs, media or document files, to hook up tracking events in frontend (e.g. using Google Tag Manager). Or it could be that certain types of links should always open in a new tab.

This blog post is about solving this task in an EPiServer solution.

Solution outline

I once came up with the following solution for an EPiServer project.

This is the key: in EPiServer the built-in property types are rendered to HTML using a set of Display Templates. These templates are Razor view files (as in ASP.Net MVC) and they can be overridden by adding a file with the same name as the original file. EPiServer keeps the original display templates in an internal zip-file, located under the modules folder in the web root folder, but you can create a new folder, called "DisplayTemplates", in the Views/Shared folders in the web root folder.

This is inherently a generic solution, as it is applied to all properties of a certain type at once, when using the built-in PropertyFor method. No need to implement something specifically for a lot of properties - I have done that too. Even though this post is about attributes on links, the solution is not limited to this. It works for other property types as well.

To showcase the solution, I will override the templates for these types: ContentReference, Url and XhtmlString. These templates will render standard HTML markup, plus some computed extra attributes (where relevant).

This is somewhat easy to do for the ContentReference and the Url types. But the XhtmlString content is more complex to manipulate, since the content of this property type is not strongly-typed, but rather stored as raw HTML, including link URLs. The internal URLs are virtual paths to an internal link, consisting of a unique GUID value. Therefore, some parsing is needed to make this work.

Imagine the following requirements. They might seem weird at first, but an analytics consultant might need something like them for special reporting.

  • Certain data attributes should be applied to link tags in any page or block, no matter if the links are rendered from ContentReference, Url or links in a rich text.
  • The rules apply to links to external pages OR to internal media or document files.
  • The attributes should be computed according to certain rules (see the table below).
Attribute name If "mailto:" link If not on this site If media file
data-category "Contact" "External" "Download"
data-label The e-mail address The absolute URL The file name
data-action "mailto" "External" The file extension
download -- -- The file name

Implementation

First, create a service class. This one is responsible for parsing URLs of links, resolving their targets and returning the relevant computed attributes. It consists of three public methods, for handling ContentReference, Url and XhtmlString properties.

Next, create an extension class for the HtmlHelper class, which EPiServer also extends, to invoke the service from the Razor views. It contains two methods for the ContentReference and Url types, so we can get the attributes in the form of a RouteValueDictionary or a HtmlString. Also, it contains a method that returns a HtmlString for a XhtmlString.

Then, create the beforementioned Razor views for the display templates. One for each of the three property types.

ContentReference.cshtml:

Url.cshtml:

XhtmlString.cshtml:

I hope that this was useful, even if you do not have the same requirements as these. If you need something resembling this, you could use this method and just implement your own attributes, values and rules.
An alternative solution could be to statically render the attributes, or having separate CMS properties for the attributes.