Using Friendly Urls in Custom Features

When you implement supporting pages in your custom feature, you may wish to use friendly urls for detail pages to improve SEO (Search Engine Optimization) of the content in your custom feature. You can do this the same as it is done in existing features such as the Blog which uses friendly urls for blog post detail, WebStore which uses friendly urls for product detail and offer detail pages, and Event Calendar Pro which uses friendly urls for event detail pages. In fact, I recommend you study the /Blog/EditPost.aspx.cs and WebStore/AdminProductEdit.aspx.cs to see examples where friendly urls are created.

So a typical scenario is that you have the ModuleControl.ascx part of the feature which is the part that plugs into a CMS page (ie a page in the menu). It serves as the entry point to your feature, and you may have a list of items displayed in the ModuleControl that need to link to supporting page(s). Suppose for example it is a list of products and you want to link to a product detail page which would be a physical .aspx implemented by you and ideally inheriting from mojoBasePage.

So the url for yuor detail page might be /featurefolder/Detail.aspx?pageid=x&mid=y&yourcustomid=z

You need to pass the pageid and module id from your ModuleControl to keep the security context of the current cms page, to keep the menu highlighted correctly, and to be able to easily make a link to get back to the cms page from your detail page. In addition you would pass your custom id for whatever item you are showing details for.

Now obviously this url with lots of query string parameters is not the prettiest url and not as SEO friendly as we would like. So what you do is create a friendly url record in the database that maps a friendlier url to this real url that has all the parameters. Our FriendlyUrl class provides what you need to do this as you will see when you study the code linked above. Once the friendly url is created in the database our built in url re-writer will detect url requests for your friendly url and it will re-write them to the real url that is stored with the friendly url record. The user will see only the friendly url in the browser navigation bar, but your page will execute using the real url with the parameters.

You need to of course store the SiteId also on the FriendlyUrl, and you should set the PageGuid on the Friendly url to a guid associated with your item. So on your item table you need a field with a unique guid for each item row, and you also need to store the relative friendly url on your item record. This is needed so you can build links to your detail pages from the ModuleControl using the friendly urls. If your item table is not using a guid (aka uniqueidentifier) as the primary key, you can still add a uniqueidentifier column and use the sql newid() function for the default value, or you can pass in a .NET guid when creating the data.

If you delete one of your items you should also delete the friendlyurl passing in the guid of the item you are about to delete.

Structure of a Friendly Url

This is very important. We DO NOT support additional segments in the url.

I recommend you do not create urls with extra / segments in them like:


Instead, if you really need to pack those extra key words into the url do it like this:


It will have the same SEO value and you can be sure our url re-writer will handle it correctly. Part of the reason for this is that our url re-writer has to handle a lot of different scenarios including sites running as a root site, sites running in a virtual directory beneath the root, sites running as folder child sites in a multi site installation. It was difficult getting all that working correctly and would probably not be possible if we let there be arbitrary extra segments in the urls. Also, as I've mentioned in this article, in a content management system it does not make sense to reflect a pages position in a site hierarchy in the url for the simple reason that urls should not change, but in a CMS we should have complete freedom to move pages around in the hierarchy, we are not limited the way sites with static html files are.