Sitecore - alternate hreflang links for SXA
Posted 6 Feb 2022 by Marek Musielak
When you run a multilanguage site on Sitecore, you definitely want to tell Google about all the available translations of your content. Thanks to that Google Search will be able to point users to the most appropriate version of your pages. How you can achieve this? By adding rel="alternate" hreflang links in <head> part of your html.
This article explains how you can achieve that if you use Sitecore SXA. It assumes basic knowledge about SXA and that you know how to create new SXA renderings, add them to available renderings of your site and edit `Metadata` partial design.
First thing we need is a model class containing IEnumerable<KeyValuePair<string, string>> Links
property only. We're going to keep language codes and corresponding URLs there:
public class HreflangLinksModel { public IEnumerable<KeyValuePair<string, string>> Links { get; set; } }
Next comes interface for repository and repository itself. We build urlOptions with AlwaysIncludeServerUrl
set to true
and LanguageEmbedding
set to LanguageEmbedding.Always
to make sure we receive absolute URL with language included in it. We loop through all languages, check if item has any version in given language and build language specific url:
public interface IHreflangLinksRepository : IAbstractRepository<HreflangLinksModel> { HreflangLinksModel GetModel(Item item); } class HreflangLinksRepository : IHreflangLinksRepository { protected IContext Context { get; } protected IUrlOptionsProvider UrlOptionsProvider { get; } public HreflangLinksRepository(IContext context, IUrlOptionsProvider provider) { Context = context; UrlOptionsProvider = provider; } public HreflangLinksModel GetModel(Item item) { var links = new List<KeyValuePair<string, string>>(); var urlOptions = UrlOptionsProvider.GetUrlOptions(); urlOptions.AlwaysIncludeServerUrl = true; urlOptions.LanguageEmbedding = LanguageEmbedding.Always; foreach (var lang in item.Languages) { var langItem = item.Database.GetItem(item.ID, lang); if (langItem.Versions.Count > 0) { urlOptions.Language = lang; var itemUrl = LinkManager.GetItemUrl(langItem, urlOptions); links.Add(new KeyValuePair<string, string>(lang.Name, itemUrl)); } } return new HreflangLinksModel { Links = links }; } HreflangLinksModel IAbstractRepository<HreflangLinksModel>.GetModel() { return GetModel(Context.Item); } }
When we have model and repository, we can create a controller class inheriting from Sitecore SXA StandardController
. Nothing surprising there - just inject our repository and use it to build the model:
public class HreflangLinksController : Sitecore.XA.Foundation.Mvc.Controllers.StandardController { private readonly IHreflangLinksRepository _repository; public HreflangLinksController(IHreflangLinksRepository repository) => _repository = repository; protected override object GetModel() => _repository.GetModel(); }
Next thing we need is a view file. Create Views\HreflangLinks\HreflangLinks.cshtml
and add content as below. It loops through Model.Links
and generates rel="alternate" hreflang links:
@model MyAssembly.MyNamespace.Models.HreflangLinksModel @{ Layout = Sitecore.Configuration.Settings.GetSetting("XA.Foundation.Presentation.MetaComponentLayoutPath", "../SXA/Meta Component Layout.cshtml"); } @foreach (var link in Model.Links) { <link rel="alternate" hreflang="@link.Key" href="@link.Value" /> }
Finally, we need to register our repository and controller in Sitecore dependency injection with Sitecore config patch file:
<configuration> <sitecore> <services> <register serviceType="MyAssembly.MyNamespace.IHreflangLinksRepository, MyAssembly" implementationType="MyAssembly.MyNamespace.HreflangLinksRepository, MyAssembly" /> <register serviceType="MyAssembly.MyNamespace.HreflangLinksController, MyAssembly" implementationType="MyAssembly.MyNamespace.HreflangLinksController, MyAssembly" /> </services> </sitecore> </configuration>
When everything is ready code wise, we can create new ControllerRendering
for HreflangLinks and add it to metadata
partial design:
And that's it. Every page which uses metadata
partial design will generate rel="alternate" hreflang links in <head> tag: