Monthly Archives: April 2015

More fun with tagging in Sitecore 8 – Grouping Tags and Tagging tags

StartImage

In my previous post Tagging is fun in Sitecore I showed you guys how easy it is to “tag” your content. In this post I would like to go a step further with the tagging:
-Grouping tags
-Tag the tags
-Create computed index fields for the tags
-Faceting the computed index fields
-Searching using LINQPAD (for Sitecore 8)

Grouping tags

The idea is to keep the tags in groups where the group(folder) will have a tag field(multilist with search) – That means we can tag the group.
(The tag groups can also contain other tag groups).

In order to accomplish this we need a template folder which will contain a “tag field”. In the Standard Values we will set the Insert Options to allow tag template and this group folder template.
GroupFolder

Next thing will be to create the tag group in the TagRepository folder under Buckets in Sitecore/Systems. Let us call it Groups and add some tags to it.
GroupsOfTags
Each tag will represent a tag group of its own. So let us create the rest of the tag groups.

In order to tag the groups we need the “Group tags” in the “multilist with search” field, we will do this by setting the source of the field. We only want to show the tags, so we need to do some filtering using TemplateFilter.

StartSearchLocation={CA34C9E3-4B6B-4994-9E52-219F22EE465C}&TemplateFilter={68BA23FD-8270-4675-97EA-4FAFC7CF3AB9}

You can also set the source by using query:

StartSearchLocation=query:/sitecore/system/Settings/Buckets/TagRepository/Sitecore8 MVC/Groups&TemplateFilter={68BA23FD-8270-4675-97EA-4FAFC7CF3AB9}

Now we can tag the folders, Europe folder will be tagged with the “Europe tag” and so on…
TaggingEurope

In this example we will list some articles in a bucket folder. Each article will contain some tag fields(multilist with search) which will contain country tags and article type tags.
ArticleTagsMore
That means the tag fields(multilist with search) will point to the group folders – Countries and Article types.
Below you can see how the source for “Countries folder” is set, it contains the sub folders “Europe” and “North America”.

StartSearchLocation={0F7B4B81-1789-44E8-A826-04E559682CED}&TemplateFilter={68BA23FD-8270-4675-97EA-4FAFC7CF3AB9}

Or using query:

StartSearchLocation=query:/sitecore/system/Settings/Buckets/TagRepository/Sitecore8 MVC/Countries&TemplateFilter={68BA23FD-8270-4675-97EA-4FAFC7CF3AB9}

Since we have set the TemplateFilter to filter tags, the “multilist with search” field will only show the tags.
Now we have prepared and setup the group tags, next thing will be to tag the tags.

Tag the tags

Let say you have a bunch of articles and you need to add some new tags. Instead of doing it for each article you could tag the tags.

For instance if you would like to tag the articles for Visually Impaired and Hearing Impaired. So let us create a new tag folder called Disabilities in the TagRepository.
Disabilities

Next will be to go through the tags in the Article Types folder and tag them accordingly.
ArticleTypes

We will use the tagging from the standard template, here is “Voice acting tag” tagged to Visually impaired
VisuallyImpairedTagging

And the rest of the tags:
Text to speach -> Visually impaired
Blog -> Hearing impaired
Newsletter -> Hearing impaired
Magazine -> Hearing impaired
Newspaper -> Hearing impaired

Next will be to do some computed index fields for the group tags and the “tagged tags” and make them facet ready.

Create computed index fields

Computed index field allows you to perform additional processing before adding data to an index

Countries and Article Types
The computed index fields for Countries and Article Types will have following base class:

public abstract class TagsBase : IComputedIndexField
{
    public virtual ID TagsSelector { get; set; }

    public object ComputeFieldValue(IIndexable indexable)
    {
        var indexableItem = indexable as SitecoreIndexableItem;

        return indexableItem == null || TagsSelector.IsNull ? null : indexableItem.Item.GetMultiListValues(TagsSelector).Select(tag => tag.Name).ToList();
    }

    public string FieldName { get; set; }
    public string ReturnType { get; set; }
}

The TagsSelector will hold the field ID which will contain the tags.

Here is the computed index fields classes for Countries and Article Types.

public class CountryTags : TagsBase
{
    public override ID TagsSelector
    {
        get
        {
            return TaggingConstants.Fields.Tagging.TaggingCountry;
        }
    }
}

public class ArticleTypeTags : TagsBase
{
    public override ID TagsSelector
    {
        get
        {
            return TaggingConstants.Fields.Tagging.TaggingArticleType;
        }
    }
}

Group tags
Here is how the computed index field for the “Group tags” is done. The TagGroupSelector is the field which will contain the group tags. The TagsSelectors holds the tag fields(ID’s) in the article item.

public class GroupTags : IComputedIndexField
{
    public ID TagGroupSelector
    {
        get { return TaggingConstants.Fields.Tagging.TagginGroup; }
    }

    public IEnumerable<ID> TagsSelectors
    {
        get
        {
            yield return TaggingConstants.Fields.Tagging.TaggingArticleType;
            yield return TaggingConstants.Fields.Tagging.TaggingCountry;
        }
    }

    public object ComputeFieldValue(IIndexable indexable)
    {
        SitecoreIndexableItem indexableItem = indexable as SitecoreIndexableItem;

        if (indexableItem == null)
            return null;

        if (!indexableItem.Item.IsDerived(TaggingConstants.Templates.Article))
            return null;

        if (!TagsSelectors.Any())
            return null;

        if (TagGroupSelector.IsNull)
            return null;

        List<string> tagsList = new List<string>();

