SharePoint: Adding Default Web Parts to a Publishing Page Layout with Feature Provisioning


You want to add a set of web parts to your publishing page layout, so that when users create new instances of a page using your layout, the page is created with some web parts already added to the page for them. You may want the web parts in that web part zone to be editable or not, or to not allow users to edit that web part zone.

The later part of this requirement, is controlled by setting the appropriate properties on the WebPartZone element in your page layout markup;

<WebPartPages:WebPartZone ID="TopZone" runat="server" Title="Top"
		AllowPersonalization="False" AllowCustomization="False" AllowLayoutChange="False">
	<ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone>
  • AllowPersonalization determines if users can change the properties of a web part using the SharePoint UI
  • AllowCustomization determines if users can change the properties of a web part for all users using the SharePoint UI
  • AllowLayoutChange determines if users can change the layout of web parts in the web part zone

So, to add default web parts to a publishing page layout there are some options;

  1. Add an event receiver to the Pages library and add web parts to the page using code.
  2. Add the web parts markup directly to the page layout (.aspx) page
  3. Add the web parts to the provisioned page layout using the AllUsersWebPart element in an elements.xml file

I’ve never tried option1, this seems a bit overkill to me, but certainly a viable option in the right circumstances.

I’ve tried option 2, without much success – I’ve been able to add stock web parts this way but not custom developed ones.

The remainder of this post will discuss option 3, adding the web parts to the page layout using the AllUsersWebPart element.

Below we can see a vanilla elements.xml file for provisioning a page layout into the master page gallery;

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
	<Module Name="PageLayouts" List="116" Url="_catalogs/masterpage" Path="PageLayouts" RootWebOnly="TRUE">
		<File Path="MyPageLayout.aspx" Url="MyPageLayout.aspx" Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE">
			<Property Name="Title" Value="My PageLayout" />
			<Property Name="MasterPageDescription" Value="My Page Layout" />
			<Property Name="ContentType" Value="$Resources:cmscore,contenttype_pagelayout_name;" />
			<Property Name="PublishingAssociatedContentType" Value=";#$Resources:cmscore,contenttype_articlepage_name;;#0x010100C568DB52D9D0A14D9B2FDCC9
6666E9F2007948130EC3DB064584E219954237AF3900242457EFB8B24247815D688C526CD44D;#"/>
		</File>
	</Module>
</Elements>

And the associated page layout page markup is again vanilla;

<%@ Page Language="C#" Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage,Microsoft.SharePoint
.Publishing,Version=14.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePointWebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<asp:Content contentplaceholderid="PlaceHolderMain" runat="server">
	<SharePointWebPartPages:SPProxyWebPartManager runat="server" id="ProxyWebPartManager">
		</SharePointWebPartPages:SPProxyWebPartManager>

	<table cellpadding="1" cellspacing="0" border="0" width="100%">
		<PublishingWebControls:EditModePanel runat=server id="ContentEditModePanel" SuppressTag="True">
			<tr>
				<td width="50%" valign="Top">
					<SharePointWebControls:TextField ID="TextField2" FieldName="Title" runat="server">
						</SharePointWebControls:TextField>
				</td>
				<td width="50%" valign="Top">
					<PublishingWebControls:RichImageField ID="RichImageField1" FieldName="PublishingRollupImage" runat="server">
						</PublishingWebControls:RichImageField>
				</td>
			</tr>
		</PublishingWebControls:EditModePanel>

		<tr>
			<td width="50%" valign="Top">
				<PublishingWebControls:RichHtmlField ID="RichHtmlField2" FieldName="PublishingPageContent" runat="server">
				</PublishingWebControls:RichHtmlField>
			</td>
			<td width="50%" valign="Top">
				<div class="webpart_zone">
					<WebPartPages:WebPartZone ID="TopZone" runat="server" Title="Top"
							AllowPersonalization="False" AllowCustomization="False" AllowLayoutChange="False">
						<ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone>
				</div>

				<div class="webpart_zone">
					<WebPartPages:WebPartZone ID="BottomZone" runat="server" Title="Bottom"
							AllowPersonalization="False">
						<ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone>
				</div>
			</td>
		</tr>
	</table>

