Update 2010-10-24: Added info about the layoutsData span and changed wording mostly to clarify which client OM I was using and why.

When trying to add a Web Part to a SharePoint 2010 team site using the Client Object Model (client OM) I found lots of posts. Unfortunately they either didn’t use the client OM or the team site wasn’t based on wiki pages. Actually I still haven’t found a single post covering this scenario. So here’s how to do it.

The Big Picture

If you add a Web Part to a Web Part page you simply tell the Web Part manager in which zone to put it. But if your page is a wiki page you also have to mark the place in HTML where the Web Part should show up. And as you probably know SharePoint 2010 team sites are based on wiki pages by default.

This was for setting up automated tests on a remote machine so I’m using the managed client OM. After acquiring the client context the next step is to get a reference that lets you access both the Web Part manager and the wiki content. The wiki content is stored in an additional form field named WikiField and you need the page as a ListItem reference to access it. A reference to the page as a File object will not work.

A small twist: if you have the .wsp file but not the .webpart file you’ll have to extract it manually as there is no way to get at the contents of a .wsp file using managed code.

Step 1: Adding the Web Part to the Web Part Zone

Once you have got the .wsp file you can use it’s content to have the Web Part manager insert the Web Part into the wiki page’s one and only Web Part zone. This zone is hidden and shows up in the HTML with an ID like ctl00_panelZone.

Some details on using the Web Part manager:

The WebPartDefinition’s Id property is read-only and you have to call ImportWebPart() to have a GUID created for you. This is different from SPWebPart where you can specify a value.

AddWebPart() adds the Web Part to the wiki page’s single Web Part zone called “wpz”–you can check that name by spying into Microsoft.SharePoint.WebPartPages.WikiEditPage’s InsertWebPartIntoWikiPage() with Reflector.

There’s no way to check whether a page already contains a specific type of Web Part using the client OM. It reports all Web Parts as being of type Microsoft.SharePoint.Client.WebParts.WebPart.

Step 2: Adding a Reference to the Web Part into the HTML

The final step is to add a reference to the Web Part into the HTML–as you can imagine this defines where the Web Part will actually show up. The reference is created by three div elements like below referencing the Web Part’s Id. It’s based on a GUID and in this case is g_2252e9e2_86d2_4c6a_9c60_6de78cd15c84.

Hi Dieter, thanks for such a compelling article — I too have struggled to find any info on how to programmatically customise wiki pages. I still need some help however…

I have added a custom button to the SharePoint Ribbon which launches a simple modal dialog. No problems so far. When the user hits OK and closes the window, I am trying to add a web part inside the RTE (this appears to be slightly different to your example, where you add the web part to the list item’s HTML field and then update/save it). I know the scenario I’m trying to achieve is possible because the SharePoint Ribbon already exposes this very same functionality! (if you edit the page, then click Insert -> Web Part -> Contact Details). This puts a Contact Details web part inside the RTE at the current cursor location with the exact same HTML as you have outlined in your example.

Could you please shed any light on how I might go about doing this? I can’t find any documentation on how to programmatically insert a web part into the RTE — nor can I find the code in the SharePoint assemblies which does this.

to add a web part while the user is editing your best bet would be to figure out how the ribbon buttons do it–I never tried. This post should get you started: Sharepoint 2010 Ribbon Control and Rich Text Editor. You could also have a look at wpadder.debug.js in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS.

Coincidentally, the article you mentioned is also the only one I could find that features any client side script for manipulating text in the RTE editor pane.

“wpadder.debug.js” has already proven useful though… I’m able to add OOTB web parts directly into the editor by simply calling some of the functions in it. For those playing at home: the following JavaScript function adds the web part reference divs to the HTML and returns you the ID of the new part:

var webPartId = _WPAdder.prototype._createWebpartPlaceholderInRte()

From here, the script issues a simple postback passing in the web part zone ID and index (“wpz” and 0, as metioned in the post) and adds the web part to the page content. In my case, I need to set some properties on the web part before it gets added to the page, so I will try overriding this postback code. I’ll add a working code sample below as soon as I’ve got it done for anybody experiencing the same pains as me… Thanks again.

I assume you already know how to add your custom button to the ribbon? If not, or you don’t understand any of the terms I’ve used below, refer to this post.

Once you have your ribbon button defined as a CustomAction your Elements.xml, you only need to call one or two of the built-in SharePoint JavaScript functions to get your web part added to the RTE. Here’s how…

1. Inside your CommandUIHandler, you will first need to ensure that the window.WPAdder object has been instantiated (this is the client-side object that SharePoint uses to add web parts to the page, so it does all the work for you).

2. You need to locate the source web part you want to add to the page in the gallery. I have done this by iterating through each category and item in the list and then comparing the Title values. You could use the ID or anything else to match on.

3. You simply call the following function which internally, will “clone” your source web part, add it to the page, add the mark-up to the RTE, and then refresh the RTE. It is this “refresh” that is probably preventing you from seeing your web part in the editor.

window.WPAdder._addItemToPage(sourceWebPart, '0', 0);

The other parameters I have passed in to this function are the web part zone ID and index. These are both zero, and are always the same on publishing pages.