Bartosz Sekula
Sep 14, 2022
  6754
(4 votes)

Built-in support for single LinkItem property

EPiServer.CMS 12.11.0 introduces a new property type LinkItem . This feature has been one of the most requested features for a long time.

The feature is very simple: it is to allow the editor to choose a single LinkItem. 

After clicking the `Add Link` button editor is presented with the standard Linkitem dialog:

After selecting any content item the editor will look like this:

In order to use the new property type you just need to use the LinkItem data type. No annotations are needed.

public class PartnerPage : PageData
{
    public virtual LinkItem MyLink { get; set; }
}

Migration from EPiServer.Labs.LinkItemProperty

If you used the Labs package before and you wish to update then you will need to follow a few manual upgrade steps:

Labs used the following:

public class PartnerPage : PageData
{
    [LinkItemProperty]
    [BackingType(typeof(PropertyLinkCollection))]
    public virtual LinkItem Link
    {
        get => this.GetLinkItemPropertyValue(nameof(Link));
        set => this.SetLinkItemPropertyValue(nameof(Link), value);
    }
}

You have to remove both LinkItemProperty and BackingType annotations and switch to auto property.

public class PartnerPage : PageData
{
    public virtual LinkItem Link { get; set; }
}

You will also need to run the following SQL command (don't forget to do the backup for safety)

DECLARE @PropertiesToUpdate NVARCHAR(4000); -- one or more coma separated properties to update with [ContentTypeName.PropertyName] format
SET @PropertiesToUpdate = ''; -- for example ArticlePage2.SingleLink,ArticlePage2.SingleLinkCultureSpecific

-- update published versions
UPDATE tblContentProperty
 SET tblContentProperty.LongString = SUBSTRING(  -- start after `<links>`
           SUBSTRING(propValue.LongString, 0, CHARINDEX('</a>',  propValue.LongString) + 4), -- remove all text after first `</a>`
           8, 100000)
 OUTPUT INSERTED.*, deleted.*
  FROM tblPropertyDefinition propDef
  JOIN tblPropertyDefinitionType propDefType ON propDefType.[Name] = 'LinkCollection'
   AND propDef.fkPropertyDefinitionTypeID = propDefType.pkID
  JOIN tblContentType ON tblContentType.pkID = propDef.fkContentTypeID
  JOIN tblContentProperty propValue ON propValue.fkPropertyDefinitionID = propDef.pkID
 WHERE propValue.LongString LIKE '<links>%'
   AND CHARINDEX(tblContentType.[Name] + '.' + propDef.[Name] + ',', @PropertiesToUpdate + ',') > 0;

-- update versions  
UPDATE tblWorkContentProperty
   SET tblWorkContentProperty.LongString = SUBSTRING(  -- start after `<links>`
          SUBSTRING(propValue.LongString, 0, CHARINDEX('</a>',  propValue.LongString) + 4), -- remove all text after first `</a>`
          8, 100000)
OUTPUT INSERTED.*, deleted.*
  FROM tblPropertyDefinition propDef
  JOIN tblPropertyDefinitionType propDefType ON propDefType.[Name] = 'LinkCollection'
   AND propDef.fkPropertyDefinitionTypeID = propDefType.pkID
  JOIN tblContentType ON tblContentType.pkID = propDef.fkContentTypeID
  JOIN tblWorkContentProperty propValue ON propValue.fkPropertyDefinitionID = propDef.pkID
 WHERE propValue.LongString LIKE '<links>%'
   AND CHARINDEX(tblContentType.[Name] + '.' + propDef.[Name] + ',', @PropertiesToUpdate + ',') > 0;

-- update property type
UPDATE tblPropertyDefinition
   SET tblPropertyDefinition.fkPropertyDefinitionTypeID = (SELECT pkID from tblPropertyDefinitionType where [Name] = 'LinkItem')
OUTPUT INSERTED.*, deleted.*
  FROM tblContentType
 WHERE tblPropertyDefinition.fkPropertyDefinitionTypeID = (SELECT pkID from tblPropertyDefinitionType where [Name] = 'LinkCollection') 
   AND CHARINDEX(tblContentType.[Name] + '.' + tblPropertyDefinition.[Name] + ',', @PropertiesToUpdate + ',') > 0;

Afterwards the Labs package can just be uninstalled.

Sep 14, 2022

Comments

Please login to comment.
Latest blogs
Optimizely Opal: How to Build Effective Workflow Agents

If you're building workflow agents in Optimizely Opal, this post covers how specialized agents pass context to each other, why keeping agents small...

Andre | May 20, 2026

ReviewPR: An Azure Function That Reviews Your Azure DevOps Pull Requests With Claude

A while back I wrote about an  Azure Function App for PDF creation that we use to offload PDF rendering from our Optimizely DXP site. That same...

KennyG | May 19, 2026

Accelerating Optimizely CMS and Commerce upgrades with agentic AI (Part 2 of 2)

The Real Transformation in Optimizely CMS 13: Why the Upgrade Itself Is the Easy Part. A field-tested playbook for enterprise teams moving from...

Hung Le Hoang | May 18, 2026

Is the most powerful AI model really the best value?

Artificial Intelligence is already becoming part of everyday software development. Developers now use AI tools to generate code, write documentatio...

K Khan | May 16, 2026