Tuesday, March 12, 2013

The Heart of the Meta

This article describes Arke System's Meta Tag Manager shared source module, available for free download from the Sitecore Marketplace.




Update 27-March-2013: Several changes have been made to this module, including adding new tag types (properties), adding support for all tag types in the pipeline, and creating "Custom Tags" to replace the less intuitive "Dynamic Processors"). See the documentation file in the Sitecore Marketplace for details.
It's almost inevitable that at some point in a solution's lifespan, there comes a need to add various types of meta tags to the head of your pages. Sometimes it's site-wide tags like turning off the silly IE image toolbar (thankfully a legacy issue now). Sometimes it's something you may need at the page level, like instructing robots not to crawl the page. Sometimes the tag values are static, like a robot directive  Sometimes they're dynamic, like page type (template), GUID or other info needed by crawlers or page script. Sometimes the need is simple, sometimes there are very complex tagging requirements for analytics or search crawling.

I've found that over time, solutions wind up with meta tags being handled in dozens of ways ... sometimes in markup, sometimes in code-behind, sometimes in base layouts, sometimes in renderings, sometimes in handlers. Discovering the providence of a tag you find in the final HTML can be challenging.

Recently, a client was concerned about the S.E.O. ramifications of having identical pages at more than one URL on their Sitecore site (for example, with and without "/en" in the path). Having pages like this (or worse, internal links formed differently) can decrease search ranking. If the same page is at two URLs, and there are links to both, the "link juice" is diluted across those pages.

One way to overcome this is to issue a "canonical URL" meta tag. If you emit a meta tag with the same canonical URL on both pages, it informs the search engine which URL is "authoritative" for that page. The search engine will (theoretically) award all of the link juice to the canonical URL.

If you are using a common base layout class, the simplest thing to do would be to have the code-behind of that class hang the canonical meta tag in the page header. But in this case, the client did not have a common base layout.

This kind of thing has come up often enough that I was motivated to create a MetaTag management module. Different chunks of code need to create meta tags, and it’s not always convenient or even possible to limit the timing of meta tag generation to the layout.

This article only covers some highlight from the module. For more detail, see the full documentation at the Sitecore Marketplace.

Overview



Tags can be added four ways:

  1. By adding processors to the InjectMetaTags pipeline.
  2. In the content editor, by adding tag definitions to a GlobalTags folder (these tags appear site-wide).
  3. In the content editor, by selecting pre-defined tags in a field that can be added to any template (these tags appear on individual pages)
  4. In code, at any point in the page lifecycle. This allows code in layouts, sublayouts and renderings to add meta tags “ad hoc”.



Several tag "types" are support to simplify creation of tags in code or configuration:


  1. Static tags: Tags where both the name and value are static, such a “robots noindex”.
  2. Custom tags: Tags where either the name, value or both are generated by custom logic.
  3. Method tags: Tags where the name is static, and the value is derived from an existing static method.
  4. Property tags: Tags where the name is static, and the value is derived from an existing static property.

Method and Property tags allow creation of dynamic tags entirely in configuration, with no coding. These tags derive their values at runttime from existing methods or properties.


There seems to be two subspecies of meta tag markup, those that use a “property” attribute and those that use “name”. Both are still effectively name/value pairs. The “name” style tag seems to be more common, but notable sets of commonly-used tags (like OpenGraph tags) use the “property” structure. This module allows both styles.

Architecture


The module uses a collection of tag description objects (not markup) that persist through the page lifecycle. Tags are added to this collection in various ways, and are flushed to the head section of the page after pre-render. To flush the tags to the page, each is formed into a custom MetaTag control. 

No modifications to the solution’s code or markup are required; all of the artifacts and event hooks are created using pipeline processors added to the httpRequestBegin and insertRenderings pipelines.

Adding Tags From Code


Coders can add tags to the page in any point in the page lifecycle, using provided convenience methods.

    PageTags.AddTag(MetaTagType.name, "MyTag""This is my tag.");

Managing Tags in the Content Editor


Site administrators can create site-wide tags by adding "StaticMetaTag" and "DynamicMetaTag" items to the appropriate folder in the Modules section of the content tree. Items added to the "GlobalTags" folder are emitted on every page; items added to the "OptionalTags" folder are available for content authors to use selectively in their pages (see below).


The definition of a StaticMeta tag is simple; just specify the tag type ("name" or "property"), and the key and value.


To define a dynamic tag, you must first create a simple "Dynamic Processor" class that exposes properties for TagType, Key and Value. Sample Dynamic Processors are provided that emit tags for the Item ID, Template Key and Machine Name. Once this class is defined, you can add it by creating a DynamicMetaTag item and supplying the class signature for the dynamic processor.


namespace Arke.SharedSource.MetaTags.DynamicProcessors
{
  public class ItemID : IDynamicProcessor
  {
    public MetaTagType TagType { getset; }
    public string Key { getset; }
    public string Value { getset; }
 
    public ItemID()
    {
      TagType = MetaTagType.name;
      Key = "ItemID";
      Value = Sitecore.Context.Item.ID.ToString();
    }
  }
}


A base template is provided, which can be added to the base templates of any site template. This gives the content author an opportunity to include the pre-defined tags (those defined n the OptionalTags folder) in any given page.



Managing Tags in the InjectMetaTags Pipeline


The process for gathering, forming and injecting tags is itself managed with a custom pipeline. Developers can add custom tags by inserting processors into this pipeline. They can also change the behavior of the process by replacing existing processors.
For more information on how to manage processes in your solutions by creating custom pipelines, see "Put That in Your Pipe and Process It"

In addition to the processors that gather the meta tags defined in content (global and page-scoped), there are  other "demonstrator" processor included in the module. One shows how to implement a fully custom meta tag processor, using the "canonical" meta tag as an example.

There are also processors that allow you to leverage your "Dynamic Processors" or any static method (including any Sitecore static method) to add a global meta, entirely in configuration, without writing a single line of code. This is accomplished by adding processor nodes that have child nodes the define class signatures and names of the processor or static method to be used. 

Here's and example of a meta tag pipeline in config (I've shortened the type names for readability):

<Arke.MetaTags.InjectMetaTags>
  <processor type="Arke...CheckContextItem, Arke.SharedSource.MetaTags" />
  <processor type="Arke...CheckHeader, Arke.SharedSource.MetaTags" />
  <processor type="Arke...CanonialUrl, Arke.SharedSource.MetaTags" />
  <processor type="Arke...MethodTag, Arke.SharedSource.MetaTags">
    <TypeSignature>Sitecore.Context, Sitecore.Kernel</TypeSignature>
    <MethodName>GetSiteName</MethodName>
    <TagName>sc_site</TagName>
    <TagType>name</TagType>
  </processor>
  <processor type="Arke...GlobalTags, Arke.SharedSource.MetaTags" />
  <processor type="Arke...ItemTags, Arke.SharedSource.MetaTags" />
  <processor type="Arke...FlushMetaTags, Arke.SharedSource.MetaTags" />
</Arke.MetaTags.InjectMetaTags>






The source code for this module is available at the Sitecore Marketplace. You can also download the documentation file.

No comments:

Post a Comment