Thursday, January 28, 2010

Tag Cloud from Sitecore content

Let's assume you have a Sitecore site containing "Products" section, it is well-structured by categories, and contains many thousands of items.



Some day you decide to add tags to all your products...

No problem, you should just find a place to store tags



And then add a new field to the product template



Here what you got on each product:


Now the most interesting part, we need to build a tag cloud based on these values. There are lot of ways to implement it, but when you have to deal with really big content tree, the most suitable solution is using some search engine. In this example I'll use Coveo, but it's possible to implement the same functionality using Lucene with almost the same effort.


In order to configure Coveo you need to perform following steps:

1) Create a new "Sitecore Connector" source and point it to your site



2) Create Index Mapping file, which will map Sitecore fields to the Coveo index fields.

It will be very simple in our case, it will tell Coveo to map Sitecore tag items titles to  its own "Tags" field.
<?xml version="1.0" encoding="utf-8" ?>
<Sitecore>
<Mapping template="{DCF9F4A5-08E9-4EBC-A4A4-92C93F55BFFB}">
<Fields>
<Tags>%[Tags.Title]</Tags>
</Fields>
</Mapping>
</Sitecore>
* This source code was highlighted with Source Code Highlighter.

3) Also, you need to declare "Tags" field in Coveo:



Done. Now press "Start" on index, and after indexing site, you'll be able to find "@tags" field in index content viewer



The most time consuming part is done, now you should retrieve data from Coveo and display it at front-end.

I'll use the following approach, it can be easily changed or extended:
  • Retrieving tags will be done using JQuery and simple web-service.
  • Tags will be displayed using jquery.tagcloud plugin(http://code.google.com/p/jquery-tagcloud/).

Here is the code to implement it:

1) Let's create really simple "Tag" class:
public class Tag
{
public string Title { get; set; }
public int Count { get; set; }
}* This source code was highlighted with Source Code Highlighter.

2) And a bit more complex CoveoHelper class with a single method:
public static IEnumerable GetTags(string[] allowedValues)
{
var builder = new SearchBuilder();ICESSearchProvider provider = SearchUtilities.CreateDefaultSearchProvider();
builder.Provider = provider;
builder.AddConstantExpression("@Source=TagCloud");
var groupByClause = new GroupBy { Field = "@tags" };
groupByClause.AllowedValues = allowedValues;
builder.GroupFields.Add(groupByClause);QueryWrapper query = QueryWrapperFactory.GetNewQueryWrapper(builder);bool moreExists;
var result = from tag in query.GetGroupByResults(0, int.MaxValue - 1, out moreExists)
select new Tag
{
Title = tag.Value,
Count = tag.NumberOfResults
};
return result;
}* This source code was highlighted with Source Code Highlighter.

3) Now, a small web-service
[OperationContract]
public Tag[] GetTags()
{
var allowedValues = tagsFolder.Children.Select(x => x.Fields["Title"].ToString()).ToArray();
var tags = CoveoHelper.GetTags(allowedValues);
return tags.ToArray();
}
* This source code was highlighted with Source Code Highlighter.

Server-side programming is done, let's add some jQuery.

We just call our web-service and use plugin to compose a tag cloud:
jQuery(document).ready(function() {
jQuery.ajax({
type: "POST",
url: "/Coveo/TagsService.svc/GetTags",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(obj) {
var tags = obj.d;
$("#wrapper").tagCloud(tags, { maxFontSizeEm: 3 });
}
});
});
* This source code was highlighted with Source Code Highlighter.

And here is the result:



Hope you liked this brief guideline, if you have any suggestions/questions, or any ideas for future articles - don't hesitate to post your comments.