Sitecore Link Resolving across sites and in EXM

Mark Gibbons
5 min readMar 30, 2021

--

Getting links to resolve correctly is trickier than one would expect.

The scenario that I want to go through here is like this:

  • 2 separate SXA sites
  • An email campaign where we want to have links to both sites
  • Both Rich Text and General Link fields can be used

The current Sitecore documentation on this is both very misleading and in one case downright incorrect unfortunately. I will go into that later.

I would like to say that having SXA shouldn’t make a difference, but unfortunately it does. So I’ll explain two ways to set this up, one with SXA, and one without.

Overview of what we’re trying to achieve

It’s all about the LinkManager and configured LinkProviders. We want them to do all the work for us, as we would expect if we were doing cross-site linking in normal Sitecore. So getting cross site linking working in your normal sites will also make it start working in SXA.

The part where Sitecore documentation is really misleading is it makes it seem you have to do something special with their Hostname Mapping tool. I know they also mention this:

The logic for generating URLs in an email message to content items is the same approach that Sitecore uses when rendering pages on a website.

But going on to give an example with multisite using just the Hostname Mapping tool is not going to work.

So the real key to using all of Sitecore’s OOTB logic is to make sure of the following

  • Ensure that the link provider has alwaysIncludeServerUrl=true when the context site is exm
  • targetHostName is set correctly on your sites

targetHostName: The host name to use when generating URLs to items within this site from the context of another site. If the targetHostName attribute is absent, Sitecore uses the value of the hostName attribute instead. Used only when the value of the Rendering.SiteResolving setting is true.

With SXA

  1. Ensure that you are using the default SXA <linkManager defaultProvider=”switchableLinkProvider”> More info here.
  2. On all sites in your solution, make sure that a single targetHostname is set. Ensure there’s no wildcards and it is the actual site URL that people use.
  3. Make sure that you’re using the LocalizableLinkProvider on all your sites (or if you need further customizations, base your code on the LocalizableLinkProvider and make sure to keep the magic around it setting the alwaysIncludeServerUrl to true if the targetHostname is set.
  4. That’s pretty much it.

Without SXA

  1. Override the LinkProvider to make sure that if the current context site is not the same as the site that it retrieves for the item set AlwaysInlcudeServerUrl to true in the URL options.
  2. As above, on all sites in your solution, make sure that a single targetHostname is set. Ensure there’s no wildcards and it is the actual site URL that people use.

Testing Notes

  • EXM will run most of its pipelines in preview mode when it comes to links. So it’s fine to test by using the quick test feature or navigating to the email item in the Content Editor and using the Message Preview tab. When you kick off an actual dispatch it will do a couple extra things like encrypt links with the contact ID but that shouldn’t break your links.
  • You’ll want to do an actual dispatch, then view the source of the email and make sure that the tracking pixel URL is resolvable. This is really important to get stats and analytics working. If the tracking pixel URL isn’t right, that’s when you can start looking at Hostname Mapping.

Gotcha #1 — Subdomain and top level domain

One gotcha I saw was that if one site is a subdomain of the top level domain then it won’t resolve correctly.

Example:

Site 1: https://test.com

Site 2: https://subdomain.test.com

It won’t actually work in this situation. If you can, change to using https://www.test.com. If you can’t, then a workaround is to set a link provider with AlwaysInlcudeServerUrl=true on your exm site.

Gotcha #2 — Multiple matching sites

You may have multiple sites that would match an item. This might be because you have your CM environment configured in Live mode (reading from master).

EXM will use the normal hostname match the same as any request, so if you are using a virtual directory on the CM site then it will appear in the URL.

I think this is a bug and it should be possible to instead choose the first site in configuration order, so feel free to raise with support, but for now I’ve gone with not having virtual directories on CM sites that need this feature.

Sitecore Docs

EXM verifies and generates hyperlinks according to the following process that is specified in the modifyHyperlink pipeline

This isn’t correct. It will in many cases have resolved the link before it gets here. A few situations where it won’t have resolved the link yet, in which case this logic does kick in.

Sitecore Link Provider / URL Builder weirdness

Why do we even need to go to all this extra effort of playing with AlwaysInlcudeServerUrl value? To me, the default item URL builder should be taking care of this, and it should somewhat take into account the current Site Context.

  • If we are not in the same Site Context as the target item, automatically set AlwaysInlcudeServerUrl=true
  • If we are in the same Site Context as the target item and AlwaysInlcudeServerUrl=true, then resolve the server URL by taking into account the targetHostname. Currently it does not do this — it instead checks if the request URL matches the hostName and then uses the request URL instead! This is totally a bug, especially where we might have a load balancer pinging the site on an internal URL, this result may then get cached.

Sitecore Versions Applicable

  • I confirmed the above behaviour on Sitecore 9.1.1 and Sitecore 10.1.0
  • The exact behaviour around the item URL builder has changed in 9.3+
  • There is a known issue in 9.3 and 10.0 around this — public ref 391005. See the fix in 10.1.0 release notes.
  • In 10.1.3 (and possibly all the latest 10.x.x cumulative hotfixes), the behaviour has changed yet again. LinkProviderService has been changed so that if the current site does not have the IsSxaSite=true property, it will force using the sitecore provider. So going forward, you’ll need to pretty much always patch the sitecore provider with either the SXA LocalizableLinkProvider or your custom implementation discussed in the “non SXA” section above.
The latest 10.1.3 LinkProviderService implementation

--

--

Mark Gibbons
Mark Gibbons

Written by Mark Gibbons

Technical Architect @ Aceik | Sitecore Technology MVP 2020 - 2024 with a love for all things #Sitecore / Twitter twitter.com/markgibbons25

No responses yet