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.