Customizing Content Query Web Parts


Content Query Web Parts
I have to say the game has changed with content query web parts. When trying to work with them in SharePoint 2007 you ended up having to do a ton of work just so a custom field from a content type. Now it really very simple to go in and start working with content query web parts all inside of SharePoint Designer. In this example I am going to:
  • Create a content query web part that is going to show me the most popular articles that are related to an article that I created.
  • I will do some “conditional formatting” to display a confidentiality warning to the user based on the metadata associated to the article.
Approach
As I alluded creating your own xsl for content query web parts is much easier with SharePoint Designer 2010. To access and modify the style sheets select All Files in the Navigation. Then drill down to Style Library >> XSL Style Sheets. There are three style sheets that come out of the box ContentQuery.xsl, Header.xsl and ItemStyle.xsl. The one you will need to work with the most of the time is ItemStyle.xsl.


Next question you may have is how to create new xsl entries for the content query web part? Well I have found the simplest approach is pretty simple.
  • I open up ItemStyle.xsl.
  • I copy ones of the existing xsl templates. Specifically, I copy a full <xsl:template> and add it to the very bottom.
  • Then you need to modify the template tag and replace XXX values <xsl:template name="XXX" match="Row[@Style='XXX']" mode="itemstyle">. It is important that both values are identical. As well, they need to be unique to the xsl file.
That’s it. I am not going to give a full lesson here on all the cool things you can do once you are in there. I leave that up to you as a creative solution developer.
When doing this write up I refined my thoughts a little bit on how to do content query web parts. Specifically I think it is not best to the ItemStyle.xsl directly. Why? Well when you make a change to the ItemStyle.xsl (as I outlined above) you will get a warning saying “Saving your changes will customize this page so that is no longer based on the site definition. Do you want to continue?”


clip_image003


So you make this change you are customizing (unghosting) the ItemStyle.xsl which may not always be the best thing if you are planning for an Upgrade. YES YOU SHOULD BE THINKING ABOUT THE NEXT VERSION OF SHAREPOINT! Look at the forest; not the tree in front of you. Customized pages had to be dealt with when upgrading from SharePoint 2003 to 2007 as well as SharePoint 2007 to 2010. My response officially is it always “depends” but I try to avoid customizing (unghosting) as much as I can.
Knowing this I believe a best practice will be to create your own content query web parts that point to a custom ItemStyle.xsl file. Then your customizations will be managed separately and will not interfere with upgrades to OOB features. The solution is so easy as well; it is a no brainer. Let me walk through it.
  • First I took the existing ItemStyle.xsl in SharePoint Designer and copy pasted it within the same directory. I named it ItemStyle_BrandingBlog.xsl.
  • Next I went into it and stripped out all of the existing <xsl:template> tags and all the content within them. If those need to be used, I will use the OOB content query web part. Then saved it.
  • Next I just added an out of the box content query web part onto a web part page.
  • I made zero changes to the content query web part and exported the web part configuration. I saved the file locally. I named it Content_Query_Branding_Blog.webpart.
  • Next I opened the Content_Query_Branding_Blog.webpart (which is nothing more than a XML configuration file for the content query web part).
  • I modified the ItemXslLink to point to my new ItemStyle_BrandingBlog.xsl. <property name="ItemXslLink" type="string">/Style Library/XSL Style Sheets/ItemStyle_BrandingBlog.xsl</property>
  • I modified the Title to <property name="Title" type="string">Branding Blog Content Query</property>
  • Next I went to Site Settings >> Web Parts Gallery >> and then upload the Content_Query_Branding_Blog.webpart.
Done.
Now you have created your own XSL style sheet and you have created a content query web part configuration that uses that style sheet. We will later automate this as part of a WSP deployment.
Now let’s jump into the configuration of the two web parts that I need to create for my technology article publishing page.
Related Articles Content Query Web Part
As you may recall I need to support the ability show related technology articles. So I want to query for all articles that are related to the one being viewed.
Step 1 – Create the XSL for Content Query Web Part
The first thing I need to do is create a view of data that will show the following:
  • The title of the article
  • The rating of the article
  • The last modified date
  • The first 300 characters from the article
To accomplish I wrote the following xsl in the ItemStyle_BrandingBlog.xsl that I created in the previous step. I did all of this in SharePoint Designer 2010.

<xsl:stylesheet 
  version="1.0" 
  exclude-result-prefixes="x d xsl msxsl cmswrt"
  xmlns:x="http://www.w3.org/2001/XMLSchema" 
  xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" 
  xmlns:cmswrt="http://schemas.microsoft.com/WebParts/v3/Publishing/runtime"
  xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
  <xsl:param name="ItemsHaveStreams">
    <xsl:value-of select="'False'" />
  </xsl:param>
  <xsl:variable name="OnClickTargetAttribute" select="string('javascript:this.target=&quot;_blank&quot;')" />
  <xsl:variable name="ImageWidth" />
  <xsl:variable name="ImageHeight" />
    <xsl:template name="TitleDateAndRatings" match="Row[@Style='TitleDateAndRatings']" mode="itemstyle">
        <xsl:variable name="SafeLinkUrl">
            <xsl:call-template name="OuterTemplate.GetSafeLink">
                <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="DisplayTitle">
            <xsl:call-template name="OuterTemplate.GetTitle">
                <xsl:with-param name="Title" select="@Title"/>
                <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
            </xsl:call-template>
        </xsl:variable>
     <div>
         <xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
            <table>
                <tr>
                    <td width="500px" colspan="3">
                        <hr />
                    </td>
                </tr>
                <tr>
                    <td width="300px">
                        <a href="{$SafeLinkUrl}" title="" >
                            <xsl:if test="$ItemsHaveStreams = 'True'">
                                <xsl:attribute name="onclick">
                                    <xsl:value-of select="@OnClickForWebRendering"/>
                                </xsl:attribute>
                            </xsl:if>
                            <xsl:if test="$ItemsHaveStreams != 'True' and @OpenInNewWindow = 'True'">
                                <xsl:attribute name="onclick">
                                    <xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>
                                </xsl:attribute>
                            </xsl:if>
                            <xsl:value-of select="$DisplayTitle"/>
                        </a>
                    </td>
                    <td nowrap="nowrap" width="100px">
                        <xsl:if test="@Ratings &gt;= 4.75">
                            <span>
                                <a class="ms-currentRating"><img src="/_layouts/Images/Ratings.png" class="ms-rating_5" alt="Current average rating is 5 stars." /></a>
                            </span>
                        </xsl:if>
                        <xsl:if test="@Ratings &gt;= 4.25 and @Ratings &lt; 4.75">
                            <span>
                                <a class="ms-currentRating"><img src="/_layouts/Images/Ratings.png" class="ms-rating_4_5" alt="Current average rating is 4.5 stars." /></a>
                            </span>
                        </xsl:if>
                        <xsl:if test="@Ratings &gt;= 3.75 and @Ratings &lt; 4.25">
                            <span>
                                <a class="ms-currentRating"><img src="/_layouts/Images/Ratings.png" class="ms-rating_4"  alt="Current average rating is 4 stars." /></a>
                            </span>
                        </xsl:if>
                        <xsl:if test="@Ratings &gt;= 3.25 and @Ratings &lt; 3.75">
                            <span>
                                <a class="ms-currentRating"><img src="/_layouts/Images/Ratings.png" class="ms-rating_3_5" alt="Current average rating is 3.5 stars." /></a>
                            </span>
                        </xsl:if>
                        <xsl:if test="@Ratings &gt;= 2.75 and @Ratings &lt; 3.25">
                            <span>
                                <a class="ms-currentRating"><img src="/_layouts/Images/Ratings.png" class="ms-rating_3" alt="Current average rating is 3 stars." /></a>
                            </span>
                        </xsl:if>
                        <xsl:if test="@Ratings &gt;= 2.25 and @Ratings &lt; 2.75">
                            <span>
                                <a class="ms-currentRating"><img src="/_layouts/Images/Ratings.png" class="ms-rating_2_5" alt="Current average rating is 2.5 stars." /></a>
                            </span>
                        </xsl:if>
                        <xsl:if test="@Ratings &gt;= 1.75 and @Ratings &lt; 2.25">
                            <span>
                                <a class="ms-currentRating"><img src="/_layouts/Images/Ratings.png" class="ms-rating_2" alt="Current average rating is 2 stars." /></a>
                            </span>
                        </xsl:if>
                        <xsl:if test="@Ratings &gt;= 1.25 and @Ratings &lt; 1.75">
                            <span>
                                <a class="ms-currentRating"><img src="/_layouts/Images/Ratings.png" class="ms-rating_1_5" alt="Current average rating is 1.5 stars." /></a>
                            </span>
                        </xsl:if>
                        <xsl:if test="@Ratings &lt; 1.25">
                            <span>
                                <a class="ms-currentRating"><img src="/_layouts/Images/Ratings.png" class="ms-rating_1" alt="Current average rating is 1 star." /></a>
                            </span>
                        </xsl:if>
                    </td>
                    <td nowrap="nowrap" width="100px">
                        <xsl:value-of select="ddwrt:FormatDateTime(string(@Date), 1033, 'M/d/yyy h:mm tt')" />
                    </td>
                </tr>
                <tr>
                    <td colspan="3" width="500px">
                        <xsl:value-of select="substring(@Description, 1, 300)" disable-output-escaping="yes" />...
                    </td>
                </tr>
            </table>         
        </div>
    </xsl:template>
</xsl:stylesheet>


Let me discuss several of things I did to accomplishing this:


  • First I created a little HTML table that will control the format of the data. Then I started to add in fields.
  • The link title is printed here - <xsl:value-of select="$DisplayTitle"/> I simply took an example from the out of the box ItemStyle.xsl.
  • Next I needed to print the star ratings. I would have never figured this out until I found this article by accident - blog. This smart person showed how to do it and I just had to make a few minor changes for myself. Basically it looks at the rating value tied to the page rating. Then using styles it will print the appropriate star image.
  • Next I needed to print the last modified date. Here is the code that accomplished that <xsl:value-of select="ddwrt:FormatDateTime(string(@Date), 1033, 'M/d/yyy h:mm tt')" />. One thing to note is I had to add this namespace to the main xsl tag xmlns:ddwrt=http://schemas.microsoft.com/WebParts/v2/DataView/runtime. If you forget to do this, you will get errors.
  • Finally print the description I used the following line of code - <xsl:value-of select="substring(@Description, 1, 300)" disable-output-escaping="yes" />. In it I only print the first 300 characters. Plus I using the disable-output-escaping attributed to remove the embedded HTML in the article.


Step 2 – Test It


I saved my work and the next thing I did was test it to make sure the formatting looked good. To accomplish this I just went to a web part page. Here is a view of it with some test data in there. You can see I am getting the article title, start rating, a nicely formatted date and the article content. Now I just need to configure this into my Page Layout.


  

Step 3 – Add and Configure the Content Query Web Part to the Page Layout


The last step is to configure this web part into the page layout. When I do this, now every page provisioned using this layout will have this web part pre-configured. What I did was:


  • Go back to my page layout.
  • Added a new row for Related Articles.
  • Open up the split view.
  • Then I will select Insert tab on the ribbon.
  • Then select the web part I deployed in the previous section

No comments:

Post a Comment