Restricting the number of words and adding a Read More link

Continuing from this post, I noticed that the whole blog post body would be displayed in the Content Query web part like below.

SharePoint Online Custom Blog Post Long

To reduce the number of words shown on the Content Query web part, I turned to XSL. Here’s a good introduction to XSL tags, structure and templates for use in the Content Query web part. [Link]

Tried out a simple piece of code to implement substring of the body contents in the template added. However, it cuts off the word midway since it restricts by number of characters.

SharePoint Customised Blog Post

This was the code snippet added.

<div class="custom_description">
	<xsl:value-of select="substring(@Body,1,255)" disable-output-escaping="yes" />
</div>

So looked around a little more and found this. [Link] Basically added the two templates and called them. This is the result.

SharePoint Customised Blog Post Word Cut-Off

In all, the previous XSL was extended as follows with the templates StripHTML removing the HTML markup for the body and FirstNWords restricting the display by N words.

  <xsl:template name="BlogPost" match="Row[@Style='BlogPost']" 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 class="custom_posttitle">
            <xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
            <a href="{$SafeLinkUrl}" title="{@LinkToolTip}">
              <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>
        </div>
    <xsl:variable name="StartDate">
        <xsl:value-of select="ddwrt:FormatDateTime(string(@PublishedDate), 1033, 'g')" />
    </xsl:variable>
    <div class="custom_date">
            <xsl:value-of select="$StartDate" />
    </div>
    <div class="custom_description">
		<xsl:variable name="BodyText">
			<xsl:call-template name="StripHTML">
				<xsl:with-param name="HTMLText" select="@Body"/>
			</xsl:call-template>
		</xsl:variable>
        <xsl:call-template name="FirstNWords">
			<xsl:with-param name="TextData" select="$BodyText"/>
			<xsl:with-param name="WordCount" select="25"/>
			<xsl:with-param name="MoreText" select="'...'"/>
		</xsl:call-template>
    </div>
  </xsl:template>
  <xsl:template name="StripHTML">
	<xsl:param name="HTMLText"/>
	<xsl:choose>
		<xsl:when test="contains($HTMLText, '&gt;')">
			<xsl:call-template name="StripHTML">
				<xsl:with-param name="HTMLText" select="concat(substring-before($HTMLText, '&lt;'), substring-after($HTMLText, '&gt;'))"/>
			</xsl:call-template>
		</xsl:when>
		<xsl:otherwise>
			<xsl:value-of select="$HTMLText"/>
		</xsl:otherwise>
	</xsl:choose>
  </xsl:template>
  <xsl:template name="FirstNWords">
	<xsl:param name="TextData"/>
	<xsl:param name="WordCount"/>
	<xsl:param name="MoreText"/>
	<xsl:choose>
		<xsl:when test="$WordCount &gt; 1 and
			(string-length(substring-before($TextData, ' ')) &gt; 0 or
			string-length(substring-before($TextData, '  ')) &gt; 0)">
			<xsl:value-of select="concat(substring-before($TextData, ' '), ' ')" disable-output-escaping="yes"/>
			<xsl:call-template name="FirstNWords">
				<xsl:with-param name="TextData" select="substring-after($TextData, ' ')"/>
				<xsl:with-param name="WordCount" select="$WordCount - 1"/>
				<xsl:with-param name="MoreText" select="$MoreText"/>
			</xsl:call-template>
		</xsl:when>
		<xsl:when test="(string-length(substring-before($TextData, ' ')) &gt; 0 or
			string-length(substring-before($TextData, '  ')) &gt; 0)">
			<xsl:value-of select="concat(substring-before($TextData, ' '), $MoreText)" disable-output-escaping="yes"/>
		</xsl:when>
		<xsl:otherwise>
			<xsl:value-of select="$TextData" disable-output-escaping="yes"/>
		</xsl:otherwise>
	</xsl:choose>
  </xsl:template>

Now I wanted to make it more intuitive by adding ‘Read More’ links to the article.

SharePoint Customised Blog Post Read More

And here’s the code snippet for the Read more links.

    <div class="custom_description">
		<xsl:variable name="BodyText">
			<xsl:call-template name="StripHTML">
				<xsl:with-param name="HTMLText" select="@Body"/>
			</xsl:call-template>
		</xsl:variable>
        <xsl:call-template name="FirstNWords">
			<xsl:with-param name="TextData" select="$BodyText"/>
			<xsl:with-param name="WordCount" select="25"/>
			<xsl:with-param name="MoreText" select="'...'"/>
		</xsl:call-template>
		<a href="{$SafeLinkUrl}"> Read more</a>
    </div>
    <br />

If the title of the blog post does not need to be hyperlinked to the article, remove this code snippet.

        <div class="custom_posttitle">
            <xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
            <a href="{$SafeLinkUrl}" title="{@LinkToolTip}">
              <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>
        </div>

And leave it like this.

	<div class="custom_posttitle">
		<xsl:value-of select="$DisplayTitle"/>
	</div>

Leave a comment