Using the Delegate Control to Add Meta Tags to SharePoint Pages

It has been a while since I last blogged about SharePoint. I have been busy working on other things in the little free time that I have. I collaborated on an article that is in the February edition of MSDN magazine. I also have been working on getting Snip-It Pro, a manager for snippets, ready for a beta at the end of the month.

Anyway, I came up with a cool and easy way of getting Meta tags into SharePoint pages that are part of a document library. Meta tags are html tags that appear in the head of a html page and are used a lot with Search Engine Optimization also known as SEO.

Without this feature, you are basically stuck adding meta information using SharePoint designer, either by adding a set of global tags to the master page or over-ridding the “PlaceHolderAdditionalPageHead” content placeholder on each page. There is no easy way to modify the meta tags without SharePoint Designer.

If you look at the actual master page, you will notice there is a Delegate control in the head element right below the “PlaceHolderAdditionalPageHead.” For those who do not know, a Delegate control is a very cool SharePoint control that allows you to inject or replace the contents at run time using a SharePoint feature.

Leveraging this Delegate Control, I built a custom sharepoint feature that will inject several different types of meta tags into document library pages that have specific columns defined. This enables content managers to edit the properties of document and define any of the following meta tags:

  • Meta Keywords
  • Meta Description
  • Meta Author
  • Meta Copyright
  • Meta Robots
  • Meta Expiration
  • Meta Refresh

The code is actually pretty simple. It’s a custom web control that looks to see if the file is an item with fields that match any of the above names:

public class MetaTagger : WebControl
  private const string KeywordKey = "Meta Keywords";
  private const string DescriptionKey = "Meta Description";
  private const string AuthorKey = "Meta Author";
  private const string RobotsKey = "Meta Robots";
  private const string CopyrightKey = "Meta Copyright";
  private const string ExpirationKey = "Meta Expiration";
  private const string RefreshKey = "Meta Refresh";

  protected override void Render(System.Web.UI.HtmlTextWriter writer)
    if (SPContext.Current != null)
      SPFile file = SPContext.Current.File;
      if (file.Item != null)
        if (file.Item.Fields.ContainsField(KeywordKey) && 
          file.Item[KeywordKey] != null && 
          file.Item[KeywordKey].ToString() != string.Empty)
          writer.Write(string.Format(@"<META name=""keywords"" 
          content=""{0}"">", file.Item[KeywordKey].ToString()));

        if (file.Item.Fields.ContainsField(DescriptionKey) && 
          file.Item[DescriptionKey] != null && 
          file.Item[DescriptionKey].ToString() != string.Empty)
          writer.Write(string.Format(@"<META name=""description"" 
          content=""{0}"">", file.Item[DescriptionKey].ToString()));
        if (file.Item.Fields.ContainsField(AuthorKey) && 
          file.Item[AuthorKey] != null && 
          file.Item[AuthorKey].ToString() != string.Empty)
          writer.Write(string.Format(@"<META name=""author"" 
          content=""{0}"">", file.Item[AuthorKey].ToString()));
        if (file.Item.Fields.ContainsField(RobotsKey) && 
          file.Item[RobotsKey] != null && 
          file.Item[RobotsKey].ToString() != string.Empty)
          writer.Write(string.Format(@"<META name=""robots"" 
          content=""{0}"">", file.Item[RobotsKey].ToString()));
        if (file.Item.Fields.ContainsField(CopyrightKey) && 
          file.Item[CopyrightKey] != null && 
          file.Item[CopyrightKey].ToString() != string.Empty)
          writer.Write(string.Format(@"<META name=""copyright"" 
          content=""{0}"">", file.Item[CopyrightKey].ToString()));
        if (file.Item.Fields.ContainsField(ExpirationKey) && 
          file.Item[ExpirationKey] != null &&
          file.Item[ExpirationKey].ToString() != string.Empty)
          writer.Write(string.Format(@"<META http-equiv=""expires"" 
          content=""{0}"">", file.Item[ExpirationKey].ToString()));
        if (file.Item.Fields.ContainsField(RefreshKey) && 
          file.Item[RefreshKey] != null && 
          file.Item[RefreshKey].ToString() != string.Empty)
          writer.Write(string.Format(@"<META http-equiv=""refresh"" 
          content=""{0}"">", file.Item[RefreshKey].ToString()));

Although the web control is simple enough, the beauty of it is that is injected automatically into the AdditionalPageHead Delegate control which is part of the default Master Page. This is accomplished through a feature. Here is the feature.xml

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns=""
  Title="Meta Tagger"
  Description="Injects Meta Tags into AdditionalPage Head Delegate Control"
    <ElementManifest Location="MetaTaggerSettings.xml"/>

And the following is the content of the MetaTaggerSettings.xml:

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="">
  <Control Id="AdditionalPageHead" Sequence="50"
    ControlAssembly="MetaTagger, Version=, Culture=neutral,
    PublicKeyToken=576bc1a4564a5293" />

I have packaged everything into a solution package (wsp) file which you can download by clicking here.

Once the feature is activated you will just need to add custom columns to the document libraries for each of the Meta Tag types you want to be able to add using the properties. The column names need to be exactly the same as the one's in the bullet list.

Snip-It Pro Released

Published in the February Issue of MSDN Magazine