How to add a Web Part into a SitePages/Home.aspx using CSOM

csomsharepoint

has anyone managed to add a Web Part into a Wiki page using CSOM?

Background: Home.aspx is a Wiki page and all its WPs are located in the rich text zone (in fact a "WikiField" column). Technically they are located in a hidden "wpz" web part zone and in addition to this there is always a placeholder with WP's ID in the WikiField column.

I've modified the existing server-side code seen on http://blog.mastykarz.nl/programmatically-adding-web-parts-rich-content-sharepoint-2010/ and http://640kbisenough.com/2014/06/26/sharepoint-2013-moving-webparts-programmatically-to-rich-content-zone/ into this:

using System;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.WebParts;

public class Class1
{
    void DeployWebPart(ClientContext clientContext, string zone, string pattern, string position)
    {
        List library = clientContext.Web.GetList("/sites/site/SitePages/");
        clientContext.Load(library);
        clientContext.ExecuteQuery();
        CamlQuery query = CamlQuery.CreateAllItemsQuery(100);
        ListItemCollection itemColl = library.GetItems(query);
        clientContext.Load(itemColl, items => items.Include(i => i.Id, i => i.DisplayName, i => i["WikiField"]));
        clientContext.ExecuteQuery();
        ListItem item = itemColl.Where(i => i.DisplayName == "Home").First();
        clientContext.ExecuteQuery();
        File page = item.File;
        LimitedWebPartManager lwm = page.GetLimitedWebPartManager(PersonalizationScope.Shared);
        string xmlWebPart = @"<webParts>...</webParts>";
        WebPartDefinition wpd = lwm.ImportWebPart(xmlWebPart);
        WebPartDefinition realWpd = lwm.AddWebPart(wpd.WebPart, "wpz", 0);
        List targetList = clientContext.Web.GetList("/sites/site/Announcements/");
        clientContext.Load(targetList, l => l.Views);
        clientContext.Load(realWpd);
        clientContext.ExecuteQuery();
        string wpId = String.Format("g_{0}", realWpd.Id.ToString().Replace('-', '_'));
        if (zone == "wpz")
        {
            string htmlcontent = String.Format(CultureInfo.InvariantCulture, "<div class=\"ms-rtestate-read ms-rte-wpbox\" contenteditable=\"false\"><div class=\"ms-rtestate-notify  ms-rtestate-read {0}\" id=\"div_{0}\"></div><div id=\"vid_{0}\" style=\"display:none;\"></div></div>", new object[] { realWpd.Id.ToString("D") });
            string content = item["WikiField"] as string;
            System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(System.Text.RegularExpressions.Regex.Escape(pattern));
            if (position == "before")
            {
                content = regex.Replace(content, (htmlcontent + pattern), 1);
            }
            else
            {
                content = regex.Replace(content, (pattern + htmlcontent), 1);
            }
            item.Update();
            clientContext.ExecuteQuery();
        }
    }
}

Everything works fine until the last item.Update() and clientContext.ExecuteQuery() are being invoked. Before the Update() the new placeholder gets properly inserted into the WikiField contents. But after the Update() the WikiField contents reverts back to its original state (!)

Note: As an alternative it is possible to add the WP into another zone (eg. "Bottom"). In this case the WP gets displayed on the page. But it has two major drawbacks: The newly created zone is not well formatted and the WP cannot be moved or even deleted.

Thanks for any input on this.

Best Answer

The following example demonstrates how to add web part into Enterprise Wiki page:

public static void AddWebPartIntoWikiPage(ClientContext context, string pageUrl, string webPartXml)
{
        var page = context.Web.GetFileByServerRelativeUrl(pageUrl);
        var webPartManager = page.GetLimitedWebPartManager(PersonalizationScope.Shared);

        var importedWebPart = webPartManager.ImportWebPart(webPartXml);
        var webPart = webPartManager.AddWebPart(importedWebPart.WebPart, "wpz", 0);
        context.Load(webPart);
        context.ExecuteQuery();

        string marker = 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></div>", webPart.Id);
        ListItem item = page.ListItemAllFields;
        context.Load(item);
        context.ExecuteQuery();
        item["PublishingPageContent"] = marker; 
        item.Update();
        context.ExecuteQuery();
}

Usage

var webPartXml = System.IO.File.ReadAllText(filePath);
using (var ctx = new ClientContext(webUri))
{
    AddWebPartIntoWikiPage(ctx, wikiPageUrl,webPartXml);
}

Result

enter image description here

Related Topic