</asp:Content>

In here we can see a couple of web part zones, TopZone and BottomZone, with TopZone being configured as read-only. We will add a default web part to this zone so that is displays on every page created using this page layout.

To do this simply add an AllUsersWebPart element within the File element as shown;

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
	<Module Name="PageLayouts" List="116" Url="_catalogs/masterpage" Path="PageLayouts" RootWebOnly="TRUE">
		<File Path="MyPageLayout.aspx" Url="MyPageLayout.aspx" Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE">
			<Property Name="Title" Value="My PageLayout" />
			<Property Name="MasterPageDescription" Value="My Page Layout" />
			<Property Name="ContentType" Value="$Resources:cmscore,contenttype_pagelayout_name;" />
			<Property Name="PublishingAssociatedContentType" Value=";#$Resources:cmscore,contenttype_articlepage_name;;#0x010100C568DB52D9D0A14D9B2FDCC
96666E9F2007948130EC3DB064584E219954237AF3900242457EFB8B24247815D688C526CD44D;#"/>
			<AllUsersWebPart WebPartZoneID="TopZone" WebPartOrder="1">
				<![CDATA[<WebPart xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/WebPart/v2">
  <Title>(Top) Content Editor</Title>
  <FrameType>Default</FrameType>
  <Description>Allows authors to enter rich text content.</Description>
  <IsIncluded>true</IsIncluded>
  <ZoneID>g_6152392B747446EE9AC5411A52737629</ZoneID>
  <PartOrder>0</PartOrder>
  <FrameState>Normal</FrameState>
  <Height />
  <Width />
  <AllowRemove>true</AllowRemove>
  <AllowZoneChange>true</AllowZoneChange>
  <AllowMinimize>true</AllowMinimize>
  <AllowConnect>true</AllowConnect>
  <AllowEdit>true</AllowEdit>
  <AllowHide>true</AllowHide>
  <IsVisible>true</IsVisible>
  <DetailLink />
  <HelpLink />
  <HelpMode>Modeless</HelpMode>
  <Dir>Default</Dir>
  <PartImageSmall />
  <MissingAssembly>Cannot import this Web Part.</MissingAssembly>
  <PartImageLarge>/_layouts/images/mscontl.gif</PartImageLarge>
  <IsIncludedFilter />
  <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
  <TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName>
  <ContentLink xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor" />
  <Content xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor">** THIS IS MY TOP CONTENT **</Content>
  <PartStorage xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor" />
</WebPart>]]>
			</AllUsersWebPart>
		</File>
	</Module>
</Elements>

I’ve used a Content Editor web part, but your own custom web parts will also work, provided they are deployed correctly. If you now deploy this with a feature and create a new page using this page layout with the SharePoint UI, the page will be created with this web part already added to the page;

Default Web Parts
Default Web Parts

And in this case the web part zone with the default web parts in is configured as read-only, the second (Bottom) web part zone is available for user to place there own content in.

So this is great from a content authors point of view, but what about page instances provisioned via a feature?

Well here the story is less great, you’d expect that provisioning a page instance using a feature would yield the same results, consider the elements.xml for a page instance below;

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
	<Module Name="Pages" Url="$Resources:cmscore,List_Pages_UrlName;" Path="Pages" RootWebOnly="TRUE">
		<File Url="MyPage.aspx" Path="template.aspx" Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE">
			<Property Name="Title" Value="My Page" />
			<Property Name="Comments" Value="This is my Page." />
			<Property Name="PublishingPageLayout" Value="~SiteCollection/_catalogs/masterpage/MyPageLayout.aspx, My PageLayout" />
			<Property Name="ContentType" Value="$Resources:cmscore,contenttype_articlepage_name;" />
		</File>
	</Module>
