Copied to clipboard

Flag this post as spam?

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


  • Michael 125 posts 409 karma points
    Jan 18, 2017 @ 10:43
    Michael
    0

    Change default document URL

    Hi all,

    Who can help me with changing default URL for specific doctype.

    I have 3 doc types.

    1. Container
    2. Container Category
    3. Container Item

    My structure is following:

    and URL is: /Container/ContainerCategory/ContainerItem

    I would like to change this URL only ContainerItem doctype and URL for ContainerItem should be /Container/ContainerItem, but structure in Umbraco should be: /Container/ContainerCategory/ContainerItem

    How I can change default URL?

    Thanks, Mike

  • Marc Goodson 2155 posts 14406 karma points MVP 9x c-trib
    Jan 22, 2017 @ 12:46
    Marc Goodson
    101

    Hi Michael

    There are two options I think...

    Option 1

    There is a slightly hidden feature of Umbraco in that if you add a textbox to your document with alias umbracoUrlAlias, anything entered here will be used as an alternative Url for your content. eg

    enter image description here

    so in the above example this page is now also available on

    /fish/swan/trout

    enter image description here

    You could then tap into the ContentService Save event to automatically populate this textbox with your shorter urls, to remove the middle container...

    https://our.umbraco.org/documentation/reference/events/ContentService-Events

    this is the easiest option, but the url the editors see on the properties tab will still be the normal one, and content will still be found on the old longer url.

    Option 2 - Actually Changing the url in the backoffice

    So if you actually want to change the Url that is displayed in the backoffice you need to implement your own IUrlProvider rule, you do this by implementing an IUrlProvider and using the UrlProviderResolver to add your rule to the list of UrlProviders. The easiest way to do this is to extend the existing DefaultUrlProvider...

     public class SkipContainerClassUrlProvider : DefaultUrlProvider
        {
            public SkipContainerClassUrlProvider() : base(UmbracoConfig.For.UmbracoSettings().RequestHandler)
            { }
    // you write the rules to form the url, any string returned from here is the displayed url to the editors
            public override string GetUrl(UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode)
            {
                var content = umbracoContext.ContentCache.GetById(id);
                if (content != null)
                {
                    var parentalContent = content.Parent;
                    if (parentalContent != null && parentalContent.DocumentTypeAlias == "ContainerCategoryAlias")
                    {
                        // let's mangle the url you might need to tweak this for your requirements
                        var currentUrl = base.GetUrl(umbracoContext,id,current,mode);
                        var mangledUrl = currentUrl.Replace(parentalContent.UrlName + "/", "");
                        if (!String.IsNullOrEmpty(mangledUrl))
                        {
                            return mangledUrl;
                        }
                    }
                }
                return null;           
            }
        }
    

    we need to tell umbraco about our new Url Provider to do this we create a class that inherits ApplicationEventHandler and register in the pipeline like so

    public class RegisterEvents : ApplicationEventHandler
    {
        protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {
            UrlProviderResolver.Current.InsertTypeBefore<DefaultUrlProvider, SkipContainerClassUrlProvider>();
        }      
    }
    

    Now your urls in the backoffice will not contain the category container segment... !!!

    But in order for these Urls to actually return the content you will also need to implement a corresponding IContentFinder, and register that with the incoming pipeline, to find the relevant content based on your shortnened url:

    eg something like this:

         public class CategoryContainerLessContentFinder : IContentFinder
            {
                public bool TryFindContent(PublishedContentRequest contentRequest)
                {
                    var urlSegments = contentRequest.Uri.Segments;
                    // to short to be in this format
                    if (urlSegments.Length < 2)
                    {
                        return false;
                    }
    // get last part of url or your own logic depending on url structure
                    var containerItemSegment = urlSegments.Last();
    
                    var contentCache = UmbracoContext.Current.ContentCache;
    //xpath to find your page in the Umbraco Content Cache, probably something like this for your structure depending on the uniqueness of the containeritems...
                    var page = contentCache.GetSingleByXPath("//Container/ContainerCategory/ContainerItem[@urlName = '" + containerItemSegment  + "']");
                    if (page!= null)
                    {
                        contentRequest.PublishedContent = page;
                        return true;
                    }
                    return false;
                }
            }
    

    register the IContentFinder

     public class RegisterEvents : ApplicationEventHandler
        {
            protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
            {
                UrlProviderResolver.Current.InsertTypeBefore<DefaultUrlProvider, SkipContainerClassUrlProvider>();
                ContentFinderResolver.Current.InsertTypeBefore<ContentFinderByNiceUrl, CategoryContainerLessContentFinder>();
            }      
        }
    

    hope that helps!

    regards

    Marc

  • Michael 125 posts 409 karma points
    Jan 23, 2017 @ 08:58
    Michael
    1

    Hi Marc,

    Thank you very much! Everything are working well!

    Thanks, Mike

  • Michael 125 posts 409 karma points
    Feb 09, 2017 @ 18:50
    Michael
    0

    Hi Marc,

    Hope you are well! I've faced with slight annoying problem with this implementation.

    I have duplicate url's if I add additional domain to home node:

    http://prntscr.com/e6n90x

    and domains: http://prntscr.com/e6najn

    I've setup fresh Umbraco added Landing category and try to add use suggested code.

    public class AppCategoryContainerLessContentFinder : IContentFinder
        {
            public bool TryFindContent(PublishedContentRequest contentRequest)
            {
                var urlSegments = contentRequest.Uri.Segments;
                // to short to be in this format
                if (urlSegments.Length < 2)
                {
                    return false;
                }
                // get last part of url or your own logic depending on url structure
                var containerItemSegment = urlSegments.Last();
    
                var contentCache = UmbracoContext.Current.ContentCache;
                //xpath to find your page in the Umbraco Content Cache, probably something like this for your structure depending on the uniqueness of the containeritems...
    
                var page = contentCache.GetSingleByXPath("//Home/landingPageCategory/LandingPage[@urlName = '" + containerItemSegment + "']");
                if (page != null)
                {
                    contentRequest.PublishedContent = page;
                    return true;
                }
                return contentRequest.PublishedContent != null;
            }
        }
    
    
        public class SkipAppCategoryUrlProvider : DefaultUrlProvider
            {
                public SkipAppCategoryUrlProvider() : base(UmbracoConfig.For.UmbracoSettings().RequestHandler)
                { }
                // you write the rules to form the url, any string returned from here is the displayed url to the editors
                public override string GetUrl(UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode)
                {
                    var content = umbracoContext.ContentCache.GetById(id);
                    var parentalContent = content?.Parent;
                    if (parentalContent != null && parentalContent.DocumentTypeAlias == "landingPageCategory")
                    {
                        // let's mangle the url you might need to tweak this for your requirements
                        var currentUrl = base.GetUrl(umbracoContext, id, current, mode);
                        var mangledUrl = currentUrl.Replace(parentalContent.UrlName + "/", "");
                        if (!String.IsNullOrEmpty(mangledUrl))
                        {
                            return mangledUrl;
                        }
                    }
                    return null;
                }
            }
    
        public class Events : ApplicationEventHandler
            {
                protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
                {
                    UrlProviderResolver.Current.InsertTypeBefore<DefaultUrlProvider, SkipAppCategoryUrlProvider>();
                    ContentFinderResolver.Current.InsertTypeBefore<ContentFinderByNiceUrl, AppCategoryContainerLessContentFinder>();
                }
            }
    

    After commenting URL provider registration you can see: http://prntscr.com/e6ncsr

    Thanks, Mike

  • Michael 125 posts 409 karma points
    Feb 10, 2017 @ 07:55
    Michael
    0

    Seems duplication was fixed by adding this peace of code:

    public override IEnumerable<string> GetOtherUrls(UmbracoContext umbracoContext, int id, Uri current)
            {
                return Enumerable.Empty<string>();
            }
    

    But I have another issue: http://prntscr.com/e6utti

    http://prntscr.com/e6utxt

    1. No hostname for Home_DOMAIN
    2. Hostname for New_DOMAIN http://prntscr.com/e6uskg

    How I can include hostname to URL provider?

    Thanks, Mike

Please Sign in or register to post replies

Write your reply to:

Draft