Provisioning Content Query Web Part querying subsites in a structured and repeatable way

Today, while working on a brand new SharePoint Web Content Management (WCM) solution, I’ve faced quite a challenge: I needed to provision a Content Query Web Part (CQWP) which would query subsites of the current site using a custom Site Definition. Each time user would create a site using that Site Definition, he would get on the home page an aggregation of the content from all underlying sites. It’s more challenging than it sounds and you won’t know it unless you had to do it yourself once.

The Content Query Web Part allows you to query content using one of the three scopes. You can query the content from the whole Site Collection, from a particular web and its children and from a particular list. Looking at my requirement, I had to use the second option.

By default the CQWP queries the whole Site Collection. Using some criteria this option is sufficient in many situations. I couldn’t use that option in my situation however because: a) it would perform too bad querying a couple of thousand pages; b) it would return more content than needed.

The second option seems to be just the right thing: by passing the URL of a web, you can make the Content Query Web Part query all the content within that particular web and all the underlying sites as well. The problem is that you need to pass the server relative URL of the site you are about to create.

Tokenizing the WebUrl property

After looking for a while on how to obtain the URL of the current site inside the ONET.XML file, I have found out that you are actually allowed to use the ~Site token to point to the current site. At some point (I’m not sure whether it’s the SharePoint site provisioning engine or the Content Query Web Part self) the token is being replaced with the site relative URL of the current site – just as the CQWP requires.

Provisioning the Custom Query Web Part using Features

Alternatively to the approach I chose you might want to use something else. First of all you might choose to create a Feature which would provision the web part upon activation. While this approach is definitely plausible and widely used, it doesn’t cope with my idea on structured and repeatable deployment. While you can reuse the functionality across many sites, provisioning web parts programmatically lacks overview to me. I just don’t like the idea of mixing configuration with custom code. To me XML provides more overview and context about the configuration of the particular page.

Provisioning Web Parts using Event Handlers

You could of course use the concept of Event Handler to provision the Web Part. Each time a Publishing Page is created, it would trigger your Event Handler. Using some custom logic you could determine whether to provision an instance of the particular Web Part or not. While this approach provides you with some extra control it shares the lack of overview with the approach I previously mentioned.

Summary

Provisioning Web Parts in a structured and repeatable way allows you to track the currently used configuration and improves the overall manageability of the SharePoint solution. By tokenizing the settings of the Content Query Web Part you can dynamically provision its instances which meet your requirements without mixing the configuration with custom code.

Humm – this doesn't work for me, which is a pity as it looked a very promising solution to a problem I'm having.

Of course the chances are that I'm doing something wrong, but if I understand you correctly this is a fairly simple concept.

I edited my .webpart as per your screenshot above to have '~Site' as the WebUrl, which when it's imported into my layout becomes
Other stuff here

The trouble is, in my output page, I get nothing. If I then replace WebUrl="/MYSUBSITE" then it works as expected (except my layout is then hard coded to a specific subsite, i.e. the problem I'm trying to get around.

@Paul: As I've mentioned I've used the token inside ONET.XML. That's where the web part is being provisioned. From what you're saying you've been trying to use the token within the CQWP deployed as a web control. I don't think it will work as the token is being replaced during the deployment and not on run-time.

@Mohamed: While you could base your provisioning process fully upon ONET.XML, it has some serious drawbacks.
First of all you would have to define in ONET.XML ALL the different Site Definitions. As working with ONET.XML isn't easy, it would take a lot of time to do it. Additionally you cannot really debug ONET.XML: it either works or doesn't. And if it breaks the ULS log is the only place where you can look for errors.
Then ONET.XML is not updateable: according to the SharePoint SDK modifying a Site Definition after instances of it have been provisioned is not supported.