Working with content types
Each SharePoint site uses content types, a site comes pre-populated with a set of content types and a set of lists and libraries that use these content types. You can also create your own content types, either being a site content type or list content type. A site content type can be reused across multiple lists in the site collection and this is the preferred model.
In the remainder of this article you'll see a lot of context
use: in this case this is a PnPContext
which was obtained via the PnPContextFactory
as explained in the overview article and show below:
using (var context = await pnpContextFactory.CreateAsync("SiteToWorkWith"))
{
// See next chapter on how to use the PnPContext for working with content types
}
Getting content types
To get the existing content types you need to load the site's ContentTypes collection or the list's content type collection.
// Get site content types, also load the content types field links in one go
await context.Web.LoadAsync(p => p.ContentTypes.QueryProperties(p => p.Name, p => p.Description,
p => p.FieldLinks.QueryProperties(p => p.Name)));
var contentTypes = context.Web.ContentTypes;
// Get list content types
var contentTypes = (await context.Web.Lists.GetByTitleAsync("Documents", p => p.ContentTypes)).ContentTypes;
foreach (var contentType in contentTypes.AsRequested())
{
// do something
}
Adding content types
Adding a content type is done by using one of the Add methods on the site's ContentTypes collection or the list's content type collection. When adding a content type you need to specify a content type id as explained in the Content Type IDs documentation.
Note
Before you can add content types to a list the list needs to be enabled for content types by setting the ContentTypesEnabled property to true.
// Add a site content type
var contentType = await context.Web.ContentTypes.AddAsync("0x0100302EF0D1F1DB4C4EBF58251BCCF5968F", "MyContentType");
// Add a list content type, start with getting a reference to the list
var list = await context.Web.Lists.GetByTitleAsync("Documents", p => p.ContentTypes);
// Ensure content type are enabled for the list
list.ContentTypesEnabled = true;
await list.UpdateAsync();
// Add the content type
await list.ContentTypes.AddAsync("0x0100302EF0D1F1DB4C4EBF58251BCCF5968F", "MyContentType");
Adding site fields to a site content type
Once the content type is added you typically also want to add fields to it, this is done by adding the needed field links in the content type's IFieldLinkCollection via the AddAsync
methods.
// Get site content types, also load the content types field links in one go
await context.Web.LoadAsync(p => p.Fields, p => p.ContentTypes.QueryProperties(p => p.Name, p => p.Description,
p => p.FieldLinks.QueryProperties(p => p.Name)));
// Get the content type to update
var contentType = context.Web.ContentTypes.AsRequested().FirstOrDefault(p => p.Name == "MyContentType");
// Get the field to add to the content type
var field = context.Web.Fields.AsRequested().First(p => p.InternalName == "myField");
// Add existing field with internal name "MyField" to the content type's field link collection as a required field
await contentType.FieldLinks.AddAsync(field, required: true);
Adding fields to a list content type
Once a content type has been added to a list you can also add list fields to that content type, the flow is similar to adding site fields but this time the list field collection is queried.
// Add a list content type, start with getting a reference to the list
var list = await context.Web.Lists.GetByTitleAsync("Documents", p => p.ContentTypes, p => p.Fields);
// Get the content type to update
var contentType = list.ContentTypes.AsRequested().FirstOrDefault(p => p.Name == "MyContentType");
// Get the field to add to the content type
var field = list.Fields.AsRequested().First(p => p.InternalName == "myField");
// Add existing field with internal name "MyField" to the content type's field link collection as a required field
await contentType.FieldLinks.AddAsync(field, required: true);
Getting and setting the content type order in the list "New" menu
When you add content types to a list they're added as last content type in the "New" menu of the list. Sometimes you however want to have your custom content type(s) be the first ones and that can be done by getting the current content type order via one of the GetContentTypeOrder
methods on IList
. You'll get a list containing the content type id's in the current order, after reordering this list you can update the content type order via using the ReorderContentTypes
methods on IList
.
// Ensure content type are enabled for the list
var myList = await context.Web.Lists.GetByTitleAsync("MyList");
myList.ContentTypesEnabled = true;
await myList.UpdateAsync();
// Add existing content type (contact)
var addedContentType = await myList.ContentTypes.AddAvailableContentTypeAsync("0x0106");
// Now we should have two content types added to the list, let's check their order
var contentTypeOrder = await myList.GetContentTypeOrderAsync();
// turn around the order
List<string> newContentTypeOrder = new List<string>();
// First add the currently last content type
newContentTypeOrder.Add(contentTypeOrder.Last());
// Add the remaining content types
foreach(var contentTypeId in contentTypeOrder)
{
if (!newContentTypeOrder.Contains(contentTypeId))
{
newContentTypeOrder.Add(contentTypeId);
}
}
// Update the content type order of this list
await myList.ReorderContentTypesAsync(newContentTypeOrder);
Updating content types
Updating a content type comes down to getting a reference to the content type to update, update the needed properties and call the UpdateAsync method.
await context.Web.LoadAsync(p => p.ContentTypes.QueryProperties(p => p.Name, p => p.Description,
p => p.FieldLinks.QueryProperties(p => p.Name)));
var contentTypes = context.Web.ContentTypes;
// Get the content type to update
var contentType = contentTypes.AsRequested().FirstOrDefault(p => p.Name == "MyContentType");
// Update the content type
contentType.Description = "PnP Rocks!";
await contentType.UpdateAsync();
// Adding a new field to the existing content type, mark it as required
await contentType.FieldLinks.AddAsync("MyRequiredField", required: true);
Updating site content type field
To update the settings of a field added to a content type one can update its field link:
// Get site content types, also load the content types field links in one go
await context.Web.LoadAsync(p => p.ContentTypes.QueryProperties(p => p.Name, p => p.Description,
p => p.FieldLinks.QueryProperties(p => p.Name, p => p.ReadOnly)));
// Get the content type to update
var contentType = context.Web.ContentTypes.AsRequested().FirstOrDefault(p => p.Name == "MyContentType");
// Get the content type field link to update
var fieldLink = await contentType.FieldLinks.AsRequested().First(p => p.Name == "myField");
// Set the field in the content type to be readonly
fieldLink.ReadOnly = true;
await fieldLink.UpdateAsync();
Note
When you update a site content type field the changes are automatically pushed down the content types inheriting from the current content type.
Updating a list content type field
To update the settings of a field added to a content type one can update its field link:
// Add a list content type, start with getting a reference to the list
var list = await context.Web.Lists.GetByTitleAsync("Documents", p => p.ContentTypes.QueryProperties(
p => p.Name, p => p.Description,
p => p.FieldLinks.QueryProperties(p => p.Name, p => p.ReadOnly)),
p => p.Fields);
// Get the content type to update
var contentType = list.ContentTypes.AsRequested().FirstOrDefault(p => p.Name == "MyContentType");
// Get the content type field link to update
var fieldLink = await contentType.FieldLinks.AsRequested().First(p => p.Name == "myField");
// Set the field in the content type to be readonly
fieldLink.ReadOnly = true;
await fieldLink.UpdateAsync();
Deleting content types
To delete a content type you need to get a reference to the content type to delete followed by calling one of the Delete methods.
await context.Web.LoadAsync(p => p.ContentTypes.QueryProperties(p => p.Name, p => p.Description,
p => p.FieldLinks.QueryProperties(p => p.Name)));
var contentTypes = context.Web.ContentTypes;
// Get the content type to update
var contentType = contentTypes.AsRequested().FirstOrDefault(p => p.Name == "MyContentType");
// Delete the content type
await contentType.DeleteAsync();
Note
If a content type is in use you cannot delete it.
Removing a site content type field
To remove a field added to a content type one can remove its field link:
// Get site content types, also load the content types field links in one go
await context.Web.LoadAsync(p => p.ContentTypes.QueryProperties(p => p.Name, p => p.Description,
p => p.FieldLinks.QueryProperties(p => p.Name, p => p.ReadOnly)));
// Get the content type to update
var contentType = context.Web.ContentTypes.AsRequested().FirstOrDefault(p => p.Name == "MyContentType");
// Get the content type field link to remove
var fieldLink = await contentType.FieldLinks.AsRequested().First(p => p.Name == "myField");
// Delete the field from the content type
await fieldLink.DeleteAsync();
Removing a list content type field
To remove a field added to a content type one can remove its field link:
// Add a list content type, start with getting a reference to the list
var list = await context.Web.Lists.GetByTitleAsync("Documents", p => p.ContentTypes.QueryProperties(
p => p.Name, p => p.Description,
p => p.FieldLinks.QueryProperties(p => p.Name, p => p.ReadOnly)),
p => p.Fields);
// Get the content type to update
var contentType = list.ContentTypes.AsRequested().FirstOrDefault(p => p.Name == "MyContentType");
// Get the content type field link to delete
var fieldLink = await contentType.FieldLinks.AsRequested().First(p => p.Name == "myField");
// Delete the field from the content type
await fieldLink.DeleteAsync();