Tuesday, February 12, 2013

Tag, You're it: Tracking Tag Management in Sitecore

As web marketers, a great deal of our strategy relies on hunting (we'll leave farming tactics, like social media, nurturing and personalization, for another day). Most of our hunting activities rely heavily on tracking. The wiki definition of tracking (in the hunting context) fits this quite well:
Tracking in hunting and ecology is the science and art of observing animal tracks and other signs, with the goal of gaining understanding of the landscape and the animal being tracked (quarry).
For web marketers, hunting requires an understanding of the web ecosystem and the behavior of our "quarry" within it, so tracking is very important to us. There has been an explosion in tracking technologies of late, most of which are based on injecting tracking tags into our pages. Our pages have more tags hanging off them than the discount rack at Macy's --- so much so that tracking tag management has become a hot service offering. Just Google tracking tag management and you'll find more tools than you can count.

These tools can be appealing. After all, we have so much tag content that we need to manage on our site.

Wait a minute ... "content" ... "manage" ... hmmm --- aren't we already working in a content management environment?

There's no doubt that we could build a superb tracking tag management system into Sitecore. When we do a deep dive into these tagging technologies, we find that the formation and injection of tags into our pages can become quite complicated, but Sitecore is the best system around for building complex content management architectures.


Simple tracking tag management in Sitecore


But let's start off simple. When you first get into tagging, you find that at its simplest, all you have to do is copy a tag snippet (typically some javascript) into your pages. You find  new tracking service you want to use, you paste their snippet into your pages, and you're off.

Simple as that sounds, our marketers can't just do that themselves. They need the developers to deploy the tags to the production servers, typically within layouts. But marketeers want things done now ... so why don't we simplify this process by creating support for simple tag injection?

The solution I'll describe here is pretty rudimentary. It assumes that you are tagging every page on your site with every tag you have. That's fine for a start; over time, we'll examine ways to create dynamic tags and associate tags with content more robustly.

We'll create templates to allow the tag markup to be managed as Sitecore content. Since we want the tags on every page, we'll use a pipeline processor to inject them into every page (rather than relying on layouts).

You can download the source and package for this solution from the Sitecore Marketplace.


The templates


First, a couple of templates. We will create other tag types over time, but for now we'll just create a template for "Html Tracking Tag" that just holds some static tag markup. We'll also create a folder template to hold all of our tag items. This just a template with no fields, but with Standard Values set with insert options for our tag template.


The HtmlTrackingTag template is simple; it just contains a memo field to hold the tag markup.


We'll create a TrackingTagFolder in our content, wherever we manage "globals".


I've added a couple of tag items, which contain simple tag markup copied from that service's site.



The code


First, we'll need a configuration file to register up our pipeline and manage our settings:

<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
    <sitecore>
        <settings>
            <setting name="TrackingTags.GlobalTagFolder" value="/sitecore/content/Global/TrackingTags" />
        </settings>
        <pipelines>
            <insertRenderings>
                <processor
                    type="Arke.SharedSource.TrackingTags.Pipelines.InsertRenderings.InsertTrackingTags, Arke.SharedSource.TrackingTags"
                    patch:after="processor[@type='Sitecore.Pipelines.InsertRenderings.Processors.AddRenderings, Sitecore.Kernel']"
                    />
            </insertRenderings>
        </pipelines>
    </sitecore>
</configuration>

And we'll create an associated settings class to make it simpler to access our settings (we only have one for now, but it's good practice).

namespace Arke.SharedSource.TrackingTags
{
 public class Settings
 {
  public const string DEFAULT_GLOBAL_TAG_FOLDER = "/sitecore/content/Global/TrackingTags";
  public static string GlobalTagFolder
  {
   get
   {
    return Sitecore.Configuration.Settings.GetSetting("TrackingTags.GlobalTagFolder", DEFAULT_GLOBAL_TAG_FOLDER);
   }
  }
 
 }
}



To render the tags to the page, we'll create a simple web control that grabs the markup from the tag definition item and spits it to the page.

