Altering Xslt Files for Blog Categories with Tags

This is the third post in a series looking at the issue of having Categories at the Blog level with Blog 4 Umbraco.  It builds upon the post dealing with extending the Blog Tags to take make them specific to a particular Blog by taking advantage of the Tag Group feature.  For background, see the following posts:

Blog 4 Umbraco installs a suite of xslt files that among other things aggregate Tags that the posts are associated with.  However, some of the code looks specifically for the default Tag Group, while other parts of it don't care what group the tags are in.  If you have multiple blogs on a site, this leads to tags being displayed that may actually have nothing to do with the Blog you are looking at.

In this article we're going to attempt to address this issue and clean the xslt files up a little.  Starting with the BlogCategories.xslt file, which by default looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:msxml="urn:schemas-microsoft-com:xslt"
  xmlns:umbraco.library="urn:umbraco.library"
  xmlns:tagsLib="urn:tagsLib"
  exclude-result-prefixes="msxml umbraco.library tagsLib">


<xsl:output method="html" omit-xml-declaration="yes"/>

<xsl:param name="currentPage"/>

<xsl:variable name="blogRoot" select="$currentPage/ancestor-or-self::Blog/@id"/>

<xsl:template match="/">
<ul>
  <li class="cat-item"><a href="{umbraco.library:NiceUrl($blogRoot)}">All</a> <span> (<xsl:value-of select="count($currentPage/ancestor-or-self::Blog//BlogPost)"/>)</span></li>
  <xsl:for-each select="tagsLib:getAllTagsInGroup('default')/tags/tag">
        <li class="cat-link">
            <a href="{umbraco.library:NiceUrl($blogRoot)}?filterby={current()}"><xsl:value-of select="current()"/></a> (<xsl:value-of select="@nodesTagged"/>)
        </li>
  </xsl:for-each>
</ul>

</xsl:template>

</xsl:stylesheet>​


Note the line that retrieves all Tags in the default using tagsLib:getAllTagsInGroup().  This is where the problem lies:  We have a blog that has had a category attribute set to "Events" (see the first article listed above), and we now have tags that are associated with the "Events" group, not the "default" group.

In order to fix this, we need to retrieve the category from the Blog node, and use that to retrieve the correct tags.  However, if the blog hasn't implemented the category attribute, or the attribute is left blank, we need to fall back on the current functionality.  So I've made the following adjustments:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:msxml="urn:schemas-microsoft-com:xslt"
  xmlns:umbraco.library="urn:umbraco.library"
  xmlns:tagsLib="urn:tagsLib"
  exclude-result-prefixes="msxml umbraco.library tagsLib">


<xsl:output method="html" omit-xml-declaration="yes"/>

<xsl:param name="currentPage"/>

<xsl:variable name="blogRoot" select="$currentPage/ancestor-or-self::Blog"/>
<xsl:variable name="blogRootId" select="$blogRoot/@id"/>
<xsl:variable name="blogCategory" select="$blogRoot/category"/>

<xsl:template match="/">
  
  <ul>
  <li class="cat-item"><a href="{umbraco.library:NiceUrl($blogRootId)}">All</a> <span> (<xsl:value-of select="count($currentPage/ancestor-or-self::Blog//BlogPost)"/>)</span></li>
  <xsl:if test="$blogCategory = ''">
    <xsl:call-template name="listCategories">
      <xsl:with-param name="category" select="'default'"/>
    </xsl:call-template>
  </xsl:if>
  <xsl:if test="$blogCategory != ''">
    <xsl:call-template name="listCategories">
      <xsl:with-param name="category" select="$blogCategory"/>
    </xsl:call-template>
</xsl:if>

</ul>

</xsl:template>

<xsl:template name="listCategories">
  <xsl:param name="category"/>
  <xsl:for-each select="tagsLib:getAllTagsInGroup($category)/tags/tag">
      <li class="cat-link">
          <a href="{umbraco.library:NiceUrl($blogRootId)}?filterby={current()}"><xsl:value-of select="current()"/></a> (<xsl:value-of select="@nodesTagged"/>)
      </li>
  </xsl:for-each>
