Tuesday, November 1, 2011

Creating a Wiki Page template For SharePoint 2010 Foundation

Introduction

As I have ever written several time in my previous posts, one of the severe limitation of SharePoint Foundation is that the Wiki Pages are based on a single template wkpstd.aspx located at

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\DocumentTemplates

If you try to add a wiki page programmatically to a wiki page library of a SharePoint Foundation team site and you want it to be ghosted you must use the method SPFileCollection.Add with this signature :

 Add(String, SPTemplateFileType)

And pass the reference of the wiki page template wkpstd.aspx to the SPTemplate parameter. If you use any other signature, you will be able to add a wikipage, but it will be unghosted.

I am now going to show you a very amazing workaround to use another template than the wkpstd.aspx one and will process in  two steps. First I will demonstrate it so as you can easily understand its principle then I will provide a programmatic way of doing it.

Demonstration

Start creating your new template by duplicating the wkpstd.aspx and rename it wkpcustom.aspx, then perform a little operation of customization in order each page based on this new template can tell its name :

In the page directive section add the namespace System.Diagnostics because the wiki pages will tell their nam in the debugView...

<%@ Import Namespace="System.Diagnostics" %>

Then, at the top of the PlaceHolderMain section paste this code:

protected override void OnPreInit(EventArgs e)
{
     base.OnPreInit(e);

    Debug.WriteLine(SPContext.Current.File.Name);
}

 

Then, we are going to prepare a feature to reference this wkpcustom.aspx file in a SharePoint Foundation wiki page library.

Assume we call the feature

 Provisioning.SPF_WikiPages

Here is the feature.xml code:

<?xml version="1.0" encoding="utf-8"?>

<Feature Id="00BFEA71-2062-426C-90BF-714C59600AAA"

Title="Adding pre populate wiki pages"

Description="This feature will add pre-populate wiki pages to the site pages wiki library of this site"

Version="1.0.0.0"

Scope="Web"

Hidden="false"

DefaultResourceFile="core"

xmlns="http://schemas.microsoft.com/sharepoint/">

  <ElementManifests>

    <ElementManifest Location="elements.xml" />

  </ElementManifests>

</Feature>

And this is the xml code of the elements.xml file

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <Module Url="SitePages" >

    <File Url="wkpcustom.aspx" Type="GhostableInLibrary"></File>

  </Module>

</Elements>

 

Last, a screen shot of the Provisioning.SPF_WikiPages feature folder

 

Then, install the feature and activate it for one of the team site of your Farm and you will have a reference to your page in the site pages library of this team site.

 

You can see a reference to the wkpcustom file located in the feature folder on the server

 

And because this file was provisioned by a feature, although there is in line code in it, if you display the wiki page using this file, it will work, the code will run and will write the name of the page in the debugview.

 

But, wait a minute, this file is already a template. It is a template for just one page within the site pages library but it is exactly like the wkpstd.aspx for the other pages. So assume we could have several pages within the library based on this file we would have created a new template. I see some of you smiling...

You have understood... It is what we are going to do now...

Now is the time to use another workaround I have already shown in a previous post to open our library in explorer mode.
So switch to shared documents library, open it in explorer mode, then using the explorer folder navigation go back to the site pages library but in explorer mode now

 

Then rename the page in "page 01.aspx"

 

then go back to the site pages library within the SharePoint UI. You will notice that the page is renamed and if you displayed it, its name in the debugview has changed too. While renamed, the page remains in its ghosted state and linked to the "template".

 

Now deactivate the feature, then reactivate it and you will have a new page wkpcustom.aspx beside the "page 01.aspx" and the two pages are linked to the same file on the server, so if we display one then the other, debugview will trace the two names based on the code of an unique file on the server: we have created our first custom template for a wiki page library in SharePoint Foundation!

 

Now we have done the demonstration we just have to find the way to do it programmatically:

Coding the sequence

this applicative page called from your site will provision 9 pages in your site page library pointing on the same unique template wkpcustom.aspx located in the feature folder. If you modify the file in the folder, you will modify the 9 pages

 

<%@ Page Language="C#" AutoEventWireup="true" Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase"

    DynamicMasterPageFile="~masterurl/default.master" %>

 

<%@ Assembly Name="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" %>

<%@ Import Namespace="Microsoft.SharePoint" %>

<%@ Import Namespace="Microsoft.SharePoint.Administration" %>

<%@ Import Namespace="System.Text" %>

<%@ Import Namespace="System.Linq" %>

<%@ Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

 

<asp:content id="PageHead" contentplaceholderid="PlaceHolderAdditionalPageHead" runat="server">

</asp:content>

<asp:content id="Main" contentplaceholderid="PlaceHolderMain" runat="server">

 

<script language="C#" runat="server">

 

    protected override void OnLoad(EventArgs e)

    {

        base.OnLoad(e);

 

        SPWeb myWeb = SPContext.Current.Web;

        myWeb.AllowUnsafeUpdates = true;

 

        for (int i = 1; i < 10; i++)

        {

 

            if (myWeb.Features[new Guid("{00BFEA71-2062-426C-90BF-714C59600AAA}")] != null)

            {

                myWeb.Features.Remove(new Guid("{00BFEA71-2062-426C-90BF-714C59600AAA}"));

            }

 

            myWeb.Features.Add(new Guid("{00BFEA71-2062-426C-90BF-714C59600AAA}"));

 

            SPList myList = myWeb.Lists["Site Pages"];

 

            SPListItem myItem = null;

 

            SPContext.Current.Web.AllowUnsafeUpdates = true;

 

            foreach (SPListItem anItem in myList.Items)

            {

                if (anItem.Name == "wkpcustom.aspx")

                {

                    myItem = anItem;

                }

            }

 

            string destinationUrl = myWeb.Url + "/" + myList.RootFolder.Url + "/" + "Wiki_page0" + i + ".aspx";

            myItem.File.MoveTo(destinationUrl);

            myItem.File.Update();

 

            myWeb.Features.Remove(new Guid("{00BFEA71-2062-426C-90BF-714C59600AAA}"));

        }

 

        lbl1.Text = "Your files has been provisionned successfully...";

    }

 

</script>

 

<asp:Label runat="server" ID="lbl1" ></asp:Label>

 

 

</asp:content>

<asp:content id="PageTitle" contentplaceholderid="PlaceHolderPageTitle" runat="server">

 

Provisioning Team Site Wiki Pages

 

</asp:content>

<asp:content id="PageTitleInTitleArea" contentplaceholderid="PlaceHolderPageTitleInTitleArea"

    runat="server">

 

Provisioning Team Site Wiki Pages

 

</asp:content>

 

 

Here are the screen shots of the applicative page after its provisioning job is finished

 

and the site pages library with the 9 new pages

 

And if I call the 9 pages, each of them will tell me its name.

 

And now, I have changed the instruction of the name displaying in the template, and I have called back the 9 pages and here is the result.

 

Have a lot of fun with that!