Site Collection-Safe CQWP XSL Links

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.

Advertisement

12 Responses to “Site Collection-Safe CQWP XSL Links”

  1. Michael Says:

    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

  2. Alberto Says:

    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

    • Sachin Dekate Says:

      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

  3. Anna Wojcik Says:

    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

    • Keith Dahlby Says:

      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…

  4. Maria Says:

    Thank you! Saved me alot of work!

    It was a very well written post!
    Regards,
    Maria

  5. Sabbah Says:

    In my case following string had become a solution:
    ~sitecollection/Style Library/XSL Style Sheets/CustomItemStyle.xsl

    • krishna Says:

      Sabbah: It doesn’t work for me the path as you said.

      Giving me error while adding web part to page.

  6. Sangeet Ahuja Says:

    Check this out…
    http://borderingdotnet.blogspot.com/2012/01/building-custom-contentquerywebpart.html

    Yes, that’s right: no slash between ~sitecollection and Style Library.

    • Sangeet Ahuja Says:

      Posted too soon.
      The technique in this post is to replace the ~sitecollection programmatically in the feature receiver
      of the feature containing the webpart.

  7. Matt Stark Says:

    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.


Comments are closed.

%d bloggers like this: