Deploying Publishing Page Layouts and Pages Using Features

In this post we go through the step-by-step process of creating a SharePoint solution that deploys a publishing page layout and a publishing page for press releases. Provisioning page layouts and pages using features and solution packages (*.wsp) allows for improved code reuse and makes it easier to move the solution between environments (development, testing, staging, and production).

As a matter of fact, there are already quite a few examples on the web that cover the topic of creating a SharePoint 2010 publishing page layout in Visual Studio 2010. One particularly good article is posted from Becky Bertram on her blog here.

However, in a recent project of ours, we also needed to deploy publishing pages together with the page layout, and after coming up with the solution, we decided to share our experience. The SharePoint Developer Tools in Visual Studio 2010 do not include specific project item templates for doing this, but it can be achieved using the module item template.

Here is how our solution will look like when we are done:

Solution Structure

Please note that in order to successfully deploy the solution the target SharePoint site should be a publishing site.

Press Release Content Type

First things first, we need to create a custom content type with fields that will hold the information for a press release.

We start by creating a new C# project, using the “Empty SharePoint Project” template in Visual Studio 2010. Then we add an Empty Element item to the project and give it the name SiteColumns. In the element we define a couple of site columns to be used in the custom Press Release content type, namely a Single line of text field for the byline and a Publishing HTML field for the press release body.

  <!-- new site column based off the "single line of text" field type -->
  <Field SourceID="http://schemas.microsoft.com/sharepoint/v3"
         ID="{0D499375-D734-43DB-A2EE-343B490B9CB0}"
         Name="PRByLine"
         StaticName="PRByLine"
         DisplayName="Press Release ByLine"
         Group="Press Release"
         Type="Text"
         Required="FALSE"
         Sealed="FALSE"
         Hidden="FALSE" />

  <!-- new site column based off the "publishing html" field type -->
  <Field SourceID="http://schemas.microsoft.com/sharepoint/v3"
         ID="{0C50E0BF-A35C-4A38-B784-AFA60BBADC00}"
         Name="PRBody"
         StaticName="PRBody"
         DisplayName="Press Release Body"
         Group="Press Release"
         Type="HTML"
         Required="FALSE"
         Sealed="FALSE"
         Hidden="FALSE"
         RichText="TRUE"
         RichTextMode="FullHtml"/>

Adding this element to the project causes SharePoint Developer Tools to automatically create a feature. We rename the feature to ContentType and set its scope to Site. We also give the feature a meaningful title and description.

Next, we add a new Content Type item to the project in which we define the Press Release content type. We make it inherit from the Page content type which contains the minimum required information for the page, such as the file name, page layout to use, a thumbnail image of the page, etc. Then we add references to the PRByLine and PRBody site columns.

  <!-- Parent ContentType: Page (0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39) -->
  <ContentType ID="0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39008D9A0288B03E457ABC84303BCDAA9CD7"
               Name="Press Release"
               Description="Press Release"
               Group="Press Release"
               Inherits="TRUE"
               Version="0">
    <FieldRefs>
      <FieldRef ID="{0D499375-D734-43DB-A2EE-343B490B9CB0}" Name="PRByLine" />
      <FieldRef ID="{0C50E0BF-A35C-4A38-B784-AFA60BBADC00}" Name="PRBody" />
    </FieldRefs>
  </ContentType>

Press Release Content Type Binding

Having defined our custom content type, we add a new web-scoped feature to the project which we name PageLayout. We will use this feature to deploy the page layout and publishing page but before that we have to perform an additional step that is by far the trickiest part of our solution. I have to admit that when preparing the sample for today’s post I initially skipped this step and I didn’t realize the solution was not actually working until I deployed on a clean SharePoint site.

What we need to do is to add another Empty Element item to our project in which we define the following content type binding:

<ContentTypeBinding ContentTypeId="0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39008D9A0288B03E457ABC84303BCDAA9CD7" ListUrl="Pages" />

What this code does is add the Press Release content type to the Pages library of the target SharePoint site. This binding needs to be done before we deploy our publishing page. If our custom content type is not bound to the library at the time the page is provisioned, the page will be assigned the default Page content type.

Press Release Page Layout

In SharePoint 2010 we need to provision custom page layouts to the Master Page Gallery in the target site collection. In order to do this we first add a module project item named PressReleaseLayout to our project. By default, the module contains a sample text file which we do not need and we can safely delete.

We then add a new file named PressRelease.aspx to our module. In the new file we add the following markup:

<%@ Page language="C#" Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage, Microsoft.SharePoint.Publishing, [four-part-assembly-name]" %>
<%@ Register Assembly="Microsoft.SharePoint, [four-part-assembly-name]" TagPrefix="SharePointWebControls" %>
<%@ Register Assembly="Microsoft.SharePoint.Publishing [four-part-assembly-name]" TagPrefix="PublishingWebControls" %>

