New Community Website

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact [email protected].

Creating a Sitemap Provider For Your Module

In DotNetNuke Core 5.3 there was some work done around the Core search engine sitemap provider that was referred to as “The sitemap now allows module admins to plugin sitemap logic for individual modules” in the release notes. When I first heard about this in a Core Team meeting, it was explained that modules that have many pieces of content on a single page (Ex. Forum, Blog, Articles, etc.) can be picked up by the search engine sitemap provider. Having just finished my recent blog series on Taxonomy, which also focuses on multiple content items within a single module, I figured this was the next thing I should cover. If you haven’t read my blog series on Taxonomy some of the terms here may not make sense (so take a gander if you haven’t already although it may not be necessary to follow this). One thing worth mentioning before we get started, I know there are third party search engine sitemap providers out there but I am unsure of how this implementation will work with them.

Basic Flow

Before diving into code, lets first take a look at how this works. When someone (or something) calls your DotNetNuke sitemap page (http://www.domain.com/Sitemap.aspx) the request is intercepted by an HttpHandler (this is set in your web.config). This handler will then run its ProcessRequest method. This method will look to see if a sitemap.xml file exists, and if not, will call BuildSiteMap to create one. BuildSiteMap is part of the Core Library project and basically what it does is the following:

Loops through all Sitemap providers one by one to build a collection of URLs (providers are stored in web.config, visible in same sitemap module)

Creates the sitemap.xml file (which is stored in Portals/[PORTALID]/Sitemap/ folder)

Something worth mentioning here is that there is a 50,000 page limit per sitemap file (the forum on this site alone would go above that limit) and that multiple files will need to be created if you go above this limit. However, the core will handle this for you and create multiple files if necessary. With the basic flow covered, lets dive into what we need to create one for our own module.

Module Additions

To get started, you should create a new class for your module project. What you call this class and where you place it in your module is completely up to you but my example is a class named Sitemap and it is stored in MyModule\Components\Providers\Sitemap.cs. In my newly created Sitemap class the first thing I need to do is inherit from the SitemapProvider class of the core (located under the DotNetNuke.Services.Sitemap namespace). In doing so, this is going to inform me that I must override a function named GetUrls if I attempt to compile. Next, since we want to be able to compile, we need to override this GetUrls function which returns a collection of SitemapURL.

At this point, we have to decide what should be in our modules sitemap. In some modules, this is simple. For example, a blog module will need a URL entry in our sitemap for every published blog post. In something like a forum, you have more options and it may lead to some confusion. Should it be the list of forums or should it be the list of threads? While you are free to do whatever you feel is best for your situation, I suggest creating URLs for things you equate to Content Items (discussed in Taxonomy series). In the case of a forum, I would have a Content Item for every thread (thus allowing tags to be assigned per thread) and therefore I would want a sitemap URL for each thread. Once we understand what we want in our sitemap, we need to create logic that communicates with the data store to retrieve our collection of content items on a per portal basis because the sitemap is portal wide. Now, lets take a look at my GetUrls function:

In lines 17-18 I communicate with the data store to retrieve all items that are published per portal, which are all the items I will want listed in the site’s sitemap. In line 20 I use some Linq logic to loop through the collection of content items and for each item I call my own private method shown below, which in the end results in a SitemapUrl list usable for sitemap generation.

In line 4 I set the URL property of a new SitemapUrl object. What this URL is will vary from module to module, just keep in mind that you will likely need TabID, ModuleID and whatever your identifier is (in my example above, it is EntryID). If your module is associated with Content Items, you will have ModuleID and TabID available to you via the relation to the ContentItems table even if you didn’t store either in your modules table (therefore I recommend doing a join to that table when retrieving, just like my previous taxonomy examples). In line 7 we set the priority, which I left here at the default value of .5. What this value should be varies and I will leave it up to you to decide. In line 8 we set the last time the content item was updated and finally in line 9 we tell it what the change frequency is (again, I will leave this up to you to decide). That is all we need as far as code goes, the only thing left for us is to add an entry to our web.config so the module provider is available. Towards the bottom of our web.config file, where the coreSitemapProvider is located, we need to add a line to make our new provider visible. This will look something like this:

Once you have done the above (compiled your module and added the web.config entry) you can start testing to see your changes. Simple go to the Admin –> Search Engine SiteMap tab for a portal that contains your module populated with content (locally) and clear the cache for the sitemap module (you may need to completely clear the site cache). At this point, you should be able to see your new provider name located in the data grid within the module. Once you see your provider, you should click the Sitemap URL link (also located in the module) to validate your module is exposing its content to the sitemap. If you are not seeing anything, you should debug to verify your provider is getting called and locate the problem by stepping through it. You should also verify that the URLs that are displayed are taking you to valid locations (and where you intended them to take you). Once all that is working, your development is done.

NOTE: Although I don’t want to cover it in great detail here, you can use a “Config” component section in the dnn manifest file (version 5.0) to automate this during install. In doing so, please be very careful otherwise you can easily bring down any site that attempts to install the module and the only way to correct it will be direct web.config access (via RDP to web server or FTP to sites root directory).

Well, that is it. Hopefully you can start taking advantage of this somewhat recent change to the core.

Comments

Hooking into the sitemap provider is a breeze, thanks for the article. What I'm looking for is a way to extend the provider so I can create a video sitemap (https://support.google.com/webmasters/answer/80472?hl=en&ref_topic=10079#1). Can I add my own attributes to the provider so I can do something like that?

Note: For site map providers located in the application s App_Code folder, the value of the type attribute is simply the class name. Alternatively, the custom site map provider could have been created in a separate Class Library project with the compiled assembly placed in the web application s /Bin directory. In that case, the type attribute value would be Namespace.ClassName, AssemblyName.

The issue i'm facing now is with the multi-portal section. Sitemapprovider showing link to all portals where we have module configure or not. Like we have http://www.abcd.com/sitemap.aspx where we added sitemap. AS on same dnn instance we have another portal running like http://www.abcde.com/sitemap.aspx, both portal showing links of the siteprovider i added.

This post is a few years old, but really helped me understand what was going on here, and saved me a lot of time (I was tasked with creating a dynamic sitemap index for our 100K+ page site) - it was great to find out this feature is built into DNN.

My question, or issue, at this point though, is to wonder if there is any way to alter SitemapProviders default value of 50,000 entries per sitemap file generated. The length of urls in the generate map are rather large, and as such are producing rather large sitemap files. I would love to be able to half the page size if possible.

Does anyone know if it is possible to decrease the number of entries per page from 50,000 to something smaller? I am not seeing it in any docs I have came across as of yet. Thanks!