Add `hreflang` for different domains
b
We can add
hreflang
to tell search engines about alternative language versions of a page, which is simply enough with the new language setup in Umbraco and just loop
Cultures
on the specific node. https://umbraco.com/blog/seo-friendly-cms-part-2-technical-seo-features#hreflang-tags However it is also possible to use
hreflang
across different domains (eventually subdomains). What is the best way to handle this with the old language setup in Umbraco (a site node per language). https://developers.google.com/search/docs/specialty/international/localized-versions The similar page in another language doesn't necessary need to exists at same level. The simple solution is just to add a content picker to site nodes, so on "en" site the content editors can pick "da", "de", "nl" etc. versions or the page, but is there a better way to handle this?
f
I've seen the solution you proposed (content picker) in production. If you are running V10 it's a lot easier to to, before the deleted pages needed to be tracked and it was a mess contentwise. Nothing we couldn't sort out in code though. The major downside with a solution like this is editors not bothering to pick the pages since it's to much work. That said, I can't think of a better solution when you can't predict where the content lives.
b
Yeah, in newer projects in is possible to get tracked references of a content node. Not sure how well it performs in frontend though. It could probably implement relations so if page A had picked page B, then page B would also know about reference to page A. Then it may only require to pick pages on "en" site, but there's a chance a page only exists in "da" and "de". Anyway I guess we on each page could just pick alternative versions - if the referenced page is deleted or not published, it doesn't exist in cache anyway. This project is on Umbraco 12 though.. do you think there's a better way to handle this nowadays? 🙂
m
If you happen to be using translation manager, it sets up relations which might be perfect (not 100% if it maps node to node but think it does)
b
I solved it using a custom property editor using a custom relation type and re-use MNTP view + configuration. Then the editor only need to relate pages on the English site, but could possible pick some on the other language version in case a page only exists in Danish and German, but not in English. I have an "Alternative Page" property on a SEO composition.
Copy code
var altPages = Model.AlternativePages
        ?.Append(Model)
        .ToList() ?? new();

var relatedPageIds = RelationService.GetByParentOrChildId(Model.Id)
    .Where(x => x.RelationType.Alias == Constants.RelationTypes.RelatedAlternativePageAlias)
    .Select(x => x.ParentId == Model.Id ? x.ChildId : x.ParentId)
    .ToList();

if (relatedPageIds.HasAny())
{
    var page = Umbraco.Content(relatedPageIds.FirstOrDefault());
    if (page is ISeo seo)
    {
        altPages.Add(page);
        altPages.AddRange(seo.AlternativePages ?? Enumerable.Empty<IPublishedContent>());
    }
}

altPages = altPages
    .DistinctBy(x => x.Id)
    .ToList();

if (altPages.HasAny())
{
    foreach (var altPage in altPages)
    {
        var culture = altPage.GetCultureFromDomains();
        string url = altPage.Url(culture: culture, mode: UrlMode.Absolute);

        var language = LocalizationService.GetLanguageByIsoCode(culture!);

        if (!string.IsNullOrEmpty(url) && url != "#" && !string.IsNullOrEmpty(culture))
        {
            @:<link rel="alternate" href="@url" hreflang="@culture" />

            if (language?.IsDefault == true)
            {
                @:<link rel="alternate" href="@url" hreflang="x-default" />
            }
        }
    }
}