Back to Insights

Programmatically change content on a Wiki Page in SharePoint 2010

SharePoint 2010 comes with some exciting new features, one of which revolves around the Wiki Pages and/or Site Pages and is primarily end-user centric. This feature allows end-users to place different elements on a page, similarly to how they would normally author an HTML page. Common SharePoint functions like Web Parts can also be inserted inline inside the Wiki page without having predefined Web Part zones on the page layout itself. More about this later...

The default site definition in SharePoint 2010 comes with a Site Page example:

Default SharePoint 2010 Home Page

We can programatically change the content of this page using the SharePoint API. Before we do this, we need to understand a few things:

  1. The Wiki Page is like any other SharePoint page but with a special field called "WikiField"
  2. The content of WikiField is HTML
  3. Any Web Part that you insert into the Wiki Page is managed by a hidden Web Part Zone referenced as "WPZ"
  4. If you want to be able to apply the column settings provided on the Wiki page editing tool bar, you will need to format the HTML accordingly

With this in mind, let's look at the code. The following code example is writen as a command-line tool to make it simple to understand. Of course you can do the same inside a feature receiver or an stsadm extension, or even as commandlets to be used in PowerShell.

First we define the high level logic of what we will be doing:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Publishing.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls.WebParts;
using System.Globalization;

namespace ChangeContentOfWikiPage
{
	class Program
	{
		static void Main(string[] args)
		{
			Execute();
		}

		private static void Execute()
		{
			using (SPSite site = new SPSite("http://YourServerUrl/"))
			{
				using (SPWeb web = site.OpenWeb())
				{
					// use an extension method to return a SPList representating the Site Pages Library
					SPList sitePagesLibrary = web.GetSitePagesLibrary();
					
					// Ensure the site pages library exists and is the right type
					EnsureSitePagesLibrary(web, sitePagesLibrary);

					// 
					string homePageFileName = SPUtility.GetLocalizedString("$Resources:core,WikiPageHomePageName;", "core", web.Language);
					string homePageUrl = string.Concat(new object[] { sitePagesLibrary.RootFolder.ServerRelativeUrl, '/', homePageFileName, ".aspx" });
					SPFile homePage = web.GetFile(homePageUrl);
					if (homePage.Exists)
					{
						// instantiate a webpart that you like to add to the Wiki page
						ContentEditorWebPart wp = new ContentEditorWebPart();
						wp.Title = "Test Web Part";

						// Replace the current wiki page content
						ChangeWikiContent(homePage, GenerateNewWikiContent());

						// insert the web part to the Wiki page with a specific content.
						InsertWebPartIntoWikiPage(homePage, wp, "{{1}}");
					}
				}
			}
		}
	}
}

The extension method for SPList is defined as:

public static class SharePointExtensions
{

	public static SPList GetSitePagesLibrary(this SPWeb web)
	{
		SPList wikiList;

		try
		{
			string serverRelativeUrl = web.ServerRelativeUrl;
			if (serverRelativeUrl == "/")
			{
				serverRelativeUrl = "/SitePages";
			}
			else
			{
				serverRelativeUrl = serverRelativeUrl + "/SitePages";
			}
			wikiList = web.GetList(serverRelativeUrl);
		}
		catch
		{
			wikiList = null;
		}
		if ((wikiList != null) && (wikiList.BaseTemplate != SPListTemplateType.WebPageLibrary))
		{
			wikiList = null;
		}

		return wikiList;

	}
}

Let's look at some of the methods being referenced by the Execute() method.

The EnsureSitePagesLibrary method checks and ensures the SPList is ready and is of the right type.

private static void EnsureSitePagesLibrary(SPWeb web, SPList sitePagesLibrary)
{
	if (sitePagesLibrary == null)
	{
		sitePagesLibrary = web.Lists.EnsureSitePagesLibrary();
	}

	if (sitePagesLibrary == null)
	{
		throw new SPException(SPResource.GetString("ListGone", new object[0]));
	}
	if (sitePagesLibrary.BaseTemplate != SPListTemplateType.WebPageLibrary)
	{
		throw new SPException(SPResource.GetString("OnlyInWikiLibraries", new object[0]));
	}
	if (sitePagesLibrary.ParentWeb != web)
	{
		throw new SPException(SPResource.GetString("WikiNotInWebException", new object[0]));
	}
}

The GenerateNewWikiContent() method creates a string that has the required HTML elements and also contains a string token {{1}} that we will replace with a Web Part reference later. The HTML elements are essential to ensure end-users can apply columns to the page.