<asp:Content runat="server" contentplaceholderid="PlaceHolderPageTitle">
  <SharePointWebControls:FieldValue id="PageTitle" FieldName="Title" runat="server"/>
</asp:Content>

<asp:Content runat="server" contentplaceholderid="PlaceHolderPageTitleInTitleArea">
  <SharePointWebControls:TextField runat="server" id="TitleField" FieldName="Title"/>
</asp:Content>

<asp:Content runat="server" contentplaceholderid="PlaceHolderMain">
  <SharePointWebControls:TextField ID="TextField1" FieldName="PRByLine" runat="server"/>
  <br />
  <PublishingWebControls:RichHtmlField ID="RichHtmlField1" FieldName="PRBody" runat="server"/>
</asp:Content>

This markup creates a basic rendering template for the Press Release content type by defining a TextField control for displaying and editing the PRByLine field and a RichHtmlField control for the PRBody field.

Once we have created our page layout template, we need to edit the CAML definition of the module. Here, we need to wire up our module to point to the URL of the Master Page Gallery, so we add a “Url” attribute to the Module node and point it to “_catalogs/masterpage”.

Then we add a File element inside the Module node. The File element has three important attributes:

  • Url – Specifies the virtual path for the file, i.e. where the file should be deployed on the server.
  • Path – Specifies the physical path to the file on the file system relative to the feature folder.
  • Type – Possible values include Ghostable and GhostableInLibrary. GhostableInLibrary specifies that the file will be provisioned as a list item in a list whose base type is DocumentLibrary. This is the option we should choose in our case.

Next we need to specify some properties for the list item that gets created in the Master Page Gallery for the page layout:

  • Title - The name of the page layout that will show up when it is being selected by the content author.
  • Content Type – This is the ID of the page layout content type. This value should be used for all page layouts because it is what SharePoint will be looking for.
  • Publishing Associated Content Type – This value tells SharePoint which content type this layout is associated with. It contains two delimited values separated with ;#. The first value is the name of the content type and the second value is the content type’s unique ID.

That’s it – we are done creating our page layout. Here is the complete module definition:

<Module Name="PressReleaseLayout" RootWebOnly="TRUE"
        Path="PressReleaseLayout" Url="_catalogs/masterpage">
    <File Url="PressRelease.aspx" Path="PressRelease.aspx" Type="GhostableInLibrary">
      <Property Name="PublishingAssociatedContentType" Value=";#Press Release;#0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39008d9a0288b03e457abc84303bcdaa9cd7;#" />
      <Property Name="ContentType" Value="$Resources:cmscore,contenttype_pagelayout_name;" />
      <Property Name="Title" Value="Press Release Layout" />
    </File>
</Module>

If we now deploy our solution to SharePoint and create a new publishing page, we will see our page layout in the list of page layouts to choose from:

Page Layout

Press Release Page

We have reached the final part of our solution – provisioning a publishing page based on the Press Release page layout. In order to do this we add another module item to our project and name it Pages. We delete the sample text file which we do not need.

Then we edit the definition of the Module element and change its “Url” attribute to point to “Pages”, which is the relative URL of the Pages library within the SharePoint site.

Inside the Module node, we add a File node with the following CAML:

<File Path="PressReleaseLayout\PressRelease.aspx" Url="PressRelease1.aspx" Type="GhostableInLibrary">
  <Property Name="Title" Value="Press Release 1"/>
  <Property Name="PublishingPageLayout" Value="~SiteCollection/_catalogs/masterpage/PressRelease.aspx, Press Release Layout"/>
  <Property Name="ContentTypeId" Value="0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF39008D9A0288B03E457ABC84303BCDAA9CD7" />
</File>

This code instructs SharePoint to provision an instance of the Press Release page layout we created in the previous step. The page is named PressRelease1.aspx and has the following properties:

  • Title - The title of the page that will show up in the UI.
  • PublishingPageLayout – The site collection relative URL and the title of the page layout, separated with a comma.
  • ContentTypeId – The ID of the content type associated with the publishing page.

We are done! Now if we deploy our solution, navigate to the target SharePoint site and open the Pages library, we should see our publishing page:

Pages Library

When we open the page for edit, we are able to insert information into the press release byline and body:

Page

Full code sample is available for download here.

4 thoughts on “Deploying Publishing Page Layouts and Pages Using Features

  1. Teodora, Excellent article. Very clear and useful. Plus the code sample works like a charm. Was wondering did you need implement rollback of articfacts if the features were deactivated?

    • Hi Amir,

      Actually rollback was not necessary in our case. If you need to clean up items in your scenario, then you will have to write some code in the Feature Deactivated event of the feature event receiver.

  2. Pingback: Deploying Publishing Page from Page Layout in Another Feature | Tippoint

Leave a Reply to Teodora Gancheva Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>