namespace Arke.SharedSource.TrackingTags
{
 public class HtmlTrackingTag : Sitecore.Web.UI.WebControl
 {
  System.Web.UI.WebControls.Literal container;
 
  public string TagItem { get; set; }
 
  protected override void OnInit(EventArgs e)
  {
   base.OnInit(e);
   container = new System.Web.UI.WebControls.Literal();
  }
 
  protected override void CreateChildControls()
  {
   Assert.IsNotNullOrEmpty(TagItem, "tag item");
   Item item = Sitecore.Context.Database.GetItem(TagItem);
   Assert.IsNotNull(item.Fields["Markup"], "Markup");
   string markup = item.Fields["Markup"].Value;
   container.Text = markup;
  }
 
  protected override void DoRender(HtmlTextWriter output)
  {
   EnsureChildControls();
   container.RenderControl(output);
  }
 
  protected override string GetCachingID() 
  { 
   return this.GetType().FullName; 
  }
 }
}

Finally, we'll use a pipeline processor to iterate over the global tags and inject a HtmlTrackingTag control into the page for each.

namespace Arke.SharedSource.TrackingTags.Pipelines.InsertRenderings
{
 public class InsertTrackingTags
 {
  public void Process(InsertRenderingsArgs args)
  {
   Assert.ArgumentNotNull(args, "args");
 
   if (Sitecore.Context.Site.Name == "shell")
   {
    return;
   }
 
   Item globalTagFolder = Sitecore.Context.Database.GetItem(Settings.GlobalTagFolder);
 
   Profiler.StartOperation("Adding Tracking Tags.");
 
   foreach (Item globalTagItem in globalTagFolder.Children)
   {
    Arke.SharedSource.TrackingTags.HtmlTrackingTag control = 
     new Arke.SharedSource.TrackingTags.HtmlTrackingTag();
    if (control != null)
    {
     control.TagItem = globalTagItem.ID.ToGuid().ToString();
     control.Cacheable = true;
     control.VaryByData = true;
     RenderingReference reference = new RenderingReference(control);
     reference.AddToFormIfUnused = true;
     args.Renderings.Add(reference);
     Tracer.Info(string.Concat("Added tracking tag '", globalTagItem.Name, "'"));
    }
   }
 
   Profiler.EndOperation();
  }
 }
}

Note from the config file that we're putting our processor before Sitecore's AddRenderings processor.This puts our renderings at the top of the body part of the page.

If you look at the page in debug mode, you can see the script tag renderings.




Shortcomings of this solution

Of course, this is a bit of a dangerous solution. We've enabled content managers to manually inject script into the page. Either by accident or intent, a content owner could wreak havoc on the site. The tag definitions in globals should have good security to limit access only to trusted power users.

As I said before, this is a pretty simple solution. The obvious next step is to create a place to store "ad hoc" tags, and a rendering parameter template for the HtmlTrackingTag control. This would allow content manager to insert specific tag into specific pages.

Beyond this, a much more robust solution would include templates for the well-known tags so they could be managed more easily (by pasting in specific parameters into specific fields, rather than the entire tag). Dynamic tags that modify their behavior depending on context, template or rendering parameters could be built as well.

This solution allows the easy things to be easy, and the hard things will just have to wait till later. At least now, when we identify a new tracking service we want to implement, its as simple as "tag, you're it".





The source code and package for this solution are available at the Sitecore Marketplace.


Friday, January 25, 2013

Render Unto c#


When it comes to CMS development (among other things in life) I’m a big fan of granularity and reusability. I believe that in a good solution architecture, both content and code are managed in discreet, granular pieces, which promotes both consistency and reusability.

That’s why it bothers me that so many Sitecore professionals react to the word “rendering” the same way a horse would. To my mind, a good solution has a geometric ratio of layouts to sublayouts, and sublayouts to renderings. Yet I see projects that are extremely sublayout-centric, with content IA and logic governing page layout.

Sitecore’s arsenal of presentation management tools, such as layout details, placeholder settings and rendering parameters, allows us as developers to truly empower our content owners. When implemented well, these features give the content authors what I like to call “controlled control” over their pages.

