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!

 

5 comments:

Anonymous said...

I am hopelessly trying to change the home page on a team site, but I am getting nowhere. I tried your method but when I try to access the site pages through explorer view it reverts me back to the web view. So I cannot do all that you are saying to.

Can you please assist?

Godfrey

Marc Charmois said...

Hi Godfrey,

my post is for changing the template of all the wiki pages of a team site.
You can change the home page of a team site using the SharePoint UI and don't need specific development operations for just that...

If you want to change the template for only one page you can also deploy a custom template once using a feature, much easier...

You can also customize the home page of your site by using the SharePoint Designer. It will unghost the page, but if you don't need great performance and are ready to deal with content deployment it could worth it , much much more easier..

There are so many solutions depending on what is your goal...

It seems you have trouble with explorer view. It doesn't work well for all environments.
Could you at least open the Shared Document library with the Explorer View ?

If not, Check with your IE version (I think it is working only with IE) and if the Front Page extensions are activated on the server...

Anonymous said...

Marc,
Thanks a lot for the detialed tutorials of tricks and workarounds. Wonderful work and thank you for sharing.

I have a different question in regards to SP 2010 team site wiki pages. My company recently is testing migration from SP 2007 to SP 2010, we noticed that the wikis on the target (SP 2010) server are missing columns that a wiki library has. For example, underneath a wiki content column, you would see in SP 2007 addittional information about the given post like author, date, tags, (etc whatever columns are set up on that Document Library).

In SP 2010, there is only wiki content displayed on the page, but none of the addittional wiki columns are visable.

How far do I need to go to tweak existing SP 2010 wiki wkpstd template? Please advice when you get a chance.

Kind Regards,
Barb

Marc Charmois said...

Hi Barb,

There is several solutions to your concern

1 - The cleaner way to get what you want is, yes, tweaking the wkpstd template by using my other post :

http://mosshowto.blogspot.ca/2010/06/sharepoint-2010-wiki-template.html

In that post, I replaced programmatically the EmbeddedFormField control of the template by a custom one that has property to render a text.

So you can bind the custom control to the information you want to display : author name, date, etc.

Don't use a delegate control as I did in my post but do it within a custom master page.

to get the metadata of the wikipage use this other post of my blog :

http://mosshowto.blogspot.ca/2008/10/use-layout-page-metadata-in-masterpages.html

that is to mean use the

SPContext.Current.File

or

SPContext.Current.Item

2 - If you don't feel like doing all that job, you can "cheat".
Don't tweak the wkpstd template but use the master page to write the metadata you need underneath the wikipage content.
You just will have to filter in master page if it is a wiki page or not that is rendered.

Page.TemplateControl.ToString().Contains("ASP.WKPSTD_ASPX")

3 - you can use a webpart that does the job and place it at the end of the page.

4 - you can do this using Ajax by writing a proxy page that can provide the metadata of a wiki page based on the site name and the wikipage ID...
The current page will send an Ajax request that will ask the proxy page to give its own required metadata...

Hope that helps...

Marc

NW Media Design said...

Thanks Marc for responding promptly, I appreciate that. Now back to choosing best method :) to solve the issue.

Kind Regards,
Barbara