Monday, April 28, 2014

Deep page links with an Umbraco widget structure

Last Friday I attended the Umbraco BE Festival organised by the Belgian Umbraco User Group with a few colleagues in Antwerp. Having such an event hosted next door is a real luxury so we couldn't resist joining the enthusiastic community.

During his outstanding 'Umbraco news, it's not only Belle' session Stephane Gay gave us some more insights into Umbraco 7 core, namely the url segment and url providers, the content finders.

EUREKA !

Interestingly enough the url provider was a perfect match for our current Umbraco project where we are creating a widget structure. For this setup we wanted to support deep page links so a backoffice user can create a link using a link picker to any content, being a page or child widget. A link to a widget should result into a page link with an anchor to this specific widget. Of course the view will automatically create an anchor element per widget while rendering the content.

So, while we were looking into a manual url resolving within the page controller, we now know about url providers and can utilize this feature to have our deep links propagated throughout the whole Umbraco system.

So we first define our widget url provider, inheriting from the DefaultUrlProvider this is easy.
1:    public class WidgetUrlProvider : DefaultUrlProvider  
2:    {  
3:      readonly IUrlProvider _provider = new DefaultUrlProvider();  
4:      public override string GetUrl(UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode)  
5:      {  
6:        var content = umbracoContext.ContentCache.GetById(id);  
7:        if (content.DocumentTypeAlias != ProjectSettings.WidgetAlias) return null;  
8:        var parentPage = content.Ancestors(ProjectSettings.PageAlias).First();  
9:        var widgetUrl = String.Format("{0}#{1}", parentPage.Url, content.Name);  
10:        return widgetUrl;  
11:      }  
12:    }  

We can now override the GetUrl method and insert our custom url builder logic. We want to activate this provider only to generate url's for out widgets, so we check if the current document type is a widget. Then we retrieve the parent page and get it's url so we can suffix the widget node name as an anchor.

All we have to do now is letting Umbraco know we have a url provider. We can hook into the Umbraco startup process by creating a class that inherits from ApplicationEventHandler so we can override the ApplicationStarting method. In this method we can add our custom url provider to the list.
1:    protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) 
2:    {  
3:      base.ApplicationStarting(umbracoApplication, applicationContext); 
4:      UrlProviderResolver.Current.InsertType<WidgetUrlProvider>();
5:    }  

The result is that every link to this widget is created our prefered way now, in the Umbraco Backoffice,


and if we create a page template to present our page


and call our Page1 we get the same link rendered in the browser if we create a link to a widget in a richtextbox for example


Now we have our custom url's activated in the backoffice as well as the template rendering.
Nice !!

Of course this sample is very simplified for sake of the demo. Our widget system is quiet more enhanced then this :-)