Unfortunately, we often see solutions where sublayouts are the dominant presentation component. Sublayouts are far less efficient than renderings, both in terms of performance and management. With sublayouts, there are all the ascx files to manage and deploy. And using sublayouts to present content seems to promote having a single component (sublayout) present multiple fields. This can dramatically reduce the solution’s flexibility – or worse, lead to having multiple components that are slight variations on each other, or have cumbersome logic (often wired to “control” fields in the content) to suppress content or change the presentation behavior.

Worse, some solutions rely almost entirely on the content tree to govern layout, such as by having fields in page templates that change the behavior of the layout, and/or by having sets of child items that code “bubbles up” into the page when they are present.

So why are renderings so often left out of solution architecture? I suspect that the problem lies in Sitecore training. Although Sitecore trainers do point out the different ways that renderings can be created, they tend to use XSL as the example technology in class (probably because it’s quicker to demonstrate --the trainer can show changes to an XSL rendering immediately, without compiling). Regrettably, this leaves many with a linkage in their minds between renderings as a Sitecore artifact and XSL as a technology. The oft-maligned rendering can be implemented using multiple technologies, yet many, many developers believe that renderings can only be developed using XSL.

I’m not going to wade into the great XSL debate here. I personally like XSL, but I rarely use it in Sitecore projects, for a number of reasons that I’ll get into that in a separate post. Suffice it to say that many developers, even if they know XSL, want to avoid it if for no other reason than to make their projects sustainable. XSL is a far more rare skill than c#, so it makes sense to ensure that future developers will be able to extend and maintain the project. And since there’s this misconception that “renderings = XSL”, the “baby” of a rendering-based architecture gets thrown out with the “bathwater” of XSL. And that’s a shame.

So let’s set the record straight. Renderings can and should be developed in c#. Actually, John West points out in his book “Professional Sitecore Development,” there are four types of renderings:
  1. XSL renderings
  2. Method renderings
  3. URL renderings
  4. Web Controls
Of these, Web Control renderings – controls that are implemented entirely in code and deployed in assemblies – are the least used yet most useful presentation component available. (In my next post, I’ll delve into the anatomy of a web control rendering.)

As a simple example, consider a page with a “core content” (“body”) area consisting of a title, a main image, and some body text. These three fields are defined in the page’s template. One way of handling this is to create a sublayout that renders these fields to the output (hopefully, at least, using field renderers). But what happens when the author does not want a title on a particular page (this is a simple example, so let’s not quibble over usability or SEO). Sure, the sublayout’s code-behind could suppress the <h1> when the field is empty or null. Or we could have a checkbox in the template to suppress the title.

What if the content author wants something other than a main image, like a flash or a video? What if they need to insert something between the image and the body? And after the body, they might need set of “spots” to point to other content?

So we might resort to having different sublayouts with variations on the content. This can lead to an unmanageable mess, creating confusion as to which sublayout does what. It also leads to redundant code, which makes ongoing maintenance and modification to the site much more challenging.

Another solution would be to put fields in the template to suppress content, or add content, or modify the presentation of content. Or we might create templates for child items that, when present, are bubbled up into the page. This puts management of presentation into the data. Sitecore is so well architected to give us excellent separation of content and presentation, so why fight that and force content to manage presentation?

I much prefer solutions that have very “light” layouts and sublayouts, with lots of renderings bound to placeholders. For the simple example, I would have a separate rendering each for title, main image, and body text, which I would bind to a placeholder in the sublayout for the core content area. Standard values in the item’s template would bind them by default, but the content owner would have the freedom to change the presentation as required. We can use features like thumbnails, rendering parameters, placeholder settings and compatible renderings both to assist them in the layout process, and to enforce brand or visual design requirements.

Most of my layouts and sublayouts are little more than div’s and placeholders. They exist to manage the geometry of the page or of regions of the page, not to present the actual content. Renderings bound to placeholders actually emit the content. Rendering parameter templates allow the editor to influence the source and behavior of the content in the page. Now, control over presentation and layout are managed in the presentation layer, and content is managed in the content layer. The design of the IA can break the content down into more manageable chunks, promoting reusability and avoiding redundancy.

