Provisioning Publishing Pages using Features declarative markup
Deployment, Development, SharePoint, Structured and repeatable deployment, WCMSharePoint Features allow you to provision all kinds of assets in a declarative way – we all know that. Using XML you can provision not only branding resources like CSS, JavaScript files and images but also Page Layouts and Master Pages. But did you know that using exactly the same mechanism you can provision Publishing Pages?
If you’re following me on Twitter you probably know that since a couple of weeks I’m working on a brand new Web Content Management (WCM) solution based on Microsoft Office SharePoint Server (MOSS) 2007. One of the things you do in every WCM solution is creating your custom branding and including it in your WSP package.
You can provision all kinds of assets using Modules in Element Manifest. If you want to provision a Page Layout for example, you could use the following XML snippet (copied from the PublishingLayouts Feature):
<File Url="ArticleLeft.aspx" Type="GhostableInLibrary">
<Property Name="Title"
Value="$Resources:cmscore,PageLayout_ArticleLeft_Title;" />
<Property Name="MasterPageDescription"
Value="$Resources:cmscore,PageLayout_ArticleLeft_Description;" />
<Property Name="ContentType"
Value="$Resources:cmscore,contenttype_pagelayout_name;" />
<Property Name="PublishingPreviewImage"
Value="~SiteCollection/.../Preview Images/ArticleLeft.png..." />
<Property Name="PublishingAssociatedContentType"
Value=";#Content Type;#0x010100C568DB52D9D0A14D9B2FDCC9666...;#"/>
</File>
While writing the provisioning script for the custom branding we have made, I have stumbled upon the following question: how is a Page Layout different than a Publishing Page? They are both documents (SPListItem + SPFile) are both stored in a Document Library and are both associated with a Content Type. Could you possibly provision a Publishing Page exactly the same way as you provision Page Layouts and Master Pages?
Proof of concept
To check it out I have decided to create a simple proof of concept. Almost immediately I have stumbled upon a challenge. While provisioning a Page Layout or a Master Page you have to point to an .aspx file which contains the contents. But what are the physical contents of a Publishing Page? The actual content is being stored within the underlying list item and the presentation is being done using a reference to the Page Layout. So what does the SPListItem.File contain?
Using a couple of lines of code I have extracted the contents of the File property of a Publishing Page which I have created using the ordinary Site Actions > Create Page menu. This is what I’ve found inside:
For the purpose of the proof of concept I have decided to simplify the Template Page (as I call the .aspx file used to provision Publishing Page) and have brought the markup down to (the Page directive has been broken into multiple lines for brevity. In your .aspx Template Page it should be in a single line):
<%@ Page
Inherits="Microsoft.SharePoint.Publishing.TemplateRedirectionPage, Microsoft.SharePoint.Publishing,Version=12.0.0.0,Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Reference VirtualPath="~TemplatePageUrl" %> <%@ Reference VirtualPath="~masterurl/custom.master" %>
To check whether it works I have created a simple Feature:
<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
Id="E5EB4D84-43C2-4093-870B-B341CB60EA1F"
Title="Deploy Publishing Page"
Description=""
Scope="Web"
Hidden="False"
Version="1.0.0.0">
<ElementManifests>
<ElementManifest Location="Elements.xml" />
<ElementFile Location="TemplatePage.aspx"/>
</ElementManifests>
</Feature>
and an Elements.xml file to provision the contents (some lines were broken for brevity):
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="Pages"
Url="$Resources:cmscore,List_Pages_UrlName;">
<File Name="Page1.aspx" Url="Page1.aspx"
Path="TemplatePage.aspx" Type="GhostableInLibrary"
IgnoreIfAlreadyExists="TRUE">
<Property Name="Title" Value="Lipsum"/>
<Property Name="PublishingPageLayout"
Value="~SiteCollection/_catalogs/masterpage/MyLayout.aspx,
/_catalogs/masterpage/MyLayout.aspx"/>
<Property Name="ContentType" Value="My page CT" />
<Property Name="ContentTypeId"
Value="0x010100C568DB52D9D0A14D9B2FDCC96666E9F200794..." />
<Property Name="PublishingPageContent"
Value="Lorem <strong>ipsum</strong>
<em>test add</em>" />
</File>
</Module>
</Elements>
After installing and activating the Feature it has properly created an instance of a Publishing Page! Cool!
So why is it so cool?
Personally I see the added value for this feature for at least two purposes.
Provisioning configuration/content in a structured and repeatable way
Speaking for myself: the customers I had a change to interact with would dislike the idea of buying a solution and getting a box of building blocks instead. In fact they expect a preconfigured environment where they can start publishing content in.
You could argue whether it’s right or wrong to do that and if it was better to let the customer do the job. Personally I compare it to the Windows and Linux experience from the old days. While you had to do everything manually on Linux, Windows presented you with a “nice” installer and after the installation was completed you had a ready-to-use operating system.
If you wanted to provide your customers with a preconfigured environment “the-old-way” you would probably use custom code to create and configure the Publishing Pages programmatically. The downside is that mixing the configuration with code isn’t a particularly good idea and might get difficult to keep overview after some time. Being able to provision the same content and configuration in a declarative way is easier to read and maintain in my opinion and is less prone to errors.
Provisioning test content
How many times did you have a customer who wanted to start entering some test content in the very first releases and then was annoyed with having to start from scratch after each new release. I face this in almost every single project. So is it once again about educating your customers or is it just common-sense?
Having test content is not just a gesture towards your customers in my opinion. Imagine having test content covering your use-cases, like testing paging, filters, etc in different scenarios. Wouldn’t it be cool to have a set of Features which would provision test content upon activation?
Using the approach I presented above you are able to create Features with test content in an intuitive way. I’m quite sure that having test content during your development process will help you test your stuff. And after the first release you could even include some of the test content create by your customer!
Limitations
Provisioning Publishing Pages using Features has unfortunately some limitations. So far I have found two.
Content Type must be bound to the Pages Library
The very first thing I’ve found that if you’re using some custom Content Type to base your Publishing Page on, be sure that it’s been bound to the Pages Library before provisioning that Publishing Page using a Feature.
You will not experience any problems while creating a Publishing Page using Site Actions > Create Page. The first you do it, SharePoint checks whether the particular Content Type is available within the Pages Library and attaches it if necessary. When using Features however you have to take care of the plumbing yourself, meaning you have to create a Feature which will associate the Content Type with the Pages Library either declarative or using custom code.
When I provisioned a Publishing Page using Feature XML using Content Type that wasn’t associated with the Pages Library that while the page has been created without any errors it was of wrong Content Type. So far I didn’t find out how SharePoint determines which Content Type to apply if the one you chose isn’t available. The fact is that you want your Content Type to be associated with the Pages Library before provisioning any Publishing Pages using Feature XML.
It’s for initial provisioning only
Using Features you can only provision new Publishing Pages. Any changes made to existing Publishing Pages won’t be provisioned. As far as I can tell this has to do with the IgnoreIfAlreadyExists attribute of the File element. If set to FALSE Feature activation will fail if the Publishing Page already exists. If set to TRUE however, the Feature activation process will skip processing all elements that already exist.
As far as I know the only exception to this is provisioning Web Parts using the AllUsersWebPart element. Each time you activate the Feature, a new instance of the Web Part will be added to the Publishing Page. At least that’s the case when provisioning Page Layouts.
How reliable is it?
So far I haven’t heard of anyone provisioning Publishing Pages using Features XML. I doubt that I’m the only one who has ever thought about it, so that brings me to the following question: is it a supported approach? As long as you’re using it for provisioning test content it doesn’t matter that much but if you would like to provision configuration of your site with it, it would be great to know the official position of Microsoft on this one.
The approach I have described in this article uses nothing else than the features available in a standard SharePoint installation. There is no reflection being applied and even no custom code at all. You might assume it’s not unsupported but it would be great if someone could confirm it.
The future
I really love the idea of being able to provision configuration and content using nothing else than Feature XML. In fact I’m so impressed by it that I’m working on a tool which will help you export the existing Publishing Pages to Feature Manifest, so all you’ll have to do is to create a Feature XML – sounds cool doesn’t it? I want the tool to work both in the context of the current Publishing Page (a custom button on the Page Editing Toolbar) and as a custom STSADM extension which will allow you to export multiple Publishing Pages at once.
I really hope I will be able to finish the tool soon. It will become available on CodePlex once it’s ready for testing. Stay tuned for updates and don’t hesitate to let me know if you have any feedback or experience with provisioning Publishing Pages using Feature XML.




