The Content Query Web Part (CQWP) is an absolutely killer for MOSS 2007 Publishing sites. It is one of the best performing rollup Web Parts available to developers and should always be considered before rolling your own solution. You can even do some really sick customization to the presentation of the results produced by the CQWP as shown in this post on the ECM team blog by George Parantatos, a PM on the product team:
However there are two things I always hear about the CQWP in terms of wish list type stuff:
- It doesn’t contain any built-in paging mechanism… yeah, I too wish for this.
- It doesn’t support dynamic filtering. For instance, I have to manually specify the filtering values rather than have them be dynamically set.
Before you rush off and roll your own, stop, get a cup of coffee, and saddle up next to your laptop. With just a few lines of code you can utilize the provided CQWP but add your own customizations. Take the second pain point: no dynamic filtering. Let’s say you have a slew of content and you want to dynamically set the filtering values, say for example, using values on the query string.
So, we start with a site filled with pages. In the below screen shot, you’ll see a subsite called Widgets that contains 10 pages. Each of these pages contains some bogus content, but there is a field called Division that has one of a few different values in it.
When I add the OOTB CQWP to the page, the default view gives me all pages in the site:
I could tweak the filtering values in the Task Pane by setting the Division field to Europe. But… what if I want to make this dynamic?
OK, time to whip open Visual Studio. What I’ll do is create a new Web Part that inherits directly from the CQWP: Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart
(MSDN link). Let’s take a look at the properties available to us. Hey, I see two that are good candidates: FilterField1
& FilterValue1
. No guessing involved, the names say exactly what they do. So, what if I set the values of those properties on the fly, but let the rest of the CQWP do its work? Ah… now it’s party time!
What I’ll do is override the OnLoad()
method and do a quick check to see if there is something expected on the query string… if not, then I need to just stop here… nothing to do. But, if there IS something there… ah… now that’s where I want to add my special sauce. Here’s the code, followed by an explanation.
protected override void OnLoad (EventArgs e) {
// if a value was specified on the query string...
if (string.IsNullOrEmpty(this.Page.Request.QueryString["Filter1Field"]))
return;
// set the chaining of filter values to OR'd
this.Filter1ChainingOperator = FilterChainingOperator.Or;
// get the filtering field by name
string filterFieldName = this.Page.Request.QueryString["Filter1Field"].ToString();
// since the field name isn't suffucient for the CQWP, get the field's GUID
Guid filterFieldID = Microsoft.SharePoint.SPContext.Current.Item.Fields[filterFieldName].Id;
// get the filtering field value
string filterFieldValue = this.Page.Request.QueryString["Filter1Value"].ToString();
// set the filtering info
this.FilterField1 = filterFieldID.ToString();
this.FilterValue1 = filterFieldValue;
}
First, I need to set the chaining operator. That is the AND/OR switch you set when you are setting filter values using the Task Pane for the CQWP. In this case, I just want to set the Filter1ChainingOperator
to OR the two values (line #15). Next, I need to get the name of the field & value to filter by from the query string (lines #18 & 22). Before going further, we need to deal with a little curve ball the CQWP throws at us. When it filters on a specific field, it does so not using the field by name, but by the field’s ID. So we need to get the field’s GUID which we can do by looking at the current lists’s Fields property (or, more specifically, we can look at any item in the list as I do in the code above) (line #20). Last but not least, set the values on the CQWP’s fields (lines # 25 & 26).
Now… package everything up and deploy it just like any other Web Part. All that’s left is to add it to a page. Initially it does the exact same thing as the stock CQWP because no query string filter values are set. But when you add them manually (or through some link on your site), you’ll see it does the filtering as shown in the following image! You can even see the values are set when you look at the query builder in the Task Pane.
And there you have it… a subclassed CQWP implementing dynamic filtering in less than 30 lines of code. Hey, if you look at the guts of the solution, the whole thing is really only 8 lines of code in the OnLoad()
method! Now that’s easy!