Sitecore: Custom Friendly URLs

Sitecore: Custom Friendly URLs

Very often every Sitecore developer has faced with the following situations:

  • there is a shared content between multiple sites.
  • there is a content tree that shouldn’t be exposed outside

In such a case would be great to have ability to manage url that is returned by LinkManager.GetItemUrl(). In order to accomplish this there is a need to implement a custom LinkProvider and configure Sitecore to use it.

A Simple LinkProvider Implementation

Let’s imagine that there is a site with blog posts and we’ve decided to embed the date of the post into the url by creating custom links rather than restructuring our content tree.

The easiest way to handle it is to create a custom class, inherit it from Sitecore.Links.LinkProvider and override the GetItemUrl() method:

using Sitecore;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Links;

namespace AndreyVinda.FriendlyUrl.Links
{
    public class FriendlyUrlLinkProvider : LinkProvider
    {
        public override string GetItemUrl(Item item, UrlOptions options)
        {
            if (item.TemplateName == "Blog Post")
            {
                DateField dateField = item.Fields["Blog Post Date"];
                var title = item["Blog Post Title"];
                return MainUtil.EncodePath($"/{dateField.DateTime:yyyy-MM-dd}-{title}", '/');
            }

            return base.GetItemUrl(item, options);
        }
    }
}

Configuring Sitecore

Now we should say Sitecore to use our custom implementation of LinkProvider. It could be done by patching linkManager section.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set">
  <sitecore>
    		<linkManager set:defaultProvider="customFriendlyUrl">
      <providers>
        <add name="customFriendlyUrl" type="AndreyVinda.FriendlyUrl.Links.FriendlyUrlLinkProvider, AndreyVinda.FriendlyUrl"/>
      </providers>
    </linkManager>
  </sitecore>
</configuration>

Testing

In order to test our LinkProvider we implement a small rendering that passes in UrlOptions:

<ul>
 @foreach (var post in sortedPosts)
 {
 var date = ((DateField)post.Fields["Blog Post Date"]).DateTime;
 var title = post["Blog Post Title"];
	<li>
 <a href="@LinkManager.GetItemUrl(post, new UrlOptions() { AlwaysIncludeServerUrl = true })">@date.ToShortDateString() -- @title</a></li>
}</ul>

(Note: While we probably wouldn’t render absolute urls for a blog post listing we would want them in sitemaps, and for SEO metadata such as canonical urls, OpenGraph tags, and microdata)

Then we view the output from our rendering:

<ul>
	<li>
      <a href="/2017-10-13-Sample">10/13/2017 -- Sample Post</a></li>
	<li>
      <a href="/2017-09-02-BeerFest">9/2/2017 -- Beer Fest</a></li>
	<li>
      <a href="/2017-08-01-MarketPlace">8/1/2017 -- Market Place</a></li>
</ul>

Fixing custom LinkProvider

Our custom url works but the UrlOptions are being ignored. To correct this we need to subclass LinkProvider.LinkBuilder and override its GetItemPathElement() method:

using Sitecore;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Links;
using Sitecore.Web;

namespace AndreyVinda.FriendlyUrl.Links
{
    public class FriendlyUrlLinkProvider : LinkProvider
    {
        protected override LinkBuilder CreateLinkBuilder(UrlOptions options)
        {
            return new FriendlyUrlLinkBuilder(options);
        }
    }

    public class FriendlyUrlLinkBuilder : LinkProvider.LinkBuilder
    {
        public FriendlyUrlLinkBuilder(UrlOptions options) : base(options)
        {
        }

        protected override string GetItemPathElement(Item item, SiteInfo site)
        {
            if (item.TemplateName == "Blog Post")
            {
                DateField dateField = item.Fields["Blog Post Date"];
                var title = item["Blog Post Title"];
                return MainUtil.EncodePath($"/{dateField.DateTime:yyyy-MM-dd}-{title}", '/');
            }

            return base.GetItemPathElement(item, site);
        }
    }
}

Using the LinkBuilder our rendering will now produce the expected results:

<ul>
<ul>
	<li> <a href="http://avinda.local/2017-10-13-Sample">10/13/2017 -- Sample Post</a></li>
	<li> <a href="http://avinda.local/2017-09-02-BeerFest">9/2/2017 -- Beer Fest</a></li>
	<li> <a href="http://avinda.local/2017-08-01-MarketPlace">8/1/2017 -- Market Place</a></li>
</ul>

Enjoy!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s