To be fair, there are times when sublayouts are a better choice than renderings. For example, for forms or other situations where postback is required, I refer to use sublayouts (ascx) controls.. Also, in cases where the parts of the page structure are immutable, it is more efficient to statically bind renderings into sublayouts (by including them in the sublayout markup). This is fine for cases like fixed headers and footers, or when the site design requires an element (like a title) to always be present. There are also rare occasions when I allow a folder of child items to bubble up into a page, but even then, I usually use a placeholder-bound rendering to do the bubbling.

A highly granular architecture, which maintains separation of content from presentation, is hugely empowering to both developers and content editors. It promotes reusability of both code and content, shifts much of the responsibility for page assembly from code to configuration, and empowers editors with more control over the layout of their pages.

Thursday, January 17, 2013

Sitecore Solution Custom Configuration

No matter how many times I look at a Sitecore web.config  I inevitably find something I’ve never seen before, or had forgotten about, or never really understood. There’s such an abundance of settings, pipelines, hooks, events --- all kinds of ways to modify and extend the application.

Good solution architecture should follow that same approach. As much as is practical, functional components should expose custom configuration settings, which allow the solution to be tweaked and extended without the need to deploy code. This includes such thing as connection strings, service URLs and communication parameters, pick list options, content locations, task behaviors, UI factors … anything that code or users need to make decisions about how the application should work.
There are four key places where configuration options can be created and managed:
  1. Web.config
  2. Config files in the /App_Config/Include folder
  3. Sitecore content items (typically in a global “MetaData” or “Settings” node)
  4. Static code classes, exposed as enums, constants, properties or methods
There are other, more obscure methods as well. For example, an application initialization event could create application-scoped objects, or even modify the running config. Cool as all that may be, these techniques are only useful in unusual circumstances, and can complicate analysis and troubleshooting.

There is no single right way for configuration management in a solution; rather, any given configuration setting should be managed in the location that makes the most sense for that function.

Using web.config


It is best to avoid using web.config to store custom application settings. Generally speaking, only Sitecore platform specific configuration should be handled here. Settings embedded within web.config can be a nightmare when deploying and reconciling across environments.
All configuration within the Sitecore section of the web config can be extended and modified within .config files (below). Rather than placing settings in web.config, it is better to group related configuration items within .config files, making management, deployment and troubleshooting much easier.

Content owners cannot make changes to web.config, and developers might not be able to easily make changes here is some landscapes.

Web.config should be used only for very stable, solution-wide settings, and that, rarely (.config files can accomplish the same thing and are more manageable). Ideally, only Sitecore platform specific configuration – things that are part of the Sitecore release --- should be managed in web.config.

Using .config files


Sitecore allows any number of .config files to be created in the  /App_Config/Include folder. These config files require a specific XML structure, and are reconciled with web.config when Sitecore initializes, to create a “running config”. This running config represents what the web.config file would look like if all configuration were managed in one file.

Remember that Sitecore reconciles all of the .config files against web.config at application initialization. It is possible for two config files to modify the same configuration item, and it is difficult to predict what order the .config files will be applied.  Sitecore provides a utility at /sitecore/admin/showconfig.aspx to view the running config, which can be very helpful when troubleshooting.

Well organized .config files are a very powerful way to handle configuration, as related configuration item can be aggregated into a single file. Configuration for settings, pipeline processors, events, etc  can be added to the “running config” here, which has the same effect as modifying web.config, but in a more manageable way. Modifying existing web config entries in external .config files allows the solution to have ‘default” behavior defined in web.config while making server, landscape or application specific changes to be made in separate file in separate environments.

This is the ideal place to manage config in the following circumstances:
  1. The configuration modifies or extends an existing setting, event or pipeline in web.config.
  2. This configuration might need to have different values in different environments.
  3. The configuration related to a module or package that needs to be distributable.
  4. Only developers or administrators should be allowed to change the configuration.

