SEO tip: Canonical link elements in Kentico CMS

   —   

The canonical link element is a feature which Google, Microsoft and Yahoo announced together to provide a better SEO options. Even that Kentico CMS does not support it directly yet, you can quite easily make this happen. Check out how ...

Hi there,

Simply said, canonical link element is a tag which allows you to make the page to behave as a page under different URL no matter where the page is or which parameters it. With this, you can join together several pages for SEO reasons. Something similar is possible with our new SEO settings in 5.0, but they are probably not as powerful as these canonical link elements.

We didn't go that far with our web sites yet so I cannot validate how useful these canonical links really are but they seem like a decent feature.

Before you continue further, it is necessary that you know how they work, so if you are not yet familiar with them, see the video from Matt Cutts (about 20 minutes).

You should also be familiar with the Macros in Kentico CMS.

What options do you have?

In this article, I will describe you two basic options you can use for your canonical links:
  • First one will not require any programming and will purely use macros and standard Kentico CMS UI to make the canonical links to be specified by the page editor (which may be also useful in some scenarios).
  • With the second one, I will use custom macros with a custom macro handler to allow the canonical links to be generated automatically. This will be just a few lines of code, you just need to know where to put it and how.
Canonical links defined by the page editor

To allow editor edit the canonical link, you need to add some field for it first, so just go to the Site manager -> Development -> Document types, and add some text field to any document where you want to allow this. I recommend you to share the name for it across all Document types, so you can use just single macro for it.



I used mine in Blog post document type and name it CustomCanonicalLink (text, 200 characters)

NOTE: You may need to allow the empty value for the field if you do not require your editors to enter the canonical link URL or modify some predefined document types such as CMS.MenuItem (which have their own custom inserting page).

Here is what editor can see, I will just enter the main document URL because I want all possible aliases of this document to behave as this main URL of the document (from the SEO perspective).



Now I need to use some macros as the site designer to allow this data to display where I need. Go to the Design tab of the root page (I want to include this to the master page because I want it to be supported on any page). Then add the web part Head HTML code because we want to add some head tags.

You just need to set two of it's properties:

 

  • HTML code - You just need to enter the canonical link HTML with the link value injected through a macro:
  • <link rel="canonical" href="{%CMSContext.CurrentDocument.CustomCanonicalLink%}

    (we are comparing the value against empty string, it gives true if the string is not empty)

    • Enabled - You need to click on the small arrow to edit the macro. We need this code to be displayed only when there is some value available, enter macro:
    So when the link URL is set, the canonical link is displayed. And that's it. If you look at the page which has the canonical link field set, you can see in the code of the web page that there is a canonical link:



    Now let's look at automatic canonical links.

    Automatic canonical links

    This will be quite similar yet different. We will use the same web part but this time a custom macro to populate the value of canonical link.

    Add the Head HTML web part on the master page and set its HTML code property to value:

    {#GetCanonicalLink#}



    This is the name of custom macro we will implement. You don't need to do any changes to the Enabled property since the macro code will ensure empty value if the data is not available.

    Now open the file ~/App_Code/Global/CMS/CMSCustom.cs, locate the method ResolveCustomMacro and replace it with following code:
    using CMS.TreeEngine;
    using CMS.PortalEngine;
    
    ...
    
    /// 
    /// Custom macro handler
    /// 
    ///Sender (active macro resolver)
    ///Expression to resolve
    ///Returns true if the macro matches (was resolved)
    public static string ResolveCustomMacro(MacroResolver sender, string expression, out bool match)
    {	
      match = false;
      string result = expression;
    
      // Add your custom macro evaluation
      switch (expression.ToLower())
      {     
        case "getcanonicallink":
          PageInfo currentPage = CMSContext.CurrentPageInfo;
          match = true;
          return "<link rel=\"canonical\" href=\"" + 
    	TreePathUtils.GetUrl(currentPage.NodeAliasPath, currentPage.DocumentUrlPath) + "\" />&quo&;;
      }
    
      return result;
    }
    
    In this case, the custom macro provides you with the complete tag for canonical link. I used current page info to get the main URL of the current document but you may generate just&&;any link.With this, you automatically get the canonical link for just any document using that master template.



    You can very easily control where to display it through web part properties or place the web part only on specific templates.

    What next?

    The next step is that you decide which way you want to go or even combine them, and let me and others know what is your experience with it.

    See you next time.
Share this article on   LinkedIn

Martin Hejtmanek

Hi, I am the CTO of Kentico and I will be constantly providing you the information about current development process and other interesting technical things you might want to know about Kentico.

Comments

David Thompson commented on

I had this issue and what I did with Kentico 5.5 was:

Root.Master.cs:

protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
PageInfo currentPage = CMS.CMSHelper.CMSContext.CurrentPageInfo;
ltlCanonical.Text = "<link rel=\"canonical\" href=\"" + UrlHelper.GetAbsoluteUrl(CMS.CMSHelper.CMSContext.GetDocumentUrl(CMS.CMSHelper.CMSContext.CurrentDocument.DocumentID)) + "\"/>";
}