public static string GenerateNewWikiContent()
{
                StringBuilder sb = new StringBuilder("");
                StringBuilder column1 = new StringBuilder("");
                StringBuilder column2 = new StringBuilder("");

                sb.Append("<table id='layoutsTable' style='width: 100%'><tbody><tr style='vertical-align:top'>");

                // prepare the content of column 1
                column1.Append("<td style='width: 66.6%'><div class='ms-rte-layoutszone-outer' style='width:100%'><div class='ms-rte-layoutszone-inner' style='min-height:60px;word-wrap:break-word'>");
                column1.Append("<p class='ms-rteFontSize-6 ms-rteThemeForeColor-7-0' style='font-size: 32px;'>Welcome to your site!</p>");
                column1.Append("<p/>");
                column1.Append("<p>Add a new image, change this welcome text or add new lists to this page by clicking the edit button above. You can click on Shared Documents to add files or on the calendar to create new team events. Use the links in the getting started section to share your site and customize its look.</p>");
                column1.Append("<p/>");

                // the following is a token that will be replaced by InsertWebPartIntoWikiPage()
                column1.Append(" {{1}}");

                column1.Append("</div></div></td>");


                // prepare the content of column 2
                column2.Append("<td style='width: 33.3%'><div class='ms-rte-layoutszone-outer' style='width: 100%'><div class='ms-rte-layoutszone-inner' style='min-height: 60px; word-wrap: break-word'>");
                column2.Append("</div></div></td>");

                sb.Append(column1.ToString());
                sb.Append(column2.ToString());
                sb.Append("</tr></tbody></table><span id='layoutsData' style='display: none'>false,false,2</span>");

                return sb.ToString();
}

The ChangeWikiContent() method applies the changes to the "WikiField" of the SPItem that represents the page and updates the item.

public static void ChangeWikiContent(SPFile wikiFile, string content)
{
	if (wikiFile == null)
	{
		throw new ArgumentNullException("wikiFile");
	}

	wikiFile.Item["WikiField"] = content;
	wikiFile.Item.Update();
}

The InsertWebPartIntoWikiPage() method inserts a web part instance into the Wiki Page by first inserting the web part into the web part zone "WPZ", and then converts its Storage Key into an ID that is recognizable by SharePoint Wiki Pages. Once we have this ID, we get the "WikiField" content and replace the string token {{1}} already inserted as part of the content with the ID.

public static void InsertWebPartIntoWikiPage(SPFile wikiFile, System.Web.UI.WebControls.WebParts.WebPart webpart, string replaceToken)
{
	if (wikiFile == null)
	{
		throw new ArgumentNullException("wikiFile");
	}
	if (webpart == null)
	{
		throw new ArgumentNullException("webpart");
	}
	string str = (string)wikiFile.Item["WikiField"];

	SPLimitedWebPartManager limitedWebPartManager = wikiFile.GetLimitedWebPartManager(PersonalizationScope.Shared);
	Guid storageKey = Guid.NewGuid();
	string str2 = StorageKeyToID(storageKey);
	webpart.ID = str2;
	limitedWebPartManager.AddWebPart(webpart, "wpz", 0);
	string str3 = string.Format(CultureInfo.InvariantCulture, "<div class='ms-rtestate-read ms-rte-wpbox' contentEditable='false'><div class='ms-rtestate-read {0}' id='div_{0}'></div><div style='display:none' id='vid_{0}'/></div>", new object[] { storageKey.ToString("D") });
	if (str == null)
	{
		str = str3;
	}
	else
	{
		if (!str.Contains(replaceToken))
		{
			str = str + str3;
		}
		else
		{
			str = str.Replace(replaceToken, str3);
		}
	}
	wikiFile.Item["WikiField"] = str;
	wikiFile.Item.Update();
}

And lastly, the StorageKeyToID() method helps convert the Storage Key to an ID referenecable inside a "WikiField" content:

public static string StorageKeyToID(Guid storageKey)
{
	if (!(Guid.Empty == storageKey))
	{
		return ("g_" + storageKey.ToString().Replace('-', '_'));
	}
	return string.Empty;
}

In the above code example, I replaced the existing content of the Wiki Page with my own message, as well as inserting an out-of-the-box Content Editor Web Part into part of the Wiki Page content, all through code. Here is what the page looks like after the code executed:

Modified Wiki Page

Hope you find this blog post useful!

Share