        foreach (ID tagsField in TagsSelectors)
        {

            if (tagsField.IsNull)
                continue;

            foreach (Item tagItem in indexableItem.Item.GetMultiListValues(tagsField))
            {
                if (tagItem.Parent == null)
                    continue;

                tagsList.AddRange(tagItem.Parent.GetMultiListValues(TagGroupSelector).Select(tag => tag.Name).ToList());
            }
        }

        return tagsList;
    }

    public string FieldName { get; set; }

    public string ReturnType { get; set; }
}

When the indexable item is an article we will loop through the selected “Countries tags” and the “Article Type tags” in order to get selected group tag/s.

Tagged tags
Finally the computed index field for the “Tagged tags”. The TagBaseSelector contains the tag field ID from standard template. The TagsSelectors holds the tag fields(ID’s) in the article item.

public class TagTags : IComputedIndexField
{
    public ID TagBaseSelector
    {
        get { return TaggingConstants.Fields.Tagging.__Semantics; }
    }

    public IEnumerable<ID> TagsSelectors
    {
        get
        {
            yield return TaggingConstants.Fields.Tagging.TaggingCountry;
            yield return TaggingConstants.Fields.Tagging.TaggingArticleType;
        }
    }

    public object ComputeFieldValue(IIndexable indexable)
    {
        SitecoreIndexableItem indexableItem = indexable as SitecoreIndexableItem;

        if (indexableItem == null)
            return null;

        if (!indexableItem.Item.IsDerived(TaggingConstants.Templates.Article))
            return null;

        if (!TagsSelectors.Any())
            return null;

        List<string> tagsList = new List<string>();

        foreach (ID tagsField in TagsSelectors)
        {

            if (tagsField.IsNull)
                continue;

            foreach (Item tagItem in indexableItem.Item.GetMultiListValues(tagsField))
            {
                tagsList.AddRange(tagItem.GetMultiListValues(TagBaseSelector).Select(tag => tag.Name).ToList());
            }
        }

        return tagsList;
    }

    public string FieldName { get; set; }

    public string ReturnType { get; set; }
}

When the indexable item is an article we will loop trough the selected “Countries tags” and the “Article Type tags” in order to get any tagged tag.

Here is patched config file for the computed index fields:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <contentSearch>
      <indexConfigurations>
        <defaultLuceneIndexConfiguration>
          <fieldMap type="Sitecore.ContentSearch.FieldMap, Sitecore.ContentSearch">
            <fieldNames hint="raw:AddFieldByFieldName">
              <field fieldName="tagtags"  storageType="YES" indexType="TOKENIZED"    vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
                <Analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
              </field>
              <field fieldName="grouptags"  storageType="YES" indexType="TOKENIZED"    vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
                <Analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
              </field>
              <field fieldName="articletypetags"  storageType="YES" indexType="TOKENIZED"    vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
                <Analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
              </field>
              <field fieldName="countrytags"  storageType="YES" indexType="TOKENIZED"    vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
                <Analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
              </field>
            </fieldNames>
          </fieldMap>
          <fields hint="raw:AddComputedIndexField">
            <field fieldName="tagtags"	storageType="yes" indexType="untokenized">Sitecore8MVC.Tagging.ComputedIndexFields.TagTags, Sitecore8MVC.Tagging</field>
            <field fieldName="grouptags"	storageType="yes" indexType="untokenized">Sitecore8MVC.Tagging.ComputedIndexFields.GroupTags, Sitecore8MVC.Tagging</field>
            <field fieldName="articletypetags"	storageType="yes" indexType="untokenized">Sitecore8MVC.Tagging.ComputedIndexFields.ArticleTypeTags, Sitecore8MVC.Tagging</field>
            <field fieldName="countrytags"	storageType="yes" indexType="untokenized">Sitecore8MVC.Tagging.ComputedIndexFields.CountryTags, Sitecore8MVC.Tagging</field>
          </fields>
        </defaultLuceneIndexConfiguration>
      </indexConfigurations>
    </contentSearch>
  </sitecore>
</configuration>

The part AddFieldByFieldName ensures that facet names(tags) are displayed correctly

Next thing to do will be to set up the facets.

Faceting

It’s time to facet the computed index fields grouptags, countrytags, articletypetags and tagtags.

We will do this by adding new facets in /sitecore/system/Settings/Buckets/Facets.
Facets
Group tags will be presented first among the facets in the search result.

Here is how the Group tags facet is done
GroupTagFacet
We add the computed index field name and check the “Global facet” checkbox.

If you don’t want the facets to be global and only be shown for a specific bucket folder you have to find the section “Indexing” on the bucket folder and select the desired facets.
LocalFacets

Here is the final result! The facets Group Tags, Related Tags (Tagged tags) etc.
FinalSearchAndFacetResult

Searching using LINQPAD

I think the LINQPAD is great for testing searches and also faceting. Here are some great posts regarding LINQPAD for Sitecore by Adam Conn:
LINQPAD AND SITECORE 7
LINQPAD DRIVER FOR SITECORE 1.9

Below you will find some examples and how easy it is to work with the LINQPAD.

A facet query to show the Group tags and the Tagged tags(Related Tags):
LinqPadGroupTags

Query for listing articles belonging to group “north america”:
LinqPadQueryGroupTags

To use the Predicate builder we need to reference Sitecore.ContentSearch.Linq.Utilities in the “Connection settings”:
LinqPadSettings

That’s all for now folks 🙂

Now when Sitecore has released Sitecore 8 it is so much funnier to work with. The design(and user experience) gives you a feeling of calm and trust – I just love Sitecore 8.
Great work Sitecore!!

Advertisements