In the head of Root.Master I added:

<asp:Literal runat="server" id="ltlCanonical" />


For both "/" and "/Home", the served url listed is "/Home". For tagpages with querystrings, the served url is "/tags" which lists all tagged pages. Seems to work OK.

sbenson-vocus commented on

Re: We need this code to be displayed only when there is some value available, enter macro:

I've applied this macro, as well as one for the Robots meta, and in both cases the code DOES appear if the value is blank. Rather than no value being seen in the source, I can see: "<link rel="canonical" href="" />"

Shouldn't the macra omit this tag if the value is blank?

john banning commented on

Great Article,
But I noticed that it is specific to the 5.X release. What would the correct syntax for the following look like?

{%CMSContext.CurrentDocument.CustomCanonicalLink != ""|(user)michalv|(hash)cae8e0e00a354f37793433c64297d9f7edacac9393ba24284dc49746ed087c18%}

Also, where does the ~/App_Code/Global/CMS/CMSCustom.cs live in the 6.0 release?

Thanks,
John

Steve Moss commented on

Hi Brendan

Maybe things have moved on, but this is a direct quote from Matt Cutts blog, at http://www.mattcutts.com/blog/canonical-link-tag/

Question: "Can this link tag be used to suggest a canonical URL on a completely different domain?"

Answer from Matt Cutts: "No. To migrate to a completely different domain, permanent (301) redirects are more appropriate. Google currently will take canonicalization suggestions into account across subdomains (or within a domain), but not across domains. So site owners can suggest http://www.example.com vs. example.com vs. help.example.com, but not example.com vs. example-widgets.com."

Steve

Brendan commented on

@Steve - sorry dude..you're wrong here. There is a cross domain use of canonical tags. Ideally multi domains should 301 redirect back to primary domain but where this is not possible then canonical tags can be used. Google says they don't honour 100% of the time though.
Re abuse, like anything in SEO world there's wide scope for abuse but am sure that Google does a lot of content matching to ensure the pages actually match first before looking at canonical tags.

@martin - excellent, found the settings. One problem though is that they don't seem to apply once saved, do I need to reset iis for them to take affect?

Appetere Web Solutions commented on

Hi Brendan

I think you have misunderstood the purpose of canonical links. They are only to specify which URL *within* a domain is the canonical URL. They do not allow you to specify a page in a different domain.

If you imagine the situation where it was possible to add a canonical link in one website which said the canonical page was on a different website - all sorts of abuse would be possible.

Regards,

Steve

Martin Hejtmanek commented on

Hi Brendan,

What version are you using? Both lowercase and 301 redirects are supported in version 5.5 and also redirects of domain aliases should work based on this setting. See this http://devnet.kentico.com/docs/5_5r2/devguide/index.html?url_format_and_configuration.htm

This article is about how to easily render canonical links even that the system doesn't support it, not a guide where to point particular URLs since that is typically based on particular content structure.

Could you please check the features in the new version and let me know what other options are you missing and how would you like them to look? We can always add them, we just need some feedback on it.

Brendan commented on

To me this looks like a completely incorrect use of the canonical tags.

From what I can see here, if I have 2 separate domains in kentico domain1.com and domain2.com then when I load domain1.com/folder the canonical tag is going to say domain1.com/folder is the correct version to use. When I load domain2.com/folder then the canonical tag is going to say domain2.com/folder is the correct version to use.

The whole point of this tag is to tell the search engine crawler which is the correct/authoritative version so your example above should write the domain name to the tag as well using the primary domain you want to show in the search results.

