World is now on Opti ID! Learn more

janaka.fernando
Mar 13, 2013
  9447
(0 votes)

Adding Canonical support to EPiServer sites

Avoiding Duplicate Content

I think everyone loves the Simple Address feature in EPiServer CMS to easily set up friendly URLs.  If you haven't come across it, Simple Address lets you set a simple URL that will come after the site domain.  This is useful if you have a long URL to the page and want to print or send a short URL  - for example a landing page that you want to direct traffic to.

So for the example here I would have two URLs

http://janaka.uk.episerver.com/About-us/News-Events/Press-Releases/Alloy-pays-it-forward/

simply becomes

http://janaka.uk.episerver.com/Forward/

Now while this is great, it produces two unique URLs with identical content... a big no-no with Google page ranking. To avoid getting penalized for this, you need to set the canonical link to let the search engine know which URL is the primary source of this content to index.

Setting a canonical URL is pretty simple, its a single <link> tag that needs to go into your <head> tag.  So for the above example we'd simply need either of the following:

Absolute <link rel="canonical" href="http://janaka.uk.episerver.com/About-us/News-Events/Press-Releases/Alloy-pays-it-forward/" />
or
Relative <link rel="canonical" href="/About-us/News-Events/Press-Releases/Alloy-pays-it-forward/" />

 

Adding Canonicalization Support to EPiServer

So we need to add a canonical link whenever a page has a Simple Address.  I'm using the new Alloy sample code base for my examples here.  I want to modify the <head> section so looking at the existing code this is best achieved through the master page base class - SiteMasterPage

Below is an excerpt from the SiteMasterPage.cs file with my modifications

 

public abstract class SiteMasterPage : System.Web.UI.MasterPage
    {
        protected override void OnLoad(System.EventArgs e)
        {
            base.OnLoad(e);
 
            if (Master != null)
            {
                return;
            }
 
            SetupMetaTags();
            SetupCanonicalURL();
        }
 
        private void SetupCanonicalURL()
        {
            // Add canonical url meta tag for simple address
            if (!string.IsNullOrEmpty(CurrentPage.ExternalURL) &&
                string.Compare(CurrentPage.ExternalURL, 
                 Request.Url.Segments.Last().Replace("/", ""), true) == 0)
            {
                var urlBuilder = new UrlBuilder(CurrentPage.LinkURL);
 
                if (EPiServer.Global.UrlRewriteProvider.ConvertToExternal(urlBuilder,                                                             
                                    CurrentPage.ContentLink,
                                    System.Text.Encoding.Default))
                {
                    string sourceUrl = urlBuilder.Uri.ToString();
                    var canonicalLink = new HtmlLink();
                    canonicalLink.Attributes.Add("rel", "canonical");
                    canonicalLink.Href = sourceUrl;
 
                    Page.Header.Controls.Add(canonicalLink);
                }
            }
     }
}

Some points to note here.  The API provides a property CurrentPage.ExternalURL which will have the simple address.  If this is present I then check if this is the current URL ( as opposed to the long name URL ).  Finally the rest if fairly straightforward, using the UrlBuilder to construct the external link to the page, then writing this to the Link.  Note that in this example I am using relative links, because CurrentPage.LinkURL is relative, but you could build up the full path and use absolute links using Uri.AbsoluteUri.

Language Fallback & Replacement

In addition to the Simple Address, another place to provide automatic support for canonical URLs is when using language replacement or fallback.  In this case the URL will be different depending on the language, but the site will contain duplicated content. 

I've refactored the previous code sample and added a second condition to the SiteMasterPage SetupCanonicalLink method, checking if the current page's language is different from what is expected.  If it's different I load the source content and update the LinkURL to indicate the source language. 

 

private void SetupCanonicalURL()
        {
            // Add canonical url meta tag for simple address
            if (!string.IsNullOrEmpty(CurrentPage.ExternalURL) &&

string.Compare(CurrentPage.ExternalURL,

Request.Url.Segments.Last().Replace("/", ""), true) == 0)

            {
                var urlBuilder = new UrlBuilder(CurrentPage.LinkURL);
                WriteCanonicalLink(urlBuilder);
            }    
 
 
            // Add canonical url meta tag for language fallback/replacement 
            if (CurrentPage.Language != ContentLanguage.PreferredCulture)
            {
                var sourcePage = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IContentRepository>()
                                                                                 .Get<PageData>(CurrentPage.ContentLink, 
                                         new LanguageSelector(CurrentPage.Language.Name));
                var sourceUrl = UriSupport.AddLanguageSelection(sourcePage.LinkURL, CurrentPage.Language.Name);
                var sourceUrlBuilder = new UrlBuilder(sourceUrl);
 
                WriteCanonicalLink(sourceUrlBuilder);
            }
        }
 
        private void WriteCanonicalLink(UrlBuilder url)
        {
            
            if (EPiServer.Global.UrlRewriteProvider.ConvertToExternal(url, CurrentPage.ContentLink, System.Text.Encoding.Default))
            {
                string sourceUrl = url.Uri.ToString();
                var canonicalLink = new HtmlLink();
                canonicalLink.Attributes.Add("rel", "canonical");
                canonicalLink.Href = sourceUrl;
 
                Page.Header.Controls.Add(canonicalLink);
            }
        }

 

Further reading:

http://www.seomoz.org/blog/canonical-url-tag-the-most-important-advancement-in-seo-practices-since-sitemaps

http://www.mattcutts.com/blog/seo-advice-url-canonicalization/

http://support.google.com/webmasters/bin/answer.py?hl=en&answer=139394

Mar 13, 2013

Comments

Please login to comment.
Latest blogs
Make Global Assets Site- and Language-Aware at Indexing Time

I had a support case the other day with a question around search on global assets on a multisite. This is the result of that investigation. This co...

dada | Jun 26, 2025

The remote server returned an error: (400) Bad Request – when configuring Azure Storage for an older Optimizely CMS site

How to fix a strange issue that occurred when I moved editor-uploaded files for some old Optimizely CMS 11 solutions to Azure Storage.

Tomas Hensrud Gulla | Jun 26, 2025 |

Enable Opal AI for your Optimizely products

Learn how to enable Opal AI, and meet your infinite workforce.

Tomas Hensrud Gulla | Jun 25, 2025 |

Deploying to Optimizely Frontend Hosting: A Practical Guide

Optimizely Frontend Hosting is a cloud-based solution for deploying headless frontend applications - currently supporting only Next.js projects. It...

Szymon Uryga | Jun 25, 2025

World on Opti ID

We're excited to announce that world.optimizely.com is now integrated with Opti ID! What does this mean for you? New Users:  You can now log in wit...

Patrick Lam | Jun 22, 2025

Avoid Scandinavian Letters in File Names in Optimizely CMS

Discover how Scandinavian letters in file names can break media in Optimizely CMS—and learn a simple code fix to automatically sanitize uploads for...

Henning Sjørbotten | Jun 19, 2025 |