A common complaint about styling the ContentByQueryWebPart is that the XslLink properties, used to reference custom XSL files that can be deployed via features (the best practice), don’t support site collection-relative links. This means that one would need to provide a separate .webpart file for each site collection that doesn’t live at the server root. Other common workarounds are to “get creative” with relative URLs or add the Web Part with code and assign a server-relative URL. Fortunately, it’s relatively easy to extend CQWP to adjust any server-relative URL to accommodate non-root site collections:
public class SiteSafeContentByQueryWebPart : ContentByQueryWebPart { protected override void OnLoad(EventArgs e) { MainXslLink = MakeServerRelativeUrl(MainXslLink); HeaderXslLink = MakeServerRelativeUrl(HeaderXslLink); ItemXslLink = MakeServerRelativeUrl(ItemXslLink); } private string MakeServerRelativeUrl(string url) { if (string.IsNullOrEmpty(url) || url[0] != '/') return url; var u = SPUtility.SiteRelativeUrlPrefix + url.TrimStart('/'); return SPUtility.GetServerRelativeUrlFromPrefixedUrl(u); } }
There are already several examples online of how to deploy and use an extended CQWP, so I won’t bother to repeat the process here. As long as the XslLink starts with “/”, it will be translated for the current site collection:
<properties> <property name="Title" type="string">SiteSafeContentByQueryWebPart</property> <property name="MainXslLink" type="string">/Style Library/CustomContentQueryMain.xsl</property> <property name="HeaderXslLink" type="string">/Style Library/CustomHeader.xsl</property> <property name="ItemXslLink" type="string">/Style Library/CustomItemStyle.xsl</property> </properties>
If there’s demand for a barebones SCSCQWP, I can post one, but I would rather see some of the more advanced versions just integrate this code.
December 14, 2008 at 7:05 pm
[…] Site Collection-Safe CQWP XSL Links […]
January 13, 2009 at 1:46 am
Hi Keith,
Thanks for the information – I gave it a try today but it doesn’t seem to be working for me and not having a development background I haven’t been able to figure out where I went wrong. Any chance you can make the basic web part available after all?
Thanks in anticipation,
Michael
December 3, 2009 at 11:24 am
Thank you Keith,
I get some issues with this when attempt to modify some properties from tool pane (es. Title) getting Exception about XSLT not found.
I found how avoid this with:
protected override void OnLoad(EventArgs e)
{
1. –> this.SaveProperties = true; if (string.IsNullOrEmpty(url) || url.StartsWith(SPContext.Current.Site.ServerRelativeUrl)) <– to avoid to continue prefixing path
Regards
June 16, 2010 at 7:21 pm
I was trying this in SharePoint 2010…
1. this.SaveProperties always throws a permission error even running with elevated permission.
2. if the 3 xslLink properties are assigned with a path which it can’t resolve or incorrect it throws an error “The web part references an untrusted XSL file. Only XSL files contained in this site’s Style Library may be referenced.”
Workaround:
1. Keep these three XSL link properties blank.
2. Expose three custom properties one for each XslLink in your webpart code
3. Assign value to these custom properties starting with “/Style Library/…”
4. Pass these values to MakeServerRelativeUrl in above code and assign it to respective orginal property
December 22, 2010 at 6:40 pm
Thanks for helpful post, glad not only me noticed this behaviour. Unfortunately, same thing happens with Summary Link webpart, but, this time, it’s sealed :( So I am not able to use this handy webpart in my publishing site definitions that can be instantiated on different managed paths URLs. Any other ideas to overcome this problem?
Regards,
Anna
December 23, 2010 at 9:57 am
Someone else may have an idea, but I can’t think of any easy way to get around the control being sealed. Maybe someday the SharePoint team will realize how much pain “sealed by default” causes the consumers of their APIs…
April 6, 2011 at 8:03 am
Thank you! Saved me alot of work!
It was a very well written post!
Regards,
Maria
October 28, 2011 at 2:21 am
In my case following string had become a solution:
~sitecollection/Style Library/XSL Style Sheets/CustomItemStyle.xsl
November 30, 2011 at 12:39 pm
Sabbah: It doesn’t work for me the path as you said.
Giving me error while adding web part to page.
January 5, 2012 at 6:05 pm
Check this out…
http://borderingdotnet.blogspot.com/2012/01/building-custom-contentquerywebpart.html
Yes, that’s right: no slash between ~sitecollection and Style Library.
January 5, 2012 at 6:13 pm
Posted too soon.
The technique in this post is to replace the ~sitecollection programmatically in the feature receiver
of the feature containing the webpart.
May 3, 2012 at 9:14 pm
Here is another option … may be a bit more slick than checking if the url starts with “/” …
var earl = Microsoft.SharePoint.Publishing.WebControls.SPUrlExpressionBuilder.EvaluateUrlExpression(url);
… this will fix the ~sitecollection/, ~site/, ~sitecollection/~lanugage/ sections of URL’s…
Get er done.