To me, Kentico is a nightmare from an SEO point of view. It doesn't support lower case characters natively, is doesn't natively support url rewriting or 301 redirecting secondary domains back to the target url at the primary domain and doesn't cleanly allow for canonical tags to be added to pages. End result is massive amounts of content duplication in search engines and potential duplicate content penalties.

This could be fairly easily fixed from a feature point of view by adding a canonical tag feature into the system and setting a primary domain for the site rather than having to cut code to fix it.

Martin Hejtmanek commented on

Thanks for sharing Brad!

Brad Vrudney commented on

I have finally figured this problem out. It requires IIS7, and the URLRewrite Module, and Kentico 5.5.

For the home page in CMSDesk, I have the Document URL Path = "/"

In the CMSSiteManager, under Settings -> Website I have Default alias path = "/"
In the CMSSiteManager, under Settings -> URLs and SEO I have:
Use URLs with trailing slash : Always use URLs with trailing slash
Redirect document aliases to main URL : Checked
Redirect invalid case URLs to their correct versions: Redirect all requests to lower case URLs

In the web.config I have:

<appSettings>
<add key="CMSUseExtensionOnPostback" value="false"/>
<add key="CMSUseTrailingSlashOnlyForExtensionLess" value="true" />
<add key="CMSDefaultPageURL" value="~/" />
</appSettings>

(This requires IIS7 and the URL Rewrite module)

<rule name="default" enabled="true" stopProcessing="true">
<match url="default.aspx" />
<conditions>
<add input="{REQUEST_URI}" negate="true" pattern="/cmsdesk/(.*)$" />
<add input="{REQUEST_URI}" negate="true" pattern="/cmssitemanager/(.*)$" />
</conditions>
<action type="Redirect" url="/" redirectType="Permanent" />
</rule>

The conditional rules prevent the admin tools from blowing up.

Martin Hejtmanek commented on

I thought you needed to do some nasty hacks with code to do that (at some point you did, but just minor). One way or another, now it will be easier for everyone ;-)

Redirecting of /default.aspx to / seems a general issue on IIS since it reports /default.aspx all the time. Here is an interesting discussion about that: http://www.ifinity.com.au/Blog/EntryId/45/301-Redirecting-from-default-aspx-to-the-site-root-the-final-word

Appetere Web Design & Web Development commented on

Thanks Martin. Although as I said in my earlier post I've already done this in Kentico 4.x just by setting up a redirection in CMS Desk (so it is possible :-) check out my site www.appetere.com to see the menu, sitemap and googlesitemap.aspx using "/"). Although to be fair, I did have to write one custom function to get the Google site map link correct for the home page.

Steve

Martin Hejtmanek commented on

Here is a follow up on that "/" thing:

I checked if it can be done and the answer is NO, current best configuration would cause an infinite loop of redirection.

But I figured out the way how to easily make that happen so you will be able to use it with hotfix 5.0.3 next Monday, I included the modification there.

So as soon as you will apply hotfix 5.0.3, you can do following:

1) Set the Home URL path to "/"
2) Add the web.config key <add key="CMSDefaultPageURL" value="~/" /> (it defaults to original "~/default.aspx")

And your home page will act as "http://www.appetere.com/" without the "default.aspx".

There is no guarantee that it will work under any configuration since it is a hotfix modification and wasn't fully tested. Let me know if you encounter any issues with it.

Martin Hejtmanek commented on

Hi Steve,

I am not sure if the redirection to / can be currently configured somehow, I must try it. I am planning a blog post to further explain the new SEO settings of Kentico CMS 5.0, I will post it soon.

Appetere Web Design & Web Development commented on

This is likely to have the most impact on the Home Page of a site:

With Kentico 4.x, the default behaviour is that menus & sitemaps always link to the home page, with something like www.devnet.kentico.com/Home.aspx (to use this site as an example). But people in the outside world, would typically link to the site using www.devnet.kentico.com. So immediately, you have a choice of which URL is the canonical one.

I've managed to sort this on my own Kentico site http://www.appetere.com/ by using some redirections in CMSDesk, so the menu, sitemap & Google sitemap all render links as "http://www.appetere.com/".

But I've not yet found a way to 301 redirect any requests for "/default.aspx" to "/".

If both the above can be addressed in Kentico 5.x, a blog post on this would be useful.

In the meantime, this new canonical link element on the home page, pointing to "/" will at least keep Google happy, without having to add redirections & such like.

Steve