</Elements>

Pretty standard stuff, we’re creating a page instance using our page layout (which includes default web parts) into the Pages library. However when this page gets created after you activate the feature, the new page instance doesn’t get the default web parts (in the page layout) added to the page.

What you have to do to get this to work is take those same default web parts (from the page layout) and also add them to the page instance, as shown below;

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
	<Module Name="Pages" Url="$Resources:cmscore,List_Pages_UrlName;" Path="Pages" RootWebOnly="TRUE">
		<File Url="MyPage.aspx" Path="template.aspx" Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE">
			<Property Name="Title" Value="My Page" />
			<Property Name="Comments" Value="This is my Page." />
			<Property Name="PublishingPageLayout" Value="~SiteCollection/_catalogs/masterpage/MyPageLayout.aspx, My PageLayout" />
			<Property Name="ContentType" Value="$Resources:cmscore,contenttype_articlepage_name;" />
			<AllUsersWebPart WebPartZoneID="TopZone" WebPartOrder="1">
				<![CDATA[<WebPart xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/WebPart/v2">
  <Title>(Top) Content Editor</Title>
  <FrameType>Default</FrameType>
  <Description>Allows authors to enter rich text content.</Description>
  <IsIncluded>true</IsIncluded>
  <ZoneID>g_6152392B747446EE9AC5411A52737629</ZoneID>
  <PartOrder>0</PartOrder>
  <FrameState>Normal</FrameState>
  <Height />
  <Width />
  <AllowRemove>true</AllowRemove>
  <AllowZoneChange>true</AllowZoneChange>
  <AllowMinimize>true</AllowMinimize>
  <AllowConnect>true</AllowConnect>
  <AllowEdit>true</AllowEdit>
  <AllowHide>true</AllowHide>
  <IsVisible>true</IsVisible>
  <DetailLink />
  <HelpLink />
  <HelpMode>Modeless</HelpMode>
  <Dir>Default</Dir>
  <PartImageSmall />
  <MissingAssembly>Cannot import this Web Part.</MissingAssembly>
  <PartImageLarge>/_layouts/images/mscontl.gif</PartImageLarge>
  <IsIncludedFilter />
  <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
  <TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName>
  <ContentLink xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor" />
  <Content xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor">** THIS IS MY TOP CONTENT **</Content>
  <PartStorage xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor" />
</WebPart>]]>
			</AllUsersWebPart>
			<AllUsersWebPart WebPartZoneID="BottomZone" WebPartOrder="1">
				<![CDATA[<WebPart xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/WebPart/v2">
  <Title>(Bottom) Content Editor</Title>
  <FrameType>Default</FrameType>
  <Description>Allows authors to enter rich text content.</Description>
  <IsIncluded>true</IsIncluded>
  <ZoneID>g_6152392B747446EE9AC5411A52737629</ZoneID>
  <PartOrder>0</PartOrder>
  <FrameState>Normal</FrameState>
  <Height />
  <Width />
  <AllowRemove>true</AllowRemove>
  <AllowZoneChange>true</AllowZoneChange>
  <AllowMinimize>true</AllowMinimize>
  <AllowConnect>true</AllowConnect>
  <AllowEdit>true</AllowEdit>
  <AllowHide>true</AllowHide>
  <IsVisible>true</IsVisible>
  <DetailLink />
  <HelpLink />
  <HelpMode>Modeless</HelpMode>
  <Dir>Default</Dir>
  <PartImageSmall />
  <MissingAssembly>Cannot import this Web Part.</MissingAssembly>
  <PartImageLarge>/_layouts/images/mscontl.gif</PartImageLarge>
  <IsIncludedFilter />
  <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
  <TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName>
  <ContentLink xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor" />
  <Content xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor">** THIS IS MY BOTTOM CONTENT **</Content>
  <PartStorage xmlns="http://schemas.microsoft.com/WebPart/v2/ContentEditor" />
</WebPart>]]>
			</AllUsersWebPart>
		</File>
	</Module>
