MOSS MVP

I've moved my blog to http://blog.falchionconsulting.com!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Saturday, August 16, 2008

Enabling Audience Targeting on a List

I thought I was done documenting my audience related STSADM commands and then I realized that I had completely forgotten one.  The first audience related command I had created was to enable audience targeting on a list - I called it gl-listaudiencetargeting.  I needed this because my current project had tons of lists that that needed audience targeting turned on.  Eventually these lists were added via a Feature but initially I did it via the command line with STSADM so that we could get a demo put together.  The nice thing is that adding the code to the Feature became a no-brainer because the code was already tested so it became simple copy and paste.

So, how do you programmatically enable audience targeting?  When I first started on this I thought it would be easy as setting a property on the list because enabling it via the browser is as simple as setting a checkbox but turns out it's not quite that simple.  The way audience targeting works is that a "special" field is added to the list.  The field schema looks like this:

<Field ID="61cbb965-1e04-4273-b658-eedaa662f48d" Type="TargetTo" Name="TargetTo" DisplayName="Target Audience" Required="FALSE" />

Once we have this schema we can add the field to the list using the AddFieldAsXml method (member of the SPFieldCollection class which can be obtained via the lists Fields property):

   1: /// <summary>
   2: /// Sets the whether audience targeting is enabled or not.
   3: /// </summary>
   4: /// <param name="url">The URL.</param>
   5: /// <param name="enabled">if set to <c>true</c> [enabled].</param>
   6: public static void SetTargeting(string url, bool enabled)
   7: {
   8:     using (SPSite site = new SPSite(url))
   9:     using (SPWeb web = site.OpenWeb())
  10:     {
  11:         SPList list = Utilities.GetListFromViewUrl(web, url);
  12:  
  13:         if (list == null)
  14:             throw new SPException("List was not found.");
  15:  
  16:         SPField targetingField = GetTargetingField(list);
  17:         if (enabled && (targetingField == null))
  18:         {
  19:             string createFieldAsXml = CreateFieldAsXml();
  20:             list.Fields.AddFieldAsXml(createFieldAsXml);
  21:             list.Update();
  22:         }
  23:         else if (!enabled && (targetingField != null))
  24:         {
  25:             list.Fields.Delete(targetingField.InternalName);
  26:             list.Update();
  27:         }
  28:  
  29:     }
  30: }
  31:  
  32: /// <summary>
  33: /// Gets the targeting field.
  34: /// </summary>
  35: /// <param name="list">The list.</param>
  36: /// <returns></returns>
  37: private static SPField GetTargetingField(SPList list)
  38: {
  39:     SPField field = null;
  40:     try
  41:     {
  42:         field = list.Fields[new Guid("61cbb965-1e04-4273-b658-eedaa662f48d")];
  43:     }
  44:     catch (ArgumentException)
  45:     {
  46:     }
  47:     return field;
  48: }
  49:  
  50: /// <summary>
  51: /// Gets the field as XML.
  52: /// </summary>
  53: /// <returns></returns>
  54: private static string CreateFieldAsXml()
  55: {
  56:     XmlElement element = new XmlDocument().CreateElement("Field");
  57:     element.SetAttribute("ID", "61cbb965-1e04-4273-b658-eedaa662f48d");
  58:     element.SetAttribute("Type", "TargetTo");
  59:     element.SetAttribute("Name", "TargetTo");
  60:     element.SetAttribute("DisplayName", "Target Audiences");
  61:     element.SetAttribute("Required", "FALSE");
  62:     return element.OuterXml;
  63: }

The help for the command is shown below:

C:\>stsadm -help gl-listaudiencetargeting

stsadm -o gl-listaudiencetargeting


Enabling audience targeting will create a targeting column for the list. Web parts, such as the Content Query Web Part, can use this data to filter list contents based on the user's context.

Parameters:
        -url <list view url>
        -enabled <true|false>

The following table summarizes the command and its various parameters:

Command Name Availability Build Date
gl-listaudiencetargeting MOSS 2007 Released: 8/6/2008

Parameter Name Short Form Required Description Example Usage
url url Yes The URL to the list that you wish to enable audience targeting on.  This can be the URL to the root folder or to a specific list view. -url http://portal/lists/announcements

or

-url http://portal/lists/announcements/forms/allitems.aspx
enabled e Yes "true" to enable audience targeting, "false" to disable audience targeting.  Note that disabling audience targeting deletes the "Target Audience" field and therefore any data that may have been assigned to the field. -enabled true

The following is an example of how to enable audience targeting for an announcements list:

stsadm -o gl-listaudiencetargeting -url http://portal/lists/announcements -enabled true

3 comments:

skylark_28 said...

Thanks heaps this should clean up hte mess i have so far. One question thou. how can you pre populate the field with a group, say the site members so that targetting is on by default?

Gary Lapointe said...

Create an event receiver that adds the appropriate values to the field.

Martin Hatch said...

There's a bug in the code.

If you try to run this on a Pages Library then you get:

"Operation Invalid Due to the current state of the object"

You need to un-seal the field and set "AllowDeletion" to get it to work:

public static void SetTargeting(SPList list, bool enabled)
{
if (list == null)
throw new SPException("List was not found.");

SPField targetingField = GetTargetingField(list);
if (enabled && (targetingField == null))
{
string createFieldAsXml = CreateFieldAsXml();
list.Fields.AddFieldAsXml(createFieldAsXml);
list.Update();
}
else if (!enabled && (targetingField != null))
{
// make sure the field can be deleted!
targetingField.AllowDeletion = true;
targetingField.Sealed = false;
targetingField.Update();

list.Fields.Delete(targetingField.InternalName);
list.Update();
}
}