CQWP & Audiencing – The Bug:
CQWP supports filtering data based on user's audience groups. E.g If you configure web part to fetch items from /mysite/pages list, it would apply audience rules and fetch you pages belonging to audience groups you are part of ( any one of it). This works in conjunction with other features of the web part
a) Query: User can select queries such as Title contains 'xyz'
b) Sort Order
c) Item Limit
However the order it applies is the cause of concern. As you would see in the image, audience rule gets set after ItemLimit rule is applied.
The impact is evident. An user can see anywhere between 0 to ItemLimit items based on his audience, though there could be lots of relevant items. Ideally the Audience rule should be set prior to Item Limit is applied.
We encountered this issue in our project and user experience was frustrating. Author configures a page to display Top 5 news items and actual news items displayed in CQWP varied anywhere between 0 to 5, though there were enough news items for all audience.
Solution:
Embarking on journey of workaround ( Sharepoint offers lot such opportunities) we considered following options
1) Can I influence this in the xslt? Answer is NO. The xslt gets called towards the end only for rendering purpose and this made sense
2) No other choice except to extend the web part to our needs. Below is the code snippet which helped to acheive this
public class AudienceContentByQueryWebPart: ContentByQueryWebPart
{
{
int userSelectedItemLimit ;
protected override void OnInit(EventArgs e)
{
this.ProcessDataDelegate += new ProcessData(ProcessData);
base.OnInit(e);
}
protected override void OnInit(EventArgs e)
{
this.ProcessDataDelegate += new ProcessData(ProcessData);
base.OnInit(e);
}
protected override void CreateChildControls()
{
//Store user selected ItemLimit and set it to -1. This is equivalent to user not setting any item limit
userSelectedItemLimit = this.ItemLimit;
this.ItemLimit = -1;
base.CreateChildControls();
}
{
//Store user selected ItemLimit and set it to -1. This is equivalent to user not setting any item limit
userSelectedItemLimit = this.ItemLimit;
this.ItemLimit = -1;
base.CreateChildControls();
}
// ProcessData is called after all rules are applied, including audience rule and before
// xslt is called.
private new DataTable ProcessData(DataTable dt)
{
// Reset the itemlimit to whatever user selected
this.ItemLimit = userSelectedItemLimit;
if (userSelectedItemLimit > 0)
{
//If number of rows greater than than the user given item limit
while (dt.Rows.Count > userSelectedItemLimit)
{
//Removing the rest of the rows
dt.Rows.RemoveAt(dt.Rows.Count - 1);
}
}
return dt;
}
}
private new DataTable ProcessData(DataTable dt)
{
// Reset the itemlimit to whatever user selected
this.ItemLimit = userSelectedItemLimit;
if (userSelectedItemLimit > 0)
{
//If number of rows greater than than the user given item limit
while (dt.Rows.Count > userSelectedItemLimit)
{
//Removing the rest of the rows
dt.Rows.RemoveAt(dt.Rows.Count - 1);
}
}
return dt;
}
}
Idea is to defer the ItemLimit rule after audiencing rule is applied. Steps were
1. Set ItemLimit = -1, forcing CQWP to avoid applying item limit. This ensures all results eligible for users, after applying audience rules are available.
2. CQWP allows you to hookup your event delegate called 'ProcessData' which gets called just before the xslt is applied. In ProcessData delegate, manually trim down the results to the user set ItemLimit.
Now all users would see the itemlimit number of items as long as enough data exists.
1. Set ItemLimit = -1, forcing CQWP to avoid applying item limit. This ensures all results eligible for users, after applying audience rules are available.
2. CQWP allows you to hookup your event delegate called 'ProcessData' which gets called just before the xslt is applied. In ProcessData delegate, manually trim down the results to the user set ItemLimit.
Now all users would see the itemlimit number of items as long as enough data exists.
Ideally I would expect the webpart to apply audience rules along with filter queries. This would ensure faster performance. Hopefully Microsoft addresses this in future releases.