Settings in these files should follow the Sitecore setting syntax.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
    <sitecore>
        <settings>
            <!—Items to fetch per connection -->
            <setting name="MyDataConsumer.ItemsToFetchPerConnection" value="10" />


Note the naming convention for the name of the setting node. Using the dotted notation (MySettingGroup.MySettingItem) creates a pseudo-namespace that prevents name collisions. Remember that all settings in config files are merged together into a single running config when Sitecore initializes. Every setting needs to have a unique name when the configs are merged.

 It is a good practice to create an associated class that exposes these settings through properties or static methods.

public static int ItemsToFetchPerConnection
{
       get
       {
              return Sitecore.Configuration.Settings.GetIntSetting(
                     MyDataConsumer.ItemsToFetchPerConnection", 0);
       }
}


Not only can .config files extend Sitecore configuration, but they can even change Sitecore configuration by using a patch attribute.  John West’s blog post, “All About web.config Include Files with the Sitecore ASP.NET CMS” discusses config patching, and includes links to more in-depth reading.

In most cases, developers can create and deploy config files, at least within the developer and QA environments. Of course, content authors generally can’t touch config files.

Using content items


It is common practice to have a global settings section of the content tree, usually (not below) the home node. This node is usually called something like “MetaData” or “Settings”.

This is a great place to manage configuration in these circumstances:
  1. The setting is always the same across all landscapes and environments.
  2. Content authors, editors or power users should be able to manage the setting.
  3. The setting relates to interface elements, like the items to be included in a pick list in a data template or rendering parameter template.

Settings stored here are very easy to manage, but there is also some risk. Whenever a setting can affect the stability of the application, there should be tighter control over who can change it. Using security can help protect these settings while allowing them to be managed in the Sitecore UI, but moving them to .config or static classes protects them from UI users altogether.

Rather than creating a template that contains all of the fields needed for a particular “set” of settings, I generally create a several generic “settings” templates, and use them to create items in grouped folders under a “settings” item at the root of the content tree. Some useful templates include: General (text), Link (for references to content items), WebService (with fields for the URL and credential info), and File (for media library file items).

Settings managed in content cannot have different values for CM and CD (unless you use two different items).

The nature of the setting also comes into play. When the setting represents a list of allowable values in a pick list in the content UI, this is really the only place to manage it (because the items in these lists are defined as data sources for the field). The danger is that these values often govern the behavior of code, and unexpected values can cause the code to throw errors. Again, security can help prevent unintended changes to these settings.

Using static classes


Settings in static classes (constants, properties or enums) is the best scenario from a performance perspective, but is also the least manageable method. Changes to these settings can only be accomplished with a code deployment.

This is a good approach for things that should only be changed when code is changing anyway, or only affect code. Static code configuration should also be considered when performance is a concern. For example, there are cases where a known predictable content item must be referenced frequently in code. Storing the GUID of this item in a static class makes the code much more efficient when accessing the item. If the GUID is unlikely to ever change, this is an excellent approach. Note that Sitecore exposes the Sitecore.FieldIDs and Sitecore.ItemIDs classes where the GUIDS of well-known items are stored.

In fact, this is a good way to “bootstrap” settings that are managed in the Sitecore content tree. Create a property in code with the GUID of the folder that contains the settings. This avoids hard-coding the location of the settings, and allows the settings to be accessed even if the location of the settings folder changes.

Settings location guidelines


 

web.config
Config file
Content item
Static class
Types (what does this setting affect?)
Part of the Sitecore platform
•
•
•
•
Related to code
•
•
•
Related to infrastructure
•
Related to content
•
Roles (who manages this setting?)
Developer
•
•
•
System administrator
•
•
Site architect
•
•
•
Business owner
•
Environments (CM vs CD)
Same on all environments
•
•
•
•
Different in each environment
•
Volatility (how often does it change?)
Frequently
•
Infrequently
•
•
•
Risk (impact of a mistake)
Changes affect entire application
•
•
•
Changes affect part of the application
•
•
Changes affect availability of data
•
•
Changes are cosmetic or content only
•
•




More reading...