</Elements>

In the example above I’ve added the same default web part to the TopZone web part zone (just as in the page layout) and I’ve also added another web part to the second web part zone (BottomZone), and when this page instance is created, it shows both web parts.

Default Web Parts for Provisioned Page
Default Web Parts for Provisioned Page

Published by

Phil Harding

SharePoint Consultant, Developer, Father, Husband and Climber.

11 thoughts on “SharePoint: Adding Default Web Parts to a Publishing Page Layout with Feature Provisioning

  1. Hi Thanks for the explanation. but I have a question…?
    Is that sandbox solution or farm solution…?

  2. Hello ,
    thanks for this article, i tried your solution on my project, it worked, but webparts are duplicated automatically after i create my page, i have 20 duplicated webparts now.
    did i miss something?

    Thans for your help

  3. Hi, no I’m afraid it’s a side effect of provisioning webparts in this way – the only workaround is to have your feature receiver delete the page instances during deactivation

  4. Phil, thanks for the article, it’s the most comprehensive one I’ve found on automated provisioning so far. I haven’t had a chance to experiment yet but could you tell me: can you configure custom tool parts from here?

    So far I have saw many examples setting Title, Description and so on but we have custom opens setting file paths, additional ids and the like and I’m looking to get these configured at deployment time as well.

    Will return with the answer if I find it before your reply.

  5. Can someone confirm that this method still works? I have literally copied and pasted your code and it is providing no errors, but is not populating the web parts into the zones.

  6. I have applied same steps on our side, i m getting below error while choosing given page layout.

    Server Error in ‘/’ Application.

    No parameterless constructor defined for this object.

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.MissingMethodException: No parameterless constructor defined for this object.

    Source Error:

    An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

    Stack Trace:

    [MissingMethodException: No parameterless constructor defined for this object.]
    System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
    System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +138
    System.Activator.CreateInstance(Type type, Boolean nonPublic) +105
    System.Activator.CreateInstance(Type type) +12
    Microsoft.SharePoint.WebPartPages.SPWebPartReflectionHelper.GetDefaultControl(Type controlType) +143
    Microsoft.SharePoint.WebPartPages.BinaryWebPartSerializer.GetDefaultControl() +32
    Microsoft.SharePoint.WebPartPages.BinaryWebPartSerializer.Serialize(PersonalizationScope scope, BinaryWebPartSerializerFlag binaryWebPartSerializerFlags, BinaryWebPartSerializerWriter writer) +87
    Microsoft.SharePoint.WebPartPages.BinaryWebPartSerializer.Serialize(SerializationMode mode, BinaryWebPartSerializerFlag binaryWebPartSerializerFlags, SPSerializationBinderBase serializationBinder, BinaryWebPartSerializerWriter writer) +706
    Microsoft.SharePoint.WebPartPages.SPWebPartManager.AddWebPartToStore(WebPart webPart, Int32 viewId, String viewGuid) +455
    Microsoft.SharePoint.WebPartPages.SPWebPartManager.AddWebPartInternal(SPSupersetWebPart superset, Boolean throwIfLocked) +158
    Microsoft.SharePoint.Publishing.PublishingPage.CopyAllWebParts(String destinationPageUrlServerRelative, SPWeb destinationPageWeb, String sourcePageUrlServerRelative, SPWeb sourcePageWeb, Boolean shouldOverwriteDestinationWebParts) +564
    Microsoft.SharePoint.Publishing.WebControls.EditingMenuActions.PageLayoutAction.changePageLayout(String newPageLayoutUrl) +421
    Microsoft.SharePoint.Publishing.WebControls.EditingMenuActions.PageLayoutAction.RaisePostBackEvent(String eventArgument) +128
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +6016

Leave a comment

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