I recently worked on an interesting issue with SharePoint 2010 Content Types. The specific request was the following:

A request to create an additional Content Type in a Document Library that wasn’t visible to other Document Libraries within a Site Collection.

This sounds easy but is a little more complex because when you create a content type at the site collection level, it’s automatically available to all other list and document libraries within the specified site collection. The original request was to prevent the content type from being visible to other Document libraries. The traditional method of simply creating a content type at Site Collection and adding it to preferred Document Library isn’t going to work. The original plan was to only pull from content types available on the Document Library.

The following PowerShell script was used to create an additional content type that’s available on that specific Document Library:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$SiteURL= "http://<serverName>"
$Library = "Shared Documents"
$site = new-object Microsoft.SharePoint.SPSite($SiteURL)
$web = $site.OpenWeb()
$lib = $web.Lists[$Library]
$item = $lib.ContentTypes["Item"];
$ct = new-Object Microsoft.SharePoint.SPContentType($item,$lib.ContentTypes,"TestContentType")
$lib.ContentTypes.Add($ct)

This works in that I can only see my newly created content type “TestContentType” within the specified Document Library.

 

 

Problem

This exposed a new problem working with word documents and the new content type. The following steps provide more detail:

1. When selecting a new Document, select the new Content Type:

 

2. Put some random text in the document and save it back to Document Library.

The expectation is that the document is saved using the “new” TestContentType. In this scenario, it doesn’t and uses the Default Document Content type. This is true even if the TestContentType is marked as default. Viewing properties on the Document displays the following:

Looking further at the newly created content type:

 

In the above screenshot, the Source is Item and no Document Source is present. When creating Word Documents via additional content types, the Content Type used must be derived from base Document content type. If you use a Content Type derived from Item, this by design behavior will occur in Document Libraries.

From MSDN:  http://msdn.microsoft.com/en-us/library/ms463016.aspx

“However, it is important to know that you cannot add every content type that is available in a given site to every list or library in the site. Any content type that you add to a document library must inherit from the built-in Document content type or from a content type that is derived from Document.”

 

Question: How can I create a content type derived from Document without using the content types available at the Site level?

Answer: You can’t if the Document Library is already created. The Document Content Type is already in use “Default Document Content Type” by default. Some advanced steps make it possible to add additional content types only available to a particular Document Library. However, it’s tedious and outside the scope of this blog.

 

First, thanks goes out to my colleague Gyorgy at Microsoft for tipping me off about the hidden group. The solution is to create a new Content Type at the site collection level and add it to the Hidden Group. The hidden group is a special group in that any content types moved there will not be visible to any list or document library.

Solution 1: Using the UI

Create a new content type

1. Access Site, Site Actions, and Site Settings
2. Under category Galleries, select Site content types
3. Select Create and Type in a Name for your content type
4. Under Select parent content type from: choose Document Content Types
5. Under Parent Content Type: choose Document
6. Under Existing Group: choose Document Content Type

It should look like this before hitting OK:

 

 Add new content type to Document Library

1. Access the Document Library and choose Library from the ribbon
2. Select Library Settings, Advanced Settings
3. Ensure that Allow management of content types is set to Yes and hit OK
4. Back to library settings page, under Content Types select “Add from existing site content types”
5. Choose the newly created content type, add, and hit OK


Move Content type into Hidden Group

1. Access Site, Site Actions, and Site Settings
2. Under category Galleries, select Site content types
3. Find and click on the newly created content type
4. Within ManageContentType.aspx select Name, description, and group
5. Select New Group and type _Hidden and hit OK

Note: This is case sensitive so it must look like: _Hidden

After the above steps, the content type is hidden and should not be visible when attempting to add it to new document libraries using the UI. Also, you can’t manipulate the content type within Site Content Types because it’s hidden. Solution 1 is good for one time use.

 

Question: What if this is a hidden content type that you add it to document libraries after it’s already marked as hidden in the future?

Answer: To add a hidden content type to additional document libraries requires custom code.

 

Solution 2: Leverage the Object Model

I’m not a big fan of solution 1 because usually the same content type will be added more than once. I decided to write a C# application that can do all of this for you.

Note: If option 2 is selected, you must know the name of the hidden content type so keep all hidden content type names in a safe location you can refer to by name at a later date.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;

namespace Content
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Enter the name of your site and press enter");
            string siteurl = Console.ReadLine();

            using (SPSite site = new SPSite(siteurl))
            {
                using (SPWeb web = site.OpenWeb())
                {

                  //Check to see if we should just create a content type
                 //or move on to add one that's already created

                 Console.WriteLine("Press 1 to create a hidden Content Type and add it to
                                                     a Document Library");

                 Console.WriteLine("Press 2 to add a previously created hidden Content Type
                                                     to a Document Library");
                    
                 int result = int.Parse(Console.ReadLine());

                 
                 if (result == 1)
                    {
                        Console.WriteLine("Enter the name of your ContentType");
                        string ctName = Console.ReadLine();

                        // Create a new site content type.
                        SPContentTypeCollection cts = web.ContentTypes;
                        SPContentType ct = new SPContentType
                        (cts[SPBuiltInContentTypeId.Document],cts, ctName);

                         // Add the content type to the site collection.
                        cts.Add(ct);
                        Console.WriteLine(
                        "Added {0} content type to site collection.", ct.Name);

                        //Put the content type in group _Hidden
                        ct.Group = "_Hidden";
                        ct.Update();

                        Console.WriteLine("Type the name of the Document Library you want
                                                             to add it to and press Enter key.");
                       
                        string doclib = Console.ReadLine();
                        SPList list = web.Lists[doclib];

                        SPDocumentLibrary oDocumentLibrary = (SPDocumentLibrary)list;
                        oDocumentLibrary.ContentTypesEnabled = true;

                        Console.WriteLine("Adding new hidden Content Type to Document
                                                             Library");
                       
                        SPContentType lstCT = oDocumentLibrary.ContentTypes.Add(ct);
                        list.Update();
                        Console.WriteLine("Operation Completed Successfully");
                    }


                    else if (result == 2)
                    {
                        Console.WriteLine("Please enter the Content Type name now");
                        string hiddenct = Console.ReadLine();

                        Console.WriteLine("Enter the name of the Document Library where the 
                                                             Content Type will be added.");
                       
                        string Dirk = Console.ReadLine();

                        SPList list2 = web.Lists[Dirk];
                        SPDocumentLibrary oDocumentLibrary = (SPDocumentLibrary)list2;
                        oDocumentLibrary.ContentTypesEnabled = true;

                        //Pull the Content Type from hidden group
                        SPContentType cthid = web.AvailableContentTypes[hiddenct];

                        //Adding hidden content type to Document Library
                        Console.WriteLine("Adding hidden content type to Document Library");
                        oDocumentLibrary.ContentTypes.Add(cthid);
                        list2.Update();

                        Console.WriteLine("Operation completed successfully");

                    }

                    else
                    {
                       Console.WriteLine("Please run the application again and choose option
                                                           (1 or 2)");
                    }
                 }
            }
        }
    }
}

 

I'm starting a blog series in which I'll be providing Power Shell scripts that do various things in SharePoint 2010.  The first topic in the PowerShell Scripting series is a script that allows you to create a content type derived from Document and mark it as hidden while adding it to a document library.  The second part of the script will provide the ability to add hidden content types previously created to additonal document libraries.  The script can be pulled from here

Thanks,

-RussMax