One of Sitefinity’s many features is its search capabilities. Using Lucene under the hood, Sitefinity indexes your site content, both built-in content types and dynamic content types, along with static HTML, and allows you to present organized results to the user. You can customized what is and isn’t indexed among other things. Most of the time, Sitefinity is smart enough to create search result URLs that take you directly to the content in question. If you have “/my-news” as your news page, for instance, a particular article URL might look something like “/my-news/2015/1/1/my-article-url”. The search indexer automatically takes the page where content is hosted into account, and creates the proper URL in its search results.
There are occasions where Sitefinity cannot figure out exactly where to take a user, however. Sometimes you may have a customized URL that doesn’t fit the default Sitefinity content URL scheme. And even though you can customize the URL scheme of content, if you have lots of existing content already, you’d have to go and re-publish every single one in order to re-apply the new scheme to them! Whatever the scenarios may be that require customization of search result URLs, there is a way to override the default behavior for URL construction, and supply your own URLs for built-in content and dynamic content. Doing so allows you to fully customize search result URLs without having to dig too deep in the search index implementation or having to write your own custom search indexing solution.
Creating a Custom Pipe
In order to customize search result URLs, you need to create a custom Pipe (based off existing ones so that 99% of the work is done for you) and override its “GetItemUrl” method. If you want to change the URL of a built-in content type, such as News, you’ll want to create a class derived from Telerik.Sitefinity.Publishing.Pipes.ContentInboundPipe. For dynamic content types, the class to derive from is Telerik.Sitefinity.DynamicModules.PublishingSystem.DynamicContentInboundPipe. I have done so in the code samples below.
public class CustomContentInboundPipe : Telerik.Sitefinity.Publishing.Pipes.ContentInboundPipe { protected override string GetItemUrl(IContent contentItem) { return base.GetItemUrl(contentItem); } } public class CustomDynamicContentInboundPipe : Telerik.Sitefinity.DynamicModules.PublishingSystem.DynamicContentInboundPipe { protected override string GetItemUrl(DynamicContent contentItem) { return base.GetItemUrl(contentItem); } }
In both cases, you see that a string is expected out of the GetItemUrl method. This is our entry point for customizing Sitefinity search result URLs. We are given the content item to reference if we need a specific property, and can use that to craft whatever URLs we please. The URLs can be relative, so you don’t have to worry about domain names: You can return “/foo/bar/my-article” and it will display correctly on your web site. In fact, let’s use that as our example for customization! For any news item, instead of the default, let’s make the URL on the search results page for news articles link to “/foo/bar/{news-item-url}.”
public class CustomContentInboundPipe : Telerik.Sitefinity.Publishing.Pipes.ContentInboundPipe { protected override string GetItemUrl(IContent contentItem) { if (contentItem.GetType() == typeof(NewsItem)) { return "/foo/bar" + contentItem.GetPropertyValue<Lstring>("UrlName"); } return base.GetItemUrl(contentItem); } }
Our method does a couple of things: First, it verifies that the content we’re dealing with currently is, in fact, a NewsItem. If it is not, we call the base method so that the default behavior is preserved. Note that many built-in content types will come through this method, which is why we have to make sure we’re working with a NewsItem before proceeding.
Once we’ve confirmed the type, we go ahead and return our desired custom URL. We access the item’s “UrlName” property and append that to our template of “/foo/bar/” and that’s it!
The dynamic content method is implemented similarly: Verify you’re working with the right type, then return a custom URL based on your template. Otherwise, preserve the default behavior.
public class CustomDynamicContentInboundPipe : Telerik.Sitefinity.DynamicModules.PublishingSystem.DynamicContentInboundPipe { protected override string GetItemUrl(DynamicContent contentItem) { Type customContentType = Telerik.Sitefinity.Utilities.TypeConverters.TypeResolutionService .ResolveType("Telerik.Sitefinity.DynamicTypes.Model.CustomModuleName.CustomContentTypeName"); if (contentItem.GetType() == customContentType) { return "/dynamic/custom/url/" + contentItem.UrlName; } return base.GetItemUrl(contentItem); } }
The only differences here are that UrlName is a strongly-typed property on DynamicContent (no need for GetPropertyValue), and we have to resolve our dynamic type using the TypeResolutionService, since dynamic types do not have strongly-typed classes associated with them.
Registering the Custom Pipes
Now that we have our customized classes, we have to register them with Sitefinity. Otherwise, the search indexer won’t know to call them when it is reindexing your site! To do so, we’ll be adding a couple lines of code to the “Bootstrapped” event that fires on startup. We’ll hook into this event in the Global class (Global.asax.cs). In addition, we have to unregister the default pipe before registering our custom one. All of this is demonstrated below:
public class Global : HttpApplication { protected void Application_Start(object sender, EventArgs e) { Bootstrapper.Initialized += OnBootstrapperInitialized; } private static void OnBootstrapperInitialized(object sender, ExecutedEventArgs e) { if (e.CommandName == "Bootstrapped") { PublishingSystemFactory.UnregisterPipe(ContentInboundPipe.PipeName); PublishingSystemFactory.RegisterPipe(ContentInboundPipe.PipeName, typeof(CustomContentInboundPipe)); string customContentTypePipeName = "Telerik.Sitefinity.DynamicTypes.Model.CustomModuleName.CustomContentTypeNamePipe"; PublishingSystemFactory.UnregisterPipe(customContentTypePipeName); PublishingSystemFactory.RegisterPipe(customContentTypePipeName, typeof(CustomDynamicContentInboundPipe)); } } }
Here we unregister the pipes for ContentInboundPipe (built-in content) and for our particular dynamic content type (which is simply the full content type name with the word “Pipe” at the end). Then we register new pipes, using the same names, but point to our custom classes instead. Because we inherited from the normal classes, these registrations are valid.
Applying the Changes to the Search Results
Once these are in place, restart your Sitefinity application and go to the backend, navigating to the Search Indexes management page (under Administration). Re-index your Sitefinity search index to have Sitefinity invoke your custom classes and overridden methods. If you debug and put breakpoints in your methods, you’ll see them hit once for every piece of content under the given type. After the re-index is complete, perform a search, and you’ll find that your custom search result URLs are in place in your search results!
The post Customizing Search Result URLs in Sitefinity appeared first on Falafel Software Blog.