Adding metadata to your site collection for a complete, secure, refinement-enabled site directory on SharePoint 2007 and SharePoint 2010

DISCLAIMER: This post is provided AS IS with no warranties and confers no rights. This is not an official Microsoft solution.

In the past couple years, I’ve often gotten the question “how can I effectively find sites (collections) based on enterprise metadata?”.  For example, we may want to find all projects based on the organizational hierarchy, or the enterprise may have major company pillars that projects are based on, or to find all ‘XYZ-related’ projects, etc.

 

With SharePoint 2007, you could use the Site Directory feature which was providing a limited single-dimension listing site collections.  However, it doesn’t scale very well to 1000s of site collections and it’s not securely trimmed.  This feature is removed from SharePoint 2010 (except for upgrade scenarios).

 

My goal was to provide something for both 2007 and 2010 that brings more features and value.  Essentially, the ability to define metadata at the feature level (metadata for the whole organization), the site definition level (metadata for the template), and at the provisioning level (metadata based on provisioning questions).  Furthermore, site owners can edit property values through a standard web part on the site’s home page – with the ability to have read-only properties that are (re-)defined programmatically or through the feature.  Last, but not least, since the metadata is added directly on the site’s page, the results are securely trimmed to what your users can actually see.

 

The solution is effectively simple: provide a metadata definition that a web part can read, add META tags to the home page, and allow for user editing.  Search will be able to index those META tags from which administrators can create Managed Properties.  From there, the standard search results can then be refined (2010), or faceted (2007 with the Faceted search component from CodePlex, https://facetedsearch.codeplex.com/).  You can decide to provide custom interfaces with standard SQL Search development.

The solution logically resembles this:

Designing Site Collection IA

 

Physically, the solution requires a somewhat complex metadata definition that is essentially a class that is serialized in XML and stored in the SPSite.RootWeb.AllProperties.  This XML can be brought by the Site Definition or Feature properties, from which the Feature Receiver will read the properties and add them to the property bag; or it can be added through simple custom code.  This definition is complex due to providing features such as multilingual display names, allowing for read-only properties, etc.

 

Feature Properties

Here’s an excerpt of the sample Feature.xml:

 <Feature  Id="3aba9d3d-228a-443d-85b3-1f35d8aa6858"
           Title="[Maxime Bombardier] Site Collection Metadata Sample"
           Description="This is a feature that samples how to use the MaximeBSiteCollectionMetadata feature receiver and web part."
           Version="12.0.0.0"
           Hidden="FALSE"
           Scope="Site"
           DefaultResourceFile="core"
           xmlns="https://schemas.microsoft.com/sharepoint/"
           ReceiverAssembly="MaximeB.SharePoint.SiteCollectionMetadata, Version=1.0.0.0, Culture=neutral, PublicKeyToken=501530d13e13b1c5"
           ReceiverClass="MaximeB.SharePoint.SiteCollectionMetadata.MaximeBSiteCollectionMetadataFeatureReceiver"
           >
   <ActivationDependencies>
     <ActivationDependency FeatureId="6ede1ea7-4396-4cbc-b3f2-a757ca203463" />
   </ActivationDependencies>
  
  
   <Properties>
  
  
     <Property Key="MetaDef-ConfidentialInformation" Value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;
 &lt;SiteCollectionMetadataDefinition xmlns:xsi=&quot;https://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd=&quot;https://www.w3.org/2001/XMLSchema&quot;&gt;
   &lt;Name&gt;ConfidentialInformation&lt;/Name&gt;
   &lt;AllowEditing&gt;true&lt;/AllowEditing&gt;
   &lt;DataType&gt;TrueFalse&lt;/DataType&gt;
   &lt;Value&gt;true&lt;/Value&gt;
   &lt;Choices /&gt;
   &lt;DisplayNames&gt;
     &lt;SiteCollectionMetadataDisplayName&gt;
       &lt;Code&gt;1036&lt;/Code&gt;
       &lt;Text&gt;Information confidentielle&lt;/Text&gt;
     &lt;/SiteCollectionMetadataDisplayName&gt;
     &lt;SiteCollectionMetadataDisplayName&gt;
       &lt;Code&gt;1033&lt;/Code&gt;
       &lt;Text&gt;Confidential Information&lt;/Text&gt;
     &lt;/SiteCollectionMetadataDisplayName&gt;
   &lt;/DisplayNames&gt;
 &lt;/SiteCollectionMetadataDefinition&gt;" />
  
     <Property Key="MetaDef-Region" Value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;
 &lt;SiteCollectionMetadataDefinition xmlns:xsi=&quot;https://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd=&quot;https://www.w3.org/2001/XMLSchema&quot;&gt;
   &lt;Name&gt;Region&lt;/Name&gt;
   &lt;AllowEditing&gt;true&lt;/AllowEditing&gt;
   &lt;DataType&gt;Choices&lt;/DataType&gt;
   &lt;Value&gt;North America&lt;/Value&gt;
   &lt;Choices&gt;
     &lt;string&gt;North America&lt;/string&gt;
     &lt;string&gt;Europe&lt;/string&gt;
     &lt;string&gt;Canada&lt;/string&gt;
   &lt;/Choices&gt;
   &lt;DisplayNames&gt;
     &lt;SiteCollectionMetadataDisplayName&gt;
       &lt;Code&gt;1036&lt;/Code&gt;
       &lt;Text&gt;Region&lt;/Text&gt;
     &lt;/SiteCollectionMetadataDisplayName&gt;
     &lt;SiteCollectionMetadataDisplayName&gt;
       &lt;Code&gt;1033&lt;/Code&gt;
       &lt;Text&gt;Region&lt;/Text&gt;
     &lt;/SiteCollectionMetadataDisplayName&gt;
   &lt;/DisplayNames&gt;
 &lt;/SiteCollectionMetadataDefinition&gt;" />
  
  
     <Property Key="MetaDef-ProjectName" Value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;
 &lt;SiteCollectionMetadataDefinition xmlns:xsi=&quot;https://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd=&quot;https://www.w3.org/2001/XMLSchema&quot;&gt;
   &lt;Name&gt;ProjectName&lt;/Name&gt;
   &lt;AllowEditing&gt;true&lt;/AllowEditing&gt;
   &lt;DataType&gt;Text&lt;/DataType&gt;
   &lt;Value&gt;Site Collection Metadata Project&lt;/Value&gt;
   &lt;Choices /&gt;
   &lt;DisplayNames&gt;
     &lt;SiteCollectionMetadataDisplayName&gt;
       &lt;Code&gt;1036&lt;/Code&gt;
       &lt;Text&gt;Nom de projet&lt;/Text&gt;
     &lt;/SiteCollectionMetadataDisplayName&gt;
     &lt;SiteCollectionMetadataDisplayName&gt;
       &lt;Code&gt;1033&lt;/Code&gt;
       &lt;Text&gt;Project Name&lt;/Text&gt;
     &lt;/SiteCollectionMetadataDisplayName&gt;
   &lt;/DisplayNames&gt;
 &lt;/SiteCollectionMetadataDefinition&gt;" />
  
  
     <Property Key="MetaDef-Model" Value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;
 &lt;SiteCollectionMetadataDefinition xmlns:xsi=&quot;https://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd=&quot;https://www.w3.org/2001/XMLSchema&quot;&gt;
   &lt;AllowEditing&gt;false&lt;/AllowEditing&gt;
   &lt;DataType&gt;Text&lt;/DataType&gt;
   &lt;Value&gt;Collaboration Team Site by Maxime&lt;/Value&gt;
   &lt;Name&gt;Model&lt;/Name&gt;
   &lt;Choices /&gt;
   &lt;Active&gt;true&lt;/Active&gt;
   &lt;DisplayNames&gt;
     &lt;SiteCollectionMetadataDisplayName&gt;
       &lt;Code&gt;1033&lt;/Code&gt;
       &lt;Text&gt;Model&lt;/Text&gt;
     &lt;/SiteCollectionMetadataDisplayName&gt;
     &lt;SiteCollectionMetadataDisplayName&gt;
       &lt;Code&gt;1036&lt;/Code&gt;
       &lt;Text&gt;Modele&lt;/Text&gt;
     &lt;/SiteCollectionMetadataDisplayName&gt;
   &lt;/DisplayNames&gt;
 &lt;/SiteCollectionMetadataDefinition&gt;" />
  
   </Properties>
 </Feature>

 

The complexity of the definition comes from the limitation of storing in the AllProperties property bag : it’s a simple name/value collection so I need to store text.  If you look carefully, the definition is actually encoded Xml with the following properties: Active, AllowEditing, DataType, Value, Name, Choices, and DisplayNames.

Note: you need to paste it as-is, I had some issues when adding spaces/tabs.

 

Site Definition Properties

At the site definition, it’s basically the same concept:

       <SiteFeatures>
 ... removed ...
  
         <!-- Site Collection Metadata -->
         <Feature ID="6ede1ea7-4396-4cbc-b3f2-a757ca203463" />
  
         <!-- Site Collection Metadata Sample -->
         <Feature ID="3aba9d3d-228a-443d-85b3-1f35d8aa6858">
           <Properties xmlns="https://schemas.microsoft.com/sharepoint/">
             <Property Key="MetaDef-SiteOwnerName" Value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;
 &lt;SiteCollectionMetadataDefinition xmlns:xsi=&quot;https://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd=&quot;https://www.w3.org/2001/XMLSchema&quot;&gt;
   &lt;Name&gt;SiteOwnerName&lt;/Name&gt;
   &lt;AllowEditing&gt;true&lt;/AllowEditing&gt;
   &lt;DataType&gt;Text&lt;/DataType&gt;
   &lt;Value&gt;Maxime Bombardier&lt;/Value&gt;
   &lt;Choices /&gt;
   &lt;DisplayNames&gt;
     &lt;SiteCollectionMetadataDisplayName&gt;
       &lt;Code&gt;1033&lt;/Code&gt;
       &lt;Text&gt;Site Owner Name&lt;/Text&gt;
     &lt;/SiteCollectionMetadataDisplayName&gt;
   &lt;/DisplayNames&gt;
 &lt;/SiteCollectionMetadataDefinition&gt;" />
  
  
 ... removed ...

 

Custom Code Properties

From a custom code perspective, I provided managers to create, serialize, and deserialize these properties, and I also provide a simple Windows application from which you can define your properties, copy them to clipboard, and paste them in your Site Definition or Feature properties.  These managers can be found with the namespace MaximeB.SharePoint.SiteCollectionMetadata.SiteCollectionMetadataDefinitionManager.  If you create a MaximeB.SharePoint.SiteCollectionMetadata.SiteCollectionMetadataDefinition and pass it to the GetStringFromMetadata method, you can store the returning value in the SPSite.RootWeb.AllProperties with a key that starts with “MetaDef-“ and it will automatically work with the Web Part.

 

The solution supports for these data types:

  • Text
  • Choice (single selection, dropdown list)
  • Yes/No (checkbox)
  • Date (displayed as Text, planning to upgrade this in the future)

 

Solution Download

The solution code can be found here: 

while the Web Part’s WSP can also be found here :

.  Note that the solutions are with Visual Studio 2008 as I needed the solution to work with SharePoint 2007.  I also used WSPBuilder 1.0.6 : https://wspbuilder.codeplex.com/.

The solution contains the following projects:

  • RedirectHomePageForSearch: in some instances with SharePoint 2010, the default page is not returned in the search results – it’s replaced by the site’s URL (i.e.: https://contoso versus https://contoso/default.aspx).  The trouble is that when you edit the page, only the https://contoso/default.aspx will be re-indexed by an incremental crawl.  This project simply adds a feature that you can activate which will create a redirect page as your welcome page, which will redirect to your ‘previous’ welcome page.  You may not need that depending on your results.
  • SiteCollectionMetadata : This is the main project that defines the metadata functionality, provides the Web Part, and packages this in a WSP.  This is the only required solution.
  • SiteCollectionMetadataSample : This is a sample project with properties defined at the site definition and feature definition levels.
  • SiteCollectionMetadataSerializationTester : This is a Windows Application that allows you to create your property definitions and paste them in a Site Definition or Feature definition.

Here’s what the Windows Application looks like:

image

 

Sample usage

Here’s a quick list of properties that can be practical:

  • Project Name
  • Description / Keywords
  • Classification level (low/medium/high business impact)
  • Technologies (list)
  • Region/Country
  • Company pillars / main themes
  • Year / Date
  • Start/End dates
  • Customer name
  • Site model name (i.e.: if you have multiple ‘project’ templates but want to aggregate them to target content)
  • Model version
  • Team, Manager, “Hierarchy” names
  • In theory, you could also create a ‘My Workspaces’ web part based on this metadata and a custom search query.  

(if you have more, add to comments!)

The flexibility of the model is practical.  Some enterprise may use a common template for projects, but they want to have a different look per business divisions, and they’d like to target content to each of them.  You could either have a custom provisioning process, or a custom site definition that defines which business division it’s in, and your ‘content/communication’ web part would be able to use the values and target content accordingly.

 

Note that you’ll have to create Managed Properties, and/or make the properties searchable, to use them with Search.  Also, when you add a new Managed Property, it requires a Full Crawl until it takes effect on all pages.  However, any updates on the metadata will be picked through an incremental crawl.

 

What happens when I activate/deactivate the feature?

When the feature’s activated, it will go through the feature and site definitions to sync properties.  If the property is already defined, and it allows editing, the definition will be updated but the value will remain the ‘old’ one.  If the property doesn’t allow editing, the definition and value will be updated.

 

When the feature is deactivated, the definitions will remain, however, the Active property will be set to False, effectively removing all META tags upon a subsequent crawl.  Reactivating the feature will reset the definition to Active by default.

 

Recap – what do I really need?

Last, a recap on what you need to do :

  • Deploy the WSP which will add a DLL in the GAC and a feature that adds the Web Part
  • (Optional) Define metadata in the feature’s property definition, or in the Site Collection’s feature activation property definition.
  • (Optional) Define metadata through code, at or after the site collection provisioning process.  Note that they can be combined.
  • Note: while the last 2 steps are optional, you have to use one of them if you want metadata! Smile
  • Add the SiteCollectionMetadata Web Part on one of your site collection page (typically the home page).  You should remove its title display so that visiting users do not see it.
  • Crawl the pages that defines new properties (at the least)
  • Define Managed Properties for the newly found properties
  • Recrawl the pages (or do a Full crawl, easier if you can)
  • (Optional) Consume the properties through a customized search tab, either with refinements or facets, or through keyword search.

 

What’s next

  • Get feedback and act on it
  • Update code with error handling and comments
  • Support for date data type
  • Support for multi-select dropdown
  • Support for cascading dropdowns (which would require AJAX)