Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Stuart Paterson 57 posts 228 karma points
    Nov 21, 2019 @ 08:52
    Stuart Paterson
    0

    Query children of multiple root nodes and return values for hreflang tags

    I have four root nodes for various cultures and host names attached.

    I'm looking to check if the current page exists as a child item in either of those nodes and if so display links, specifically an hreflang tag. (not all child pages exist on every node)

    What I've tried so far is creating foreach loops to loop through and it's child items, however so far it only returns me the children for level 1.

    IPublishedContent homeOne = Umbraco.TypedContent(1172); IPublishedContent homeTwo = Umbraco.TypedContent(6093); IPublishedContent homeThree = Umbraco.TypedContent(7886); IPublishedContent homeFour = Umbraco.TypedContent(9679);

    var pageUrl = CurrentPage.Url().ToString();

    foreach (var item in homeOne.Children) { var pagePath = item.Url.ToString();

    if (pagePath == pageUrl)
    {
        <link rel="alternate" href="@string.Format("https://www.domain.xx{0}", pagePath)" hreflang="x-default" />
        <link rel="alternate" href="@string.Format("https://www.domain.xx{0}", pagePath)" hreflang="en-gb" />
    }
    

    }

    I then have three similar foreach loops beneath this for the other home nodes, interestingly/annoyingly...if I'm on a child page of homeOne, I only see the links generated for homeOne, however if I go to a child page of homeTwo I see the links generated for homeOne and homeTwo. Subsequently visiting homeThree returns links for homeOne and homeThree only.

    Hope someone can point me in the right direction

    Thanks

  • Muhammad Umar 11 posts 121 karma points
    Nov 21, 2019 @ 16:52
    Muhammad Umar
    100

    I had implemented the code below to achieve exactly what you are trying to achieve. The code below will add hreflang tag where it finds a child page in other root nodes with same URL to the current page.

    You will need to update the values in rootNodeObjects variable according to your site.

    Hope this helps!

    <!--Here add your all the site names as key and nodeid of the sites-->    
        var rootNodeObjects = new
        {
            items = new[] {
                new {key = "GB" , nodeId = 0},
                new {key = "IE" , nodeId = 0},
                new {key = "NI" , nodeId = 0},
                new {key = "CA" , nodeId = 0}
            }
        };
    
        int currentRootNodeId = Model.Content.Site().Id;
        var currentUrl = Model.Content.UrlAbsolute();
        var currentUrlSlug = Model.Content.Url.Replace(Model.Content.Site().Url, "");
        var umbracoHelper = new UmbracoHelper(Umbraco.UmbracoContext);
    
        int matchesFound = 0;
    
    
        foreach (var item in rootNodeObjects.items.Where(x => x.nodeId != currentRootNodeId))
        {
            foreach (var content in umbracoHelper.TypedContentAtRoot().Where(x => x.Id == item.nodeId).First().DescendantsOrSelf())
            {
                var contentUrlSlug = content.Url.Replace(content.Site().Url, "");
                if (contentUrlSlug.Equals(currentUrlSlug))
                {
                    matchesFound++;
                    <link rel="alternate" hreflang="[email protected]" href="@content.UrlAbsolute()" />
                }
            }
        }
    
        if (matchesFound > 0)
        {
            <link rel="alternate" hreflang="[email protected](x => x.nodeId == currentRootNodeId).First().key" href="@Model.Content.UrlAbsolute()" />
        }
    
  • Stuart Paterson 57 posts 228 karma points
    Nov 27, 2019 @ 08:40
    Stuart Paterson
    0

    Muhammad the code above really helped me out big time, thanks again I've exactly what I was looking for now.

    For anyone who comes across this post I just had to add a couple of things which are probably just down to differences in my Umbraco instance.

    Initially I wasn't returning any matches on the child items because the currentUrl and contentUrl were different so had to trim the values to remove forward slashes, after that I was seeing results returned.

    Secondly, on my across my four root nodes, three of these have 3 other domains/host names attached to them and I the code as above was only generating the links for 1 domain on each root node. So I used the DomainService below to generate the links for each domain.

                var domainService = ApplicationContext.Current.Services.DomainService;
            var domains = domainService.GetAll(true).ToList();
    

    This was duplicating the links three times (for each root nodeId) so I just put an if statement in to only generate a link of the rootnodeId matched the item.nodeId in the initial foreach loop.

            var domainService = ApplicationContext.Current.Services.DomainService;
            var domains = domainService.GetAll(true).ToList();
    
            if (contentUrlSlug.Equals(currentUrlSlug))
            {
                matchesFound++;
    
                foreach (var host in domains)
                {
                    var getHost = host.DomainName.ToString();
    
                    var hostName = string.Format("http://" + getHost + "/" + contentUrlSlug);
                    if (host.RootContentId == item.nodeId)
                    {
                        if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".ae"))
                        {
    
  • Muhammad Umar 11 posts 121 karma points
    Nov 27, 2019 @ 11:07
    Muhammad Umar
    0

    Glad to help Stuart,

    Great to hear that you got it working according to you Umbraco instance and that the code helped you big time.

    Looking forward to the final version of your updated implementation. For anyone coming across this post in future will have two implementation to help them start.

  • Stuart Paterson 57 posts 228 karma points
    Nov 22, 2019 @ 09:11
    Stuart Paterson
    0

    Muhammad, can't thank you enough for taking the time to post this up!

    Did you also have this working for the child items so it was generating the tags for the lvl 2, 3 child pages?

    Two of my root nodes have 3 different countries attached for example the Far East node has HK, SG and MY attached so I'll look at making some tweaks but if I get it working I'll post the update here just in case anybody else comes across this post.

  • Muhammad Umar 11 posts 121 karma points
    Nov 22, 2019 @ 09:28
    Muhammad Umar
    0

    Yes, it works for level 2 and 3 and this is achieved by getting Descendants of the root node instead of Children. Getting descendants will return all children of root node no matter which level they are at.

  • Stuart Paterson 57 posts 228 karma points
    Nov 22, 2019 @ 14:35
    Stuart Paterson
    0

    Getting closer Muhammad but returning some strange results.

    Can I also check I'm using this as I should be...all I I've done to your code snippet is change the key and nodeId values, everything else is as per snippet.

    I've put the code in a partial and I'm rendering this partial on the Master template of my site in the head tag.

    Results -

    • Browsing the first root node in my tree (.co.uk) returns the four links as it should.
    • Browsing the second root node (.ae) in my tree only returns the link for this node twice
    • If I try and browse a child item of the .co.uk root node it doesn't generate any links, however if I do the same for the second root node again it returns two links for the child node of the root being viewed.

    My tree structure with 'cultures and host names' in brackets-

    • HomeUK (base Url domain.co.uk)
      • Courses
        • area1
        • area2
    • HomeME (domain.ae domain.qa domain.com.kw)
      • Courses
        • area1
    • HomeFE (domain.sg domain.hk domain.my)
      • Courses
        • area1
        • area2
    • HomeIE (domain.ie)
      • Courses
        • area1

    Thanks again Stuart

  • Muhammad Umar 11 posts 121 karma points
    Nov 22, 2019 @ 15:22
    Muhammad Umar
    0

    Can you post the updated version of code so i can see whats going on.

    The implementation will not print out any hreflang tag if it does not find any match in other sites. Check the URL of the nodes for each site and see if they are same, ignoring the domain in URL.

  • Stuart Paterson 57 posts 228 karma points
    Nov 22, 2019 @ 15:42
    Stuart Paterson
    0

    The Url's are the same, the only difference is the domains attached to each root node in the cultures & hostnames

    UK just uses the base URL in the web.config and so page links show as relative URL's

    The other three root nodes have three ccTLD's each attached to them and as such their links in Umbraco are displayed as absolute URL's

  • Stuart Paterson 57 posts 228 karma points
    Nov 22, 2019 @ 15:35
    Stuart Paterson
    0

    Current code -

    @{
    
    var rootNodeObjects = new
    {
        items = new[] {
            new {key = "GB" , nodeId = 1172},
            new {key = "GB" , nodeId = 6093},
            new {key = "GB" , nodeId = 7886},
            new {key = "GB" , nodeId = 9679}
        }
    };
    
    int currentRootNodeId = Model.Content.Site().Id;
    var currentUrl = Model.Content.UrlAbsolute();
    var currentUrlSlug = Model.Content.Url.Replace(Model.Content.Site().Url, "");
    var umbracoHelper = new UmbracoHelper(Umbraco.UmbracoContext);
    
    int matchesFound = 0;
    
    
    foreach (var item in rootNodeObjects.items.Where(x => x.nodeId != currentRootNodeId))
    {
        foreach (var content in umbracoHelper.TypedContentAtRoot().Where(x => x.Id == item.nodeId).First().DescendantsOrSelf())
        {
            var contentUrlSlug = content.Url.Replace(content.Site().Url, "");
            if (contentUrlSlug.Equals(currentUrlSlug))
            {
                matchesFound++;
                <link rel="alternate" hreflang="[email protected]" href="@content.UrlAbsolute()" />
            }
        }
    }
    
    
    if (matchesFound > 0)
    {
        <link rel="alternate" hreflang="[email protected](x => x.nodeId == currentRootNodeId).First().key" href="@Model.Content.UrlAbsolute()" />
    }
    

    }

  • Muhammad Umar 11 posts 121 karma points
    Nov 22, 2019 @ 15:57
    Muhammad Umar
    0

    I don't think setting up different domains in cultures and hostnames would cause any issues.

    What i would suggest is to run the project in debug mode in Visual Studio and add a breakpoint on this line of code:

    if (contentUrlSlug.Equals(currentUrlSlug))
    

    Check the value in contentUrlSlug and currentUrlSlug variables and see if the URL value being output is correct.

    Hope this helps!

  • Stuart Paterson 57 posts 228 karma points
    Nov 22, 2019 @ 15:58
    Stuart Paterson
    0

    ok thanks Muhammad, I'll fire through it and post back if that's ok if I find anything

  • Stuart Paterson 57 posts 228 karma points
    Nov 26, 2019 @ 09:29
    Stuart Paterson
    0

    Muhammad, just to drop you a note on this and say it's 90% working which is greats so thanks again.

    It's generating links for the child items of each root node, at the moment it's only generating links for one of the domains within the cultures & hostnames. My other root nodes have 3 domains attached to each so links need to be generated for all of those and not just one domain per root node.

    Working on this just now though so I'll post up the tweaks I've made for our environment once it produces all links for all host names.

  • Stuart Paterson 57 posts 228 karma points
    Nov 27, 2019 @ 11:51
    Stuart Paterson
    0

    Final solution used -

    This includes generating canonical link and also a small additional tweak for matches on the root node being visited for cultures and host names. (formatting looks a bit strange on here, apologies)

    @inherits Umbraco.Web.Mvc.UmbracoTemplatePage<IPublishedContent>
    

    @using System.Text.RegularExpressions @using SimplestStore.Controllers @using SimplestStore.Models @using Umbraco.Core.Models @using ICSLearnV7.pocos @using ICSLearnV7.Controllers @using ClientDependency.Core @using ClientDependency.Core.Mvc @using Newtonsoft.Json; @using ICSLearnV7.Helpers;

    @{ IPublishedContent currentPage = UmbracoContext.PublishedContentRequest.PublishedContent;

    var domainService = ApplicationContext.Current.Services.DomainService;
    var domains = domainService.GetAll(true).ToList();
    
    var rootNodeObjects = new
    {
        items = new[] {
    

    new {key = "GB" , nodeId = 1172}, new {key = "AE" , nodeId = 6093}, new {key = "HK" , nodeId = 7886}, new {key = "IE" , nodeId = 9679} } };

    int currentRootNodeId = Model.Content.Site().Id;
    var pageUrl = currentPage.Url.ToString();
    var currentUrl = pageUrl.Trim("/");
    var slugUrl = Model.Content.Url.ToString();
    var currentUrlSlug = slugUrl.Trim("/");
    var umbracoHelper = new UmbracoHelper(Umbraco.UmbracoContext);
    
    
    int matchesFound = 0;
    
    
    foreach (var item in rootNodeObjects.items.Where(x => x.nodeId != currentRootNodeId))
    {
        foreach (var content in umbracoHelper.TypedContentAtRoot().Where(x => x.Id == item.nodeId).First().DescendantsOrSelf())
        {
            var contentTrimUrl = content.Url.Replace(content.Site().Url, "");
    
            var contentUrlSlug = contentTrimUrl.Trim("/");
    
            if (contentUrlSlug.Equals(currentUrlSlug))
            {
                matchesFound++;
    
                //where matches exist and in other root nodes and generating links where domains exist in cultures and
                //host names
    
                foreach (var host in domains)
                {
                    var getHost = host.DomainName.ToString();
    
                    var hostName = string.Format("https://" + getHost + "/" + contentUrlSlug);
    
                    if (host.RootContentId == item.nodeId)
    
                    {
                        if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".ae"))
                        {
                            <link rel="alternate" hreflang="en-ae" href="@string.Format("{0}", hostName)" />
                        }
                        if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".qa"))
                        {
                            <link rel="alternate" hreflang="en-qa" href="@string.Format("{0}", hostName)" />
                        }
                        if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".kw"))
                        {
                            <link rel="alternate" hreflang="en-kw" href="@string.Format("{0}", hostName)" />
                        }
                        if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".sg"))
                        {
                            <link rel="alternate" hreflang="en-sg" href="@string.Format("{0}", hostName)" />
                        }
                        if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".my"))
                        {
                            <link rel="alternate" hreflang="en-my" href="@string.Format("{0}", hostName)" />
                        }
                        if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".hk"))
                        {
                            <link rel="alternate" hreflang="en-hk" href="@string.Format("{0}", hostName)" />
                        }
                        if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".ie"))
                        {
                            <link rel="alternate" hreflang="en-ie" href="@string.Format("{0}", hostName)" />
                        }
                        if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".uk"))
                        {
                            <link rel="alternate" hreflang="en-gb" href="@string.Format("{0}", hostName)" />
                        }
                    }
                }
            }
        }
    }
    
    if (matchesFound > 0)
    {
        //where root node is the node being visited and for domains which are applied in cultures & host names
        foreach (var host in domains)
        {
            var getHost = host.DomainName.ToString();
    
            var hostName = string.Format("https://" + getHost + "/" + currentUrlSlug);
    
            if (host.RootContentId == currentRootNodeId)
    
            {
    
                if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".ae"))
                {
                <link rel="alternate" hreflang="en-ae" href="@string.Format("{0}", hostName)" />
                }
                if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".qa"))
                {
                <link rel="alternate" hreflang="en-qa" href="@string.Format("{0}", hostName)" />
                }
                if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".kw"))
                {
                <link rel="alternate" hreflang="en-kw" href="@string.Format("{0}", hostName)" />
                }
                if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".sg"))
                {
                <link rel="alternate" hreflang="en-sg" href="@string.Format("{0}", hostName)" />
                }
                if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".my"))
                {
                <link rel="alternate" hreflang="en-my" href="@string.Format("{0}", hostName)" />
                }
                if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".hk"))
                {
                <link rel="alternate" hreflang="en-hk" href="@string.Format("{0}", hostName)" />
                }
                if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".ie"))
                {
                <link rel="alternate" hreflang="en-ie" href="@string.Format("{0}", hostName)" />
                }
                if (host.DomainName.ToString().Contains("www") && host.DomainName.ToString().Contains(".uk"))
                {
                <link rel="alternate" hreflang="en-gb" href="@string.Format("{0}", hostName)" />
                }
            }
        }
    
        //generate rel canonical link
        <link rel="canonical" href="@Model.Content.UrlAbsolute()" />
    }
    else 
    {
        //generate canonical link on page if no matches are found
        <link rel="canonical" href="@Model.Content.UrlAbsolute()" />
    }
    // general x-default hreflag tag...I've just hardcoded my default domain for now
    <link rel="alternate" href="@string.Format("https://www.yourdomain" + "{0}", slugUrl)" hreflang="x-default" />
    

    }

Please Sign in or register to post replies

Write your reply to:

Draft