Deploy Publishing Pages and Content Types as a feature

Aka “CAML is the bastard spawn of Satan”.

So, I’m writing a site definition to create a Publishing site. This is a bit of a first for me. One of the things I want to do is deploy a new Publishing Page Content type, and associate some layouts with it.

I started by following Andrew Connell’s instructions for a Minimal Site Definition (as in his book). This all seemed to go pretty well; testing created a new, minimal site.

Next up I wanted to deploy the Content Type and associated page layouts. Well, there wasn’t much information in his book on this – like him, I’d figured I’d write a separate Feature for deploying just the content type and page layouts – but there was very little information in his book about this.

My first efforts were pretty unsuccessful. I used his STSADM commands to pull the content type I wanted to use out of SharePoint as CAML, and wrote the feature to deploy that content type and my page layout files. However, when I activated the feature, if I went to the ‘Create New Page’ page or the ‘Site Content Types’ page my CPU usage went to 100% and sat there. Looked like it was an infinite loop.

“Hmm. Something wrong with the Content Type” I thought – but could I see what was wrong? My first thought was that it was the presence of the fields defined by the parent Page content type, but fixing that still resulted in nothing. Eventually, after a couple of hours of experimentation and trawling of the web, I found this explanation.

the XML generated does not contain the XML Namespace: Also note that this tool doesn’t create XML that is 100% correct for use in a Feature.

Thanks Daniel Pollard, good to know. Added my NamespaceURL as shown below, and my content type deployed correctly, without high CPU usage.

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ContentType ID="[Long Content Type ID]" Name="Andy's Page" Description="A Page For Andy" Group="Andy's Types">
<FieldRefs>
<FieldRef ID="f55c4d88-1f2e-4ad9-aaa8-819af4ee7ee8" Name="PublishingPageContent" />
</FieldRefs>
<DocumentTemplate TargetName="/_layouts/CreatePage.aspx" />
<XmlDocuments>
<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<Display>DocumentLibraryForm</Display>
<Edit>DocumentLibraryForm</Edit>
<New>DocumentLibraryForm</New>
</FormTemplates>
</XmlDocument>
</XmlDocuments>
</ContentType>
</Elements>

Of course, it then occurred to me that I probably didn’t need the XMLDocuments section. So I deleted it:

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ContentType ID="[Long Content Type ID]" Name="Andy's Page" Description="A Page For Andy" Group="Andy's Types">
<FieldRefs>
<FieldRef ID="f55c4d88-1f2e-4ad9-aaa8-819af4ee7ee8" Name="PublishingPageContent" />
</FieldRefs>
<DocumentTemplate TargetName="/_layouts/CreatePage.aspx" />
</ContentType>
</Elements>

Reams of CAML cut down to a few lines. Next time, I’m just writing all this by hand.

Anyway, the content type was going in alright, but my page layouts were not attached to it. I couldn’t find any documentation about that either in MSDN. Then I found a useful article by Josh Carlisle trying to so what I was doing – deploy a content type and a page layout. Ah-ha! PublishingAssociatedContentType looks promising. Indeed Chris O’Brien has a good description of the fields of this too.

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="LayoutPreviews" Url="_catalogs/masterpage/$Resources:core,Culture;/Preview Images" RootWebOnly="True" Path="PageLayoutPreviews">
<File Url="Andys.png" IgnoreIfAlreadyExists="TRUE" Type="GhostableInLibrary"></File>
</Module>
<Module Name="Layouts" Url="_catalogs/masterpage" RootWebOnly="True" Path="PageLayouts">
<File Url="AndysLayout.aspx" IgnoreIfAlreadyExists="TRUE" Type="GhostableInLibrary">
<Property Name="Title" Value="Andys Layout" />
<Property Name="ContentType" Value="$Resources:cmscore,contenttype_pagelayout_name;" />
<Property Name="PublishingAssociatedContentType" Value=";#Andy's Page;#[Long Content Type ID];#" />
<Property Name="PublishingPreviewImage" Value="~SiteCollection/_catalogs/masterpage/$Resources:core,Culture;/Preview Images/Andys.png, ~SiteCollection/_catalogs/masterpage/$Resources:core,Culture;/Preview Images/Andys.png" />
</File>
</Module>
</Elements>

That seems to work nicely – it deploys the page layout, gives it a friendly name and preview image, and hooks it up to the content type. Note: the Content Type property is not the SharePoint Content type, but some text saying that this file is a page layout. See the resources for CMSCore to see the exact text.

So, what did I make of this experience? Well, lot’s of CAML – which is virtually some obscure dead language spoken by a strange tribe lost in the artic wilderness. I actually think it might’ve been easier to write C# code to do all this set up. Anyway, it does appear that blogs are better than Microsoft’s documentation.

Advertisement
Deploy Publishing Pages and Content Types as a feature

3 thoughts on “Deploy Publishing Pages and Content Types as a feature

  1. Hmm. Yep, I’ll have a look at that. That’s sort of what Andrew Connell’s STSADM commands were for – but unfortunately didn’t do it entirely well 😦

    Not sure when I’ll get the chance to look at it, but I will at some stage, I’m sure.

  2. jason robbo says:

    CAML and other forms of XML are to be tooled. The frustrating thing about many XML def is the definition is written and there is no tool the tool should be the first or don’t bother

Leave a Reply to Andy Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.