</xsl:template>
</xsl:stylesheet>​



Notice that we've split the actual rendering of the categories list into a separate template called listCategories and have conditionally called it with either the category retrieved from the Blog document or the 'default' tag Group if the category doesn't exist.

Next we tackle the Tag Cloud in much the same way.  The original Xslt source:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
    <!ENTITY nbsp " ">
]>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxml="urn:schemas-microsoft-com:xslt"
  xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:BlogLibrary="urn:BlogLibrary"
  exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib BlogLibrary ">


    <xsl:output method="xml" omit-xml-declaration="yes"/>

    <xsl:param name="currentPage"/>

    <xsl:template match="/">
        <div class="tagcloud">
            <p>

                <xsl:for-each select="tagsLib:getAllTags()/tags/tag [@nodesTagged > 0]">
                    <xsl:sort select="." order="ascending"/>
                    <a href="{umbraco.library:NiceUrl($currentPage/ancestor-or-self::Blog/@id)}?filterby={.}">
                        <xsl:attribute name="class">
                            <xsl:choose>
                                <xsl:when test="@nodesTagged > 5">
                                    <xsl:value-of select="string('tagweight5')"  />
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:value-of select="concat('tagweight',@nodesTagged)"/>
                                </xsl:otherwise>
                            </xsl:choose>
                        </xsl:attribute>
                        <xsl:value-of select="."/>
                    </a>
                    <xsl:text> </xsl:text>
                </xsl:for-each>

            </p>
        </div>

    </xsl:template>

</xsl:stylesheet>​

And after our modifications:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
    <!ENTITY nbsp " ">
]>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxml="urn:schemas-microsoft-com:xslt"
  xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:BlogLibrary="urn:BlogLibrary"
  exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib BlogLibrary ">


    <xsl:output method="xml" omit-xml-declaration="yes"/>

    <xsl:param name="currentPage"/>

    <xsl:variable name="blogRoot" select="$currentPage/ancestor-or-self::Blog"/>
    <xsl:variable name="blogRootId" select="$blogRoot/@id"/>
    <xsl:variable name="blogCategory" select="$blogRoot/category"/>
    
    <xsl:template match="/">
        <div class="tagcloud">
            <p>
              
            <xsl:if test="$blogCategory = ''">
              <xsl:call-template name="createCloud">
                <xsl:with-param name="category" select="'default'"/>
              </xsl:call-template>
            </xsl:if>
            <xsl:if test="$blogCategory != ''">
              <xsl:call-template name="createCloud">
                <xsl:with-param name="category" select="$blogCategory"/>
              </xsl:call-template>
            </xsl:if>
             
            </p>
        </div>

    </xsl:template>
    
  <xsl:template name="createCloud">
    <xsl:param name="category"/>

    <xsl:for-each select="tagsLib:getAllTagsInGroup($category)/tags/tag [@nodesTagged > 0]">
        <xsl:sort select="." order="ascending"/>
        <a href="{umbraco.library:NiceUrl($blogRootId)}?filterby={.}">
            <xsl:attribute name="class">
                <xsl:choose>
                    <xsl:when test="@nodesTagged > 5">
                        <xsl:value-of select="string('tagweight5')"  />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="concat('tagweight',@nodesTagged)"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:attribute>
            <xsl:value-of select="."/>
        </a>
        <xsl:text> </xsl:text>
    </xsl:for-each>

  </xsl:template>
</xsl:stylesheet>​​​


And there we have it. Both the Tags list and the Tag Cloud now behave nicely when used within the context of a Blog.

1 comment for “Altering Xslt Files for Blog Categories with Tags”

  1. Posted Friday, December 06, 2013 at 2:24:11 PM

    We can check that an image or paragraph exists by the return value of the SelectSingleNode or SelectNodes methods making it very easy to conditionally display the image or a placeholder if desired, for example.

Post a comment