April 1st, 2009 at 2:53 pm
"Content Type must be bound to the Pages Library"
Damn – that's exactly the problem I had a week ago. I should've thought of that. It's a bit frustrating though, the way that if you go to a Pages library and click on, "New > Article Page" it takes you to a list of all the available content types for the site – I wouldn't expect that. And then the available content types is determined by the 'Page Layouts' section of the 'Site Settings' – I didn't expect that either.
So it's all a bit confused as to how important that binding to the library itself is – but I must have missed doing that in my site definition. Damn.
Thanks for describing the problem though. Do you have code on how to do that binding declaratively?
April 1st, 2009 at 4:18 pm
@Andy: you can bind a Content Type to a List either programmatically or declaratively. To do that declaratively you can use the ContentTypeBinding element of a Feature (http://msdn.microsoft.com/en-us/library/aa543152.aspx)
April 2nd, 2009 at 2:43 pm
Really nice investigation indeed! However, if the customer really wants the ready-system, shouldn't a list back using one of available Powershell scripts (Fabrice Romerland has one on CodePlex) should be also an option, considering that Pages Library is still a Library afterall? (Obviously we assume that content types are already pre-defined accordingly)!
Still it remains the problem of customized vs uncustomized pages on subsequent stages, updates..etc. (stsadmextractfiles extension is really usefull to extract all SP designer changed files from Content DB).
Regards, Marius C.
April 2nd, 2009 at 6:35 pm
@Marius C.: if it was only about preparing the environment a PowerShell script would a suitable solution in my opinion. As I prefer to have the configuration separated from the code however, I'd rather have XML and then an engine to parse it and do the job. Sure you could create such engine using PowerShell but why bother if it's already available within SharePoint AND it's supported by Microsoft?
May 20th, 2009 at 4:12 am
I've been having a bit of a discussion with Chris O'Brien regarding some behavior I have noticed when using this exact approach. He pointed me to your post so…
Have you tested/needed to update the page layout the provisioned page relies on and seen whether the provisioned page reflects these updates? So far I have only managed to make the page take on the page layout changes by a dettach/reatttach type hack.
Cheers,
Nick Hadlee
May 20th, 2009 at 7:11 am
@Nick Hadlee: I haven't tested changing the Page Layout yet. As changing anything else in SharePoint I wouldn't expect this to work declaratively and would use code instead.
May 20th, 2009 at 7:20 am
Sorry I wasn't very clear in my last question. I meant if you make a change to the page layout that the page references and then deploy that. I don't mean changing which layout the page uses.
E.g: Make a change to the feature based page layout and then do a feature upgrade to deploy the change. A UI provisioned page will show the changes from the page layout but the feature provisioned page will not. The onyl way I have made the provisioned page show the changes is by reghosting it. Kind of limiting factor if you have a lot of these type of pages deployed which I am hoping is not a "by design" thing.
November 19th, 2009 at 11:19 pm
You can provision a publishing page based upon a feature in SharePoint. Pretty easy! When adding web parts to the page that must be acomplished via a feature receiver, payihg attention to check out, and check in of the page. If you would like to see the code, email me
December 30th, 2009 at 5:25 pm
Man, you're fantastic!
Exactly what I needed – I work in an organisation which doesn't allow any editing in the Prod environment – everything must be provisioned through WSP's.
December 6th, 2011 at 6:31 pm
[...] provisioning a bunch of Publishing pages using a feature, using the template redirection [...]
April 21st, 2012 at 8:23 pm
[...] your publishing page (again, refer to the MSDN article, or better yet, see my friend Waldek's article discussing just this). So what am I talking about? I want to focus on how to set two specific properties on the page [...]
April 21st, 2012 at 8:23 pm
[...] your publishing page (again, refer to the MSDN article, or better yet, see my friend Waldek's article discussing just this). So what am I talking about? I want to focus on how to set two specific properties on the page [...]