This post is a wrap up of previous blog posts that I have written on creating a custom list schema. I find myself searching for these posts every time I need to do this, so I thought it would be handy to have it all in one place (at least for myself). In one of our current projects, we were creating custom list schemas like this. we tried to query the lists (using Content Query Web Part) based on the custom content type that is associated with these list. At first this did not work and this post also shows how we fixed that. At the end of this article you will find the link to the ZIP file containing all code.
This article shows how to:
- Create a custom site column from a feature
- Create a custom content type using that site column from a feature
- Create a custom list schema using that content type
- Rename the Title field to a custom display name
- Add a new view to the list, to show the new site column
- Create a new feature that creates a new instance of the new list template
- Populate the list with default items
- Show items from lists based on this template using the Content Query Web Part
My solution has 2 features:
- site collection feature for registering site column, content type and list template.
- web feature for creating a list and populating it with data.
Step 1 – The Site Collection Feature
The XML snippet below is the XML from my feature.xml file that ends up in folder <SharePoint Root>\TEMPLATE\FEATURES\TST.CustomListTemplate. Nothing special to mention here, except that you can register multiple site columns, content types and list templates by creating 1 feature. You don’t need to create a new feature for every list template. SharePoint allows you to do that, but you end up with having a lot of features. If you want to have a feature for each list template, I would recommend creating hidden features and creating 1 wrapper features with activation dependencies.
1: <?xml version="1.0" encoding="utf-8"?>
2: <Feature Id="23ddef43-9d01-4127-9903-beeb77c28c5d"
3: Title="TST Custom List Template demo"
4: Description="Custom list template with a custom content type associated (Ton Stegeman)"
5: Version="1.0.0.0"
6: Scope="Site"
7: Hidden="FALSE"
8: xmlns="http://schemas.microsoft.com/sharepoint/">
9: <ElementManifests>
10: <ElementManifest Location="Fields.xml"/>
11: <ElementManifest Location="Contenttype.xml"/>
12: <ElementManifest Location="ListTemplates\Template.xml" />
13: </ElementManifests>
14: </Feature>
The sample above activates three element manifests. These can be found in the next paragraphs.
Step 2 – The Site Column
In this XML snippet below, the new site column is created.
1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3: <Field
4: Type="Text"
5: DisplayName="Demo Text Field"
6: Required="TRUE"
7: MaxLength="255"
8: Group="TST Demo Fields"
9: ID="{ee69b92a-02cd-4a5d-b6bd-d1fec35c301f}" 10: StaticName="DemoTextField"
11: Name="DemoTextField"/>
12: </Elements>
Most important thing to notice here is that I removed the spaces that are used in the displayname of the field from the internalname attributes of the field. I would recommend doing this for all special characters, otherwise you end up with encoded internal field names using ‘_x0020’. My custom site column would have had internal name ‘TST_x0020_Demo_x0020_Field’ if I did not remove the spaces from the internal names.
Step 3 – The Content Type
Below you can find the contents of Contenttype.xml. In the <FieldRefs> element you will find all fields that are used by the content type. You see a reference to our custom site column (it has the same ID and Name). The first field used in this sample is the title field that is renamed to have another displayname.
1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3: <ContentType ID="0x01008c43d032ae654d6e8b965c45acc4af3a"
4: Name="Demo Contenttype"
5: Description="Content type with a custom text field and a renamed Title field."
6: Group="TST Demo Fields"
7: Version="0"
8: Sealed="FALSE"
9: ReadOnly="FALSE"
10: BaseType="0x01">
11: <FieldRefs>
12: <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" 13: DisplayName="Demo Title Field"
14: Name="Title"
15: Required="TRUE"
16: ShowInNewForm="TRUE"
17: ShowInEditForm="TRUE"/>
18: <FieldRef ID="{ee69b92a-02cd-4a5d-b6bd-d1fec35c301f}" 19: Name="DemoTextField"
20: Required="TRUE"
21: ShowInNewForm="TRUE"
22: ShowInEditForm="TRUE"/>
23: </FieldRefs>
24: </ContentType>
25: </Elements>
There is something special about the ID of a custom content type. If you haven’t seen this before, you better read the something of the backgrounds, to understand this mechanism. Brett Maytom explains how it works. This MSDN article by Scot Hillier also explains it briefly.
Step 4 – The List Schema
Next thing to create is the list schema that is using our custom content type. I won’t publish the full content of the schema.xml file. You can find this in the attached ZIP file (see the end of this article). Important in the schema is that you will need to have the XML definition of the Field elements that are in your content type.
1: <ContentTypes>
2: <ContentTypeRef ID="0x01008c43d032ae654d6e8b965c45acc4af3a">
3: <Folder TargetName="Item" />
4: </ContentTypeRef>
5: </ContentTypes>
6: <Fields>
7: <Field
8: Name="LinkTitle"
9: ID="{82642ec8-ef9b-478f-acf9-31f7d45fbc31}" 10: DisplayName="Demo Title Field"
11: Sealed="TRUE"
12: SourceID="http://schemas.microsoft.com/sharepoint/v3"
13: StaticName="LinkTitle">
14: </Field>
15: <Field
16: Name="LinkTitleNoMenu"
17: ID="{bc91a437-52e7-49e1-8c4e-4698904b2b6d}" 18: DisplayName="Demo Title Field"
19: Sealed="TRUE"
20: SourceID="http://schemas.microsoft.com/sharepoint/v3"
21: StaticName="LinkTitleNoMenu">
22: </Field>
23: <Field
24: ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" 25: Type="Text"
26: Name="Title"
27: ShowInNewForm="TRUE"
28: DisplayName="Demo Title Field"
29: Sealed="TRUE"
30: SourceID="http://schemas.microsoft.com/sharepoint/v3"
31: StaticName="Title">
32: </Field>
33: <Field
34: Type="Text"
35: DisplayName="Demo Text Field"
36: Required="TRUE"
37: MaxLength="255"
38: Group="TST Demo Fields"
39: ID="{ee69b92a-02cd-4a5d-b6bd-d1fec35c301f}" 40: StaticName="DemoTextField"
41: Name="DemoTextField"/>
42: </Fields>
The snippet above shows how to associate the custom content type we created in Step 3 with the list. The Fields elements contains all fields that we will use in our list (also our custom field that is part of the content type). If you don’t put the XML for your fields here, the content type will be associated with the list, but the fields will not be available in the list items. The snippet also shows how to rename the Title field to have a custom display name. It also renames the out of the box computed fields that use this Title field (like ‘Title (linked to item with edit menu)’).
Step 5 – The View
In the schema.xml file we also add the new view to our list. The snippet below just shows the <View> element.
1: <View
2: BaseViewID="2"
3: Type="HTML"
4: WebPartZoneID="Main"
5: DisplayName="TST Custom View"
6: DefaultView="FALSE"
7: SetupPath="pages\viewpage.aspx"
8: ImageUrl="/_layouts/images/generic.png"
9: Url="DemoView.aspx">
Important attributes of this element are BaseViewID, SetupPath and Url. BaseViewID must be a unique ID for all views in your schema.xml file. SetupPath is a reference to a page that is used as template for your view page. If you don’t want to use custom form, set it to ‘pages\viewpage.aspx’. The Url will be the name of the aspx of the View itself. If you don’t specify the SetupPath, you will have to make sure your list schema folder has an aspx for the view page.
Step 6 – The List Template
After creating the list schema, next thing to do is to define the list template. This is the 3rd XML file that is referenced from our feature.xml file in step 1. The contents of my example is shown in the snippet below.
1: <?xml version="1.0" encoding="utf-8"?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3: <ListTemplate
4: Name="List"
5: Type="90010"
6: BaseType="0"
7: OnQuickLaunch="TRUE"
8: SecurityBits="11"
9: Sequence="410"
10: DisplayName="Demo list template with custom content type (Ton Stegeman)"
11: Description="Custom list with a custom content type associated, a renamed title field and an extra view."
12: Image="/_layouts/images/itgen.gif"/>
13: </Elements>
Make sure that the Name attribute matches the name of the folder that contains the schema.xml file. In my case, the feature folder has a subfolder called ‘List’ that holds the schema.xml file. Second thing to look at is to define a unique number for your list template and use that in the Type attribute.
Step 7 – The Web Feature
In the previous steps we have completed our site collection feature that registers the schema for our custom list. In this step, we will create a Web scoped feature that creates a new instance based on this list schema and adds some items to it.
1: <?xml version="1.0" encoding="utf-8"?>
2: <Feature Id="05fd17d4-5f70-40ab-a5e9-975ba15df371"
3: Title="TST Custom List Instance demo"
4: Description="Custom list instance based on a custom schema (Ton Stegeman)"
5: Version="1.0.0.0"
6: Scope="Web"
7: Hidden="FALSE"
8: xmlns="http://schemas.microsoft.com/sharepoint/">
9: <ElementManifests>
10: <ElementManifest Location="Lists.xml" />
11: </ElementManifests>
12: <ActivationDependencies>
13: <ActivationDependency FeatureId="23ddef43-9d01-4127-9903-beeb77c28c5d"/>
14: </ActivationDependencies>
15: </Feature>
The above snippet shows the XML file the feature. Make sure the Id for your feature is unique. Create a new GUID using http://www.newguid.com, use GuidGen in Visual Studio, or use the CodeRush/Refactor tools for SharePoint Developers by Andrew Connell.
The feature has a dependency on our site collection feature. SharePoint will first check if this feature is activated before activating the web feature.
Step 8 – The List
The feature in step 7 uses Lists.xml as element manifest. The contents of this file is shown in the snippet below. The FeatureId attribute is a reference to the feature that registered the list template. This is our site collection feature from Step 1, not the web feature from step 7!
1: <?xml version="1.0" encoding="utf-8" ?>
2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
3: <ListInstance
4: FeatureId="23ddef43-9d01-4127-9903-beeb77c28c5d"
5: Title="Demo list"
6: Description="Demo list with custom schema and items."
7: Id="90010"
8: TemplateType="90010"
9: Url="Lists/Demolist">
10: </ListInstance>
11: </Elements>
Make sure that the Id attribute matches the Type attribute of the ListTemplate element in Step 6. If you have spaces in the title of your list, it might be good to remove them from the url for your list. The Url attribute allows you to specify the url for your list. This will be the name of the rootfolder of the list.
Step 9 – The Data
In this step, we populate the list with some data once the list is created. Add the snippet below as a child element of the ListInstance element in the XML file of step 8.
1: <Data>
2: <Rows>
3: <Row>
4: <Field Name="ID">1</Field>
5: <Field Name="Title">Title of the first item (created in the feature)</Field>
6: <Field Name="DemoTextField">Demo text first item</Field>
7: </Row>
8: <Row>
9: <Field Name="ID">2</Field>
10: <Field Name="Title">Title of the first item (created in the feature)</Field>
11: <Field Name="DemoTextField">Demo text first item</Field>
12: </Row>
13: </Rows>
14: </Data>
For every Row, the ID field is set explicitly. It is not necessary to do this, but if you don’t do it and your feature gets re-activated, you end up with duplicated content in your list.
Step 9 – The Deployment
Deployment of our 2 features is done using a WSP package. In my Visual Studio solution, the folder TSTCustomListTemplate contains the site collection feature and all content. The folder TSTCustomListInstance contains all content for the web feature. The package is created using the DDF file below:
1: ;
2: .OPTION EXPLICIT ; Generate errors
3: .Set CabinetNameTemplate=TST.TestList2007.ListTemplate.wsp
4: .set DiskDirectoryTemplate=CDROM ; All cabinets go in a single directory
5: .Set CompressionType=MSZIP;** All files are compressed in cabinet files
6: .Set UniqueFiles="ON"
7: .Set Cabinet=on
8: .Set DiskDirectory1=Package
9: manifest.xml manifest.xml
10:
11: ; Include files for the Feature folder
12: ..\TSTCustomListTemplate\Feature.xml TST.CustomListTemplate\Feature.xml
13: ..\TSTCustomListTemplate\Contenttype.xml TST.CustomListTemplate\Contenttype.xml
14: ..\TSTCustomListTemplate\Fields.xml TST.CustomListTemplate\Fields.xml
15: ..\TSTCustomListTemplate\ListTemplates\Template.xml TST.CustomListTemplate\ListTemplates\Template.xml
16: ..\TSTCustomListTemplate\List\schema.xml Features\TST.CustomListTemplate\List\schema.xml
17:
18: ..\TSTCustomListInstance\Feature.xml TST.CustomListInstance\Feature.xml
19: ..\TSTCustomListInstance\Lists.xml TST.CustomListInstance\Lists.xml
20: ;
The manifest of the solution:
1: <?xml version="1.0" encoding="utf-8" ?>
2: <Solution SolutionId="56e1580d-7eb8-4428-adea-1a17c120389c" xmlns="http://schemas.microsoft.com/sharepoint/">
3: <TemplateFiles>
4: <TemplateFile Location="Features\TST.CustomListTemplate\List\schema.xml"/>
5: </TemplateFiles>
6: <FeatureManifests>
7: <FeatureManifest Location ="TST.CustomListTemplate\Feature.xml"/>
8: <FeatureManifest Location ="TST.CustomListInstance\Feature.xml"/>
9: </FeatureManifests>
10: </Solution>
11:
Deploying the solution is done using SharePoint Solution Installer from CodePlex. The snippet below shows the configuration for the installer, from setup.exe.config. The SolutionId needs to be the same value as the value of the SolutionId attribute in the manifest file.
1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <appSettings>
4: <add key="BannerImage" value="Default"/>
5: <add key="LogoImage" value="None"/>
6: <add key="EULA" value=""/>
7: <add key="SolutionId" value="56e1580d-7eb8-4428-adea-1a17c120389c"/>
8: <add key="FarmFeatureId" value=""/>
9: <add key="SolutionFile" value="TST.TestList2007.ListTemplate.wsp"/>
10: <add key="SolutionTitle" value="TST Demo List Template"/>
11: <add key="SolutionVersion" value="1.0.0.0"/>
12: <add key="UpgradeDescription" value="Upgrades {SolutionTitle} on all frontend web servers in the SharePoint farm."/> 13: <add key="RequireDeploymentToCentralAdminWebApplication" value="false"/>
14: <add key="RequireDeploymentToAllContentWebApplications" value="false"/>
15: </appSettings>
16: </configuration>
Step 10 – The Test
After installing and deploying the solution, you can test the new list. First activate the site collection feature:
In the site(s) where you want to use your new list, activate the web feature:
If all is well, you now have a new list in your site called ‘Demo list’:
This list should have a custom view (TST Custom View), the Title field is renamed to ‘Demo Title Field’ and it has 2 items, as shown in the screenshot above.
Step 11 – Querying The Content
Last step in this article is to show how you can query for content in your new list(s) using the Content Query Web Part. Drag the web part onto a page and modify the properties. In the Query section you can select your new content type, as is shown in this screenshot:
The issue we have here is that you also need to specify the list type. In some cases, our custom list is not available in the dropdown. I was unable to figure out why the custom list template was not available in the dropdown, but I have seen it a few times. The way to solve this is to full configure your web part. Then save the changes. This will result in the message ‘This query has returned no items’. Export your web part and delete it from the page. Open the file in an editor. Find the property where that attribute Name has value ‘ServerTemplate’. Change the value of this property to the value of your Type attribute in the ListTemplate regristration in Step 6. In my case this is 90010.
1: <webParts>
2: <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
3: <data>
4: <properties>
5: <property name="ServerTemplate" type="string">90010</property>
6: </properties>
7: </data>
8: </webPart>
9: </webParts>
Save the .webpart file , import it onto your page and that’s it. Your web part will show the results from your custom lists:
This ZIP file contains all the files I described in this article.
http://www.tonstegeman.com/Blog/Documents/TST.TestList2007.zip