Torunn Surnflødt
Mar 21, 2025
  2937
(3 votes)

Links in Optimizely Cms: A guide

In Optimizely CMS there are several ways to link to internal or external content using different property types, and there are several ways to render these properties. This can be confusing, so here is an overview to hopefully make it easier to choose the best option
We will also take a look at the "on page edit" functionality in this matter, and make sure the links are properly localized..

This article is based on Optimizely Cms 12 with razor views, and the Alloy solution is used for demonstration.

Choose the correct property type

First, we will map out the different property types available.

Link to pages

There are two options when creating a property for linking to other pages:
 

  • ContentReference:  A good option if there is no need for linking to external content. You can also limit which pagetype should be allowed, using annotation.
     
    public virtual ContentReference Link1 { get; set; }
  • Url: If you want a simple property for linking both internally and externally.

    public virtual Url Link2 { get; set; }

 

Images

  • Url with UIHint.Image: If you want a property for choosing an image, you can use the Url property with a UIHint.

    [UIHint(UIHint.Image)]
    public virtual Url Link3 { get; set; }
    The UIHint can also be used for the ContentReference type.

General links

  • LinkItem: If you want a property for adding a link to either internal or external content, the best option is LinkItem. This will give you some extra attributes, which is described later on.

    public virtual LinkItem Link5 { get; set; }
  • LinkItemCollection: If you want the possibility to add multiple links, like a link list, you can use LinkItemCollection:

    public virtual LinkItemCollection Link4 { get; set; }

 

Choose how to render the property

Now, when you have chosen the preferred property type, the next step is to choose the correct way to render the property.

Unformatted

The Url property can be rendered directly, with no formatting, but this will not give you a friendly url.

  • Url:
    <a href="@Model.CurrentPage.Link2">Link</a>

    Result:
    <a href="/link/fdac9c5f86b64223b4a6397fe72483f9.aspx">Link</a>

     
  • Url with UIHint for image:
    <img src="@Model.CurrentPage.Link3" width="50"/>

    Result:
    <img src="/link/6f97d70164be4681975690d8f8c05379.aspx" width="50">

 

Friendly urls and localization

To make sure you get a url which takes into account localization and gives you a user friendly url, you should use the UrlResolver in backend and the UrlHelper in the views. Here is how to do this for the different property types:

 

Razor views:

  • ContentReference:
    <a href="@Url.ContentUrl(Model.CurrentPage.Link1)">Link</a>

    Result: 
    <a href="/no/alloy-plan/">Link</a>

     
  • Url:
    <a href="@Url.ContentUrl(Model.CurrentPage.Link2.Uri.ToString())">Link</a>

    Result: 
    <a href="/en/alloy-plan/">Link</a>
     

  • Url with UIHint for image:
    <img src="@Url.ContentUrl(Model.CurrentPage.Link3.Uri.ToString())" width="50" />

    Result:
    <img src="/globalassets/pexels-binoculars.jpg" width="50">

     
  • LinkItem:
    <a href="@Url.ContentUrl(Model.CurrentPage.Link5.Href)">Link</a>

    Result:
    <a href="/en/alloy-plan/">Link</a>

 

  • LinkItemColleciton:

    You will have to loop through the items in the LinkitemCollection to render each item the same way as the LinkItem above

    <ul>
    @foreach (var link in Model.CurrentPage.Link4)
    {
     <li><a href="@Url.ContentUrl(link.Href)">Link</a></li>
    }
    </ul>

    Result:
    <ul>
    <li><a href="/en/alloy-plan/">Link</a></li>
    <li><a href="/en/alloy-track/">Link</a></li>
    </ul>

 

Backend:

  • For backend it will be similar, just use an instance of the urlResolver instead.

    UrlResolver _urlResolver;
    (…)
    var url = _urlResolver.GetUrl(startPage);

 

LinkItem

Let's take a closer look at the LinkItem property. Previously, it was only available as part of the LinkItemCollection and could not be used independently. It is now available as a standalone property type, which is very convenient. The Url property gives you a simple way to add a url, whereas the LinkItem lets you store information such as text, target and link attributes. It also provides these methods:

 

  • GetMappedHref():

    /link/fdac9c5f86b64223b4a6397fe72483f9.aspx

     
  • ToMappedLink():

    <a title="Link to Alloy Plan" href="/link/fdac9c5f86b64223b4a6397fe72483f9.aspx">Read more about Alloy Plan</a>

     
  • ToPermanentLink():

    <a title="Link to Alloy Plan" href="~/link/fdac9c5f86b64223b4a6397fe72483f9.aspx">Read more about Alloy Plan</a>

None of these gives you a friendly or localized url though.

 

On page edit

The on page edit is a useful mode for the editor, so you should put in some effort to make it function properly.

There are three different ways to add this functionality:

 

  1. The good old "@Html.PropertyFor"
     
  2. The newer version "epi-property"
     
  3. And the helpful "@Html.EditAttributes" which can come into rescue where the above mentioned is not sufficient

 


All of them gives the same on page edit functionality. Example of the three options used with the Url property:

 

  1. @Html.PropertyFor(x => Model.CurrentPage.Link2)
  2. <a href="@Model.CurrentPage.Link2" epi-property="@Model.CurrentPage.Link2">Link</a> 
  3. <a href="@Model.CurrentPage.Link2" @Html.EditAttributes(x => Model.CurrentPage.Link2)>Link</a>


Now, there are some differences to the rendered markup. Number 2 and 3 will give you a simple link:


<a href="/link/fdac9c5f86b64223b4a6397fe72483f9.aspx">Link</a>

 

But number 1 will gives you significantly more out of the box. It provides a friendly url, automatically uses the page name as the link text, and ensures the link is properly localized for the correct culture.

<a href="/en/alloy-plan/">Alloy Plan</a>


Lets check out another example - the LinkItemCollection. As you remember from earlier, you had to manually loop through the items and render them one by one. If you want a simpler solution, you can use the Html.PropertyFor.


@Html.PropertyFor(x => Model.CurrentPage.Link4)


This will create the following markup:

<ul>
<li>
<a href="/en/alloy-plan/" title="Link to Alloy Plan">Read more about Alloy Plan</a>
</li>
<li>
<a href="/en/alloy-track/" title="Link to Alloy Track">Read more about Alloy Track</a>
</li>
</ul>

 

So the Html.PropertyFor gives you a full markup with on page edit and properly localized urls. Pretty nice - but there is one drawback. You don't have any control of the markup, regarding e.g. adding css classes.

 

Absolute Url

Often, you will need an absolute url, not just a relative one.  To achieve this, you can combine the relative url you have obtained using one of the methods mentioned earlier, with the site url:

 

var siteUrl = SiteDefinition.Current.SiteUrl.AbsoluteUri.TrimEnd('/');
var absoluteUrl = string.Concat(siteUrl, url);

 

This gives you an absolute url: https://localhost:5080/en/alloy-plan/

 

Summary

We have looked at different property types for creating link properties in Optimizely Cms 12:
 

  • The ContentReference is for linking to an internal page
  • The Url and the LinkItem can be used for linking internally or externally, where the latter lets you apply attributes like text, title and target
  • The Url with a UIHint annotation will let you link to media
  • The LinkItemCollection is convenient when you need multiple links

 

We looked at different ways to render each property type:

  • Unformatted: works for the Url property
  • Friendly, localized url: obtained using the UrlHelper for frontend and UrlResolver for backend
  • On page edit: different ways of rendering while maintaining the on page edit functionality


Finally, we looked at different ways to maintain the on page edit functionality for these property types.

  • @Html.PropertyFor
  • epi-property
  • @Html.EditAttributes

 

I hope this was helpful! Please let me know if you have any feedback.

Mar 21, 2025

Comments

Please login to comment.
Latest blogs
Lessons from Building Production-Ready Opal Tools

AI tools are becoming a normal part of modern digital platforms. With  Optimizely Opal , teams can build tools that automate real tasks across the...

Praful Jangid | Mar 7, 2026

My Takeaway from Optimizely Opal Agents in Action 2026 - What Agentic AI Means for the Future of Digital Marketing

I would like to share with you what stayed in my head after this amazing virtual event organized by Optimizely. Agents in Action 2026 , a live...

Augusto Davalos | Mar 6, 2026

From Vision to Velocity: Introducing the Optimizely MVP Technical Roundtable

Digital transformation is a two-sided coin. On one side, you have the high-level strategy, the business cases, the customer journeys, and the...

Patrick Lam | Mar 6, 2026

Commerce 14.45.0 is incompatible with CMS 12.34.2 (but that's an easy fix!)

Incompatible is a strong word, but that is to get your attention. This is one of the small thing that can be overlooked, but if you run into it, it...

Quan Mai | Mar 5, 2026

Announcing Stott Security Version 5.0

March 2026 marks the release of Stott Security v5, a significant update to the popular web security add-on for Optimizely CMS 12+, with more than...

Mark Stott | Mar 5, 2026

Is Opal the Enterprise-Ready Evolution of OpenClaw?

From OpenClaw experiments to enterprise AI agents: exploring the journey from my personal automation to governed execution at scale with Optimizely...

Hristo Bakalov | Mar 5, 2026 |