Who can help me with changing default URL for specific doctype.
I have 3 doc types.
Container
Container Category
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
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
so in the above example this page is now also available on
/fish/swan/trout
You could then tap into the ContentService Save event to automatically populate this textbox with your shorter urls, to remove the middle container...
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>();
}
}
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>();
}
}
Change default document URL
Hi all,
Who can help me with changing default URL for specific doctype.
I have 3 doc types.
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
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
so in the above example this page is now also available on
/fish/swan/trout
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...
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
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:
register the IContentFinder
hope that helps!
regards
Marc
Hi Marc,
Thank you very much! Everything are working well!
Thanks, Mike
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.
After commenting URL provider registration you can see: http://prntscr.com/e6ncsr
Thanks, Mike
Seems duplication was fixed by adding this peace of code:
But I have another issue: http://prntscr.com/e6utti
http://prntscr.com/e6utxt
How I can include hostname to URL provider?
Thanks, Mike
is working on a reply...