Share

LinkedIn

Customizing Sitecore’s Hyperlink Manager to Track “OnClick” Events

I was reviewing some code for a past client with a colleague of mine recently, and they became very excited about one particular feature.

We had customized the Hyperlink Manager so that it would automatically include a Google Analytics tracking event when the link was rendered – allowing the client to maintain an extensive analytics store when transferring to a Sitecore-based site.

My colleague Ben Golden mentioned this in a video interview in this blog post. I wanted to build on the lessons from his post and show an example of how to implement this automatic analytics link rendering.

Many of our clients come to us with the goal of rebuilding an existing web site in Sitecore, rather than creating something completely new. Over the years, we’ve learned to ask in our discovery sessions if the client is tracking any parts of their existing site (including document downloads or outbound links) with analytics software. The client may or may not realize it, but keeping those analytics tags the same on the new site can be a huge asset when redesigning the site. The goal of this article is to show how easy it can be to allow the content editors to maintain these analytics tags in the new site implementation in Sitecore.

Important note:
You can also use this customized Sitecore feature in your current site.

  • Make your content author’s life easier by enabling them to maintain analytics tags within the Hyperlink Manager.
  • Add analytics tracking to ALL kinds of links in the Rich Text Editor using the Hyperlink Manager – internal links, email links, external links (use different tracking keys for links that open in a new window), etc.

Following Ben’s excellent instructions, we first modify the /Sitecore/shell/Controls/Rich Text Editor/EditorPage.aspx file to point to our new Hyperlink Manager dialog. Next we copy the existing LinkManager.ascx file out of the Telerik.Web.UI.dll using Reflector. For our purposes, we will be adding a new text field to the Hyperlink tab of the Hyperlink Manager, as shown below. This is where the content editor will enter the key used for a link in Google Analytics.

Aware Blog Posts

This is easy to add to the markup by just adding a new table row and textbox:

<tr>
    <td class="reLabelCell">
        <label for="LinkAnalyticsKey" class="reDialogLabel">
            <span>Analytics Key</span>
        </label>
    </td>
    <td class="reControlCell">
        <input type="text" id="LinkAnalyticsKey" />
    </td>
</tr>

Now, let’s move on to editing the JavaScript component of the Hyperlink Manager. We start with the simple tasks of adding a data member to hold the value that the user enters for the analytics key, and initialize it as well.

setupChildren: function ()
{
    // Existing code here.
    this._linkAnalyticsKey = $get("LinkAnalyticsKey");
}
  
  
_cleanInputBoxes: function ()
{
    // Existing code here.
this._linkAnalyticsKey.value = "";
}

Next, we have to modify the getModifiedLink function to take our new data field into account:

getModifiedLink: function ()
{
    var resultLink = this._clientParameters.get_value();
    var selectedIndex = this._tab.get_selectedIndex();
  
    if (selectedIndex == 0)//"link"
    {
        resultLink.href = this._linkUrl.value;
            // Analytics Key tracking code starts here
        if (this._linkAnalyticsKey.value != '')
        {
            var paramDelimiter = this._linkUrl.value.indexOf('?') != -1 ? '&' : '?';
            resultLink.href = this._linkUrl.value + paramDelimiter + "tk=" + this._linkAnalyticsKey.value;
        }
        // Analytics Key tracking code ends here
           // ...

Finally, we need to add two helper functions to the JavaScript component to aid in parsing our analytics key on the link URI:

getAnalyticsKeyFromUrl: function (url)
{
    if (url.indexOf('tk=') != -1)
    {
        var urlParts = url.split('?');
  
        var params = '';
        if (urlParts.length > 1)
        {
            params = this.parseQueryString(urlParts[1]);
        }
  
        return params != '' && params["tk"] != undefined ? params["tk"] : '';
    }
    return '';
},
  
removeAnalyticsKeyFromUrl: function (url)
{
    var urlParts = url.split('?');
  
    var params = '';
    if (urlParts.length > 1)
    {
        params = this.parseQueryString(urlParts[1]);
    }
  
    if (params != '')
    {
        var newQs = '';
        for (var param in params)
        {
            if (param == 'tk')
                continue;
  
            if (newQs != '')
                newQs += '&';
            newQs += param + "=" + params[param];
        }
        return urlParts[0] + '?' + newQs;
    }
    return url;
}

These functions are utilized by the _loadLinkProperties function that already exists as part of the dialog component. One line is modified near the end of this function, and another is added:

this._linkUrl.value = this.removeAnalyticsKeyFromUrl(href);
this._linkAnalyticsKey.value = this.getAnalyticsKeyFromUrl(currentHref);

Now, if you’ve read the code carefully at this point, you’ll notice that all it does is add a “tk” querystring to the link. How do we get from that (which has nothing to do with Google Analytics), to a useful call to the Google API? With more JavaScript, of course. We have a Global.js file that is loaded onto every page and runs the following script (which is dependent on jQuery):

(function ()
{
    function InitializeAnalytics()
    {
        jQuery('a[href*="tk="]').each(function (index)
        {
            var elem = jQuery(this);
            var href = elem.attr('href').split('?');
  
            var params = '';
            if (href.length > 1)
            {
                params = ParseQueryString(href[1]);
            }
  
            var modifiedParams = {};
            jQuery.each(params, function (index, val)
            {
                if (index != 'tk')
                    modifiedParams[index] = val;
            });
  
            var newQs = '';
            jQuery.each(modifiedParams, function (index, val)
            {
                if (newQs != '')
                    newQs += "&";
                newQs += index + "=" + encodeURIComponent(val);
            });
  
            elem.attr('href', href[0] + (newQs != '' ? "?" + newQs : ''));
            elem.attr('onclick', "javascript:_gaq.push(['regionalTracker._trackPageview', '" + params['tk'] + "']);");
        });
    }
  
    function ParseQueryString(qs)
    {
        var result = {}, queryString = qs, re = /([^&=]+)=([^&]*)/g, m;
        while (m = re.exec(queryString))
        {
            result[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
        }
        return result;
    }
})();

That looks more like it, doesn’t it? You can see that we look for all links on the page with “tk=” in their href attribute, take that querystring out of the URI and add an onclick attribute with the appropriate values. This is the “missing link” that moves the tracking key from being an attribute of the URI to being sent to Google via their gaq.push API call.

I hope you’ve enjoyed seeing a second example of how to modify the Sitecore Rich Text Editor’s Hyperlink Manager for a different use case, and I hope the idea of using an additional JavaScript function to reformat the data stored in the Hyperlink Manager into an actual Google Analytics call was helpful. If you have your own favorite modifications to the Hyperlink Manager or a different way of tracking external links with Google Analytics, please share them in the comments below!

(Thank you to Adam Weber for his contributions to the code in this post!)

Sitecore development, Sitecore custom code, Google Analytics

Comments

Add a Comment

*
*

Please confirm you are human by typing the text you see in this image:

Brian Spradlin said: 7/25/2012 at 5:08 PM

I'm not seeing a LinkManager.ascx anywhere in the Telerik.Web.UI.dll in version 6.4. Is this something only in a certain version of Sitecore? Or am I missing how to find that code entirely? All I can find is "LinkManagerDialog" in there using Reflector's search function.

Thanks!

Roger Willis said: 2/18/2014 at 8:55 PM

Brian, it's in the Resources folder at the bottom...
BTW... Pretty awesome TUT! I was trying to figure out a way to do this in Sitecore and this worked like a charm. Thanks!

Aware Web said: 2/19/2014 at 3:55 PM

Thanks Roger!