In this post, I'll describe how we can create a custom style for a content query web part.
A reason why we may need to do something like this is because sometimes the OOTB content query web part does not display exactly what we need when querying articles for example. I wanted to the web part to display the date, title, and some of the body text (and a read more link). Unfortunately, this is something that needs to be customized since it's not available OOTB.
Firstly, you need to open ItemStyle.xsl in SharePoint Designer. Check the file out, so you can roll back if you make any mistakes in it.
Scroll to the bottom of the file and add the following just before the </xsl:stylesheet> tag:
<xsl:template name="WeiStyle" match="Row[@Style='WeiStyle']" 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="SafeImageUrl">
<xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
<xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
</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>
<xsl:variable name="LinkTarget">
<xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
</xsl:variable>
<xsl:variable name="Created">
<xsl:value-of select="ddwrt:FormatDateTime(string(@Created) ,1033 ,'dd-MM-yyyy')" />
</xsl:variable>
<div id="linkitem" class="item">
<xsl:if test="string-length($SafeImageUrl) != 0">
<div class="image-area-left">
<a href="{$SafeLinkUrl}" target="{$LinkTarget}">
<img class="image" src="{$SafeImageUrl}" alt="{@ImageUrlAltText}" />
</a>
</div>
</xsl:if>
<div class="link-item">
<xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
<a href="{$SafeLinkUrl}" target="{$LinkTarget}" title="{@LinkToolTip}">
<xsl:value-of select="$Created"/> - <xsl:value-of select="$DisplayTitle"/>
</a>
<div class="description">
<xsl:value-of select="substring(@PublishingPageContent, 0, 200)" disable-output-escaping="yes"/>
<a href="{$SafeLinkUrl}" target="{$LinkTarget}" title="Read more">...</a>
</div>
</div>
</div>
</xsl:template>
Note that in the code above that you pasted, there is a xsl variable that you set that formats the date in any way you like. To make the date formatting work, you need to add the following at the top of the xsl (namespace attribute):
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
Now save the document and refresh the page where the CQWP resides. You'll see that everything works except there is no body (yet). To make the summarised body appear, you need to export the CQWP and edit the .webpart file it in Notepad. This needs to be done because you need to add the scope to the web part.
Look for the property name CommonViewFields and change it as follows:
<property name="CommonViewFields" type="string">ExternalUrl,URL;PublishingPageImage,Image;PublishingPageContent,Note;</property>
Save the .webpart file and then go back to where the CQWP resides, delete the web part that's there and re-add a new web part. Click Advanced Web Part gallery and options, then click the "Browse" drop down and select Import. Look for the .webpart file and import that web part. You should now be able to see the web part with the date, title, content (to 200 chars) and then a ... to read more.
But that's not all. While I was doing this, I found that the first 200 chars that the web part displays actually includes any HTML code that's in there. And it just so happened (while I was testing), that if the 200th character happens to be within the HTML tag itself, the "..." read more link wouldn't work. In addition, there is a big ugly gap between the title and the summary body (because of the <p> tag in the body). So I had to figure out how to strip all HTML tags from the summary.
Go back to the ItemStyle.xsl file and add the following at the end just before the </xsl:stylesheet> tag:
<xsl:template name="RemoveHtmlTags">
<xsl:param name="html"/>
<xsl:choose>
<xsl:when test="contains($html, '<')">
<xsl:value-of select="substring-before($html, '<')"/>
<!-- Recurse through HTML -->
<xsl:call-template name="removeHtmlTags">
<xsl:with-param name="html" select="substring-after($html, '>')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$html"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This is the template that will remove all html code (when called).
Now, let's re-visit the original code you entered into the ItemStyle above. We need to add a new variable that calls this RemoveHtmlTags template in order to remove the HTML tags in the summary.
<xsl:template name="DetailedStyle" match="Row[@Style='DetailedStyle']" 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="SafeImageUrl">
<xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
<xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
</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>
<xsl:variable name="LinkTarget">
<xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
</xsl:variable>
<xsl:variable name="Created">
<xsl:value-of select="ddwrt:FormatDateTime(string(@Created) ,1033 ,'dd-MM-yyyy')" />
</xsl:variable>
<xsl:variable name="PureTextBody">
<xsl:call-template name="RemoveHtmlTags">
<xsl:with-param name="html" select="@PublishingPageContent" />
</xsl:call-template>
</xsl:variable>
<div id="linkitem" class="item">
<xsl:if test="string-length($SafeImageUrl) != 0">
<div class="image-area-left">
<a href="{$SafeLinkUrl}" target="{$LinkTarget}">
<img class="image" src="{$SafeImageUrl}" alt="{@ImageUrlAltText}" />
</a>
</div>
</xsl:if>
<div class="link-item">
<xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
<a href="{$SafeLinkUrl}" target="{$LinkTarget}" title="{@LinkToolTip}">
<xsl:value-of select="$Created"/> - <xsl:value-of select="$DisplayTitle"/>
</a>
<div class="description">
<xsl:value-of select="substring($PureTextBody, 0, 200)" disable-output-escaping="yes"/>
<a href="{$SafeLinkUrl}" target="{$LinkTarget}" title="Read more">...</a>
</div>
</div>
</div>
</xsl:template>
I have highlighted the difference in <bold> so you can see what was done to strip out the HTML.
