5

I'd like to add custom Web Part to page without Web Part Zone programmatically, however, for some reason, I simply don't know how to do it.

I created blank new Page (Body Only)

PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(web);
string pageName = "NewPage.aspx";
PageLayout[] pageLayouts = pWeb.GetAvailablePageLayouts();
PageLayout newPage = pageLayouts[0]; //Body only type of page layout
PublishingPageCollection pages = pWeb.GetPublishingPages();
PublishingPage nPage = pages.Add(pageName, newPage);

Page is Created, Checked in and Published. This part works as charm.

However, when I try to add custom Web Part to it, code does nothing

SPFile file = web.GetFile(web.Url + "/Pages/NewPage.aspx");
file.CheckOut();
string err = string.Empty;
string wPartURL = web.Url + "/_catalogs/wp/MyWebPart.webpart";
SPLimitedWebPartManager manager = web.GetLimitedWebPartManager(web.Url + "/Pages/NewPage.aspx", PersonalizationScope.Shared);
XmlTextReader reader = new XmlTextReader(new StringReader(web.GetFileAsString(wPartURL)));
System.Web.UI.WebControls.WebParts.WebPart wp = (System.Web.UI.WebControls.WebParts.WebPart)manager.ImportWebPart(reader, out err);
wp.Title = "Web Part Title";
manager.AddWebPart(wp, "Page Content", 0);
manager.SaveChanges(wp);
file.Update();
web.Update();
manager.Dispose();
file.CheckIn("Checked in by Code");

In page's source, I can't find any "Zone" and I was trying to pass to AddWebPart method several different value (like "Page Content", "PageContent", "Central", and so on). Nothing worked, and not even once was thrown exception. I'm taking wild guess here, but I feel like I need to update something which I don't in upper code (and for this reason no error is ever risen). The above code is written as Console Application with no try / catch blocks.

EDIT: With @beavel help, I managed to get zoneID (Page Content), however, Web Part still isn't added to the page.

EDIT2: I found out that problem is - Body Only page layout doesn't have Web Part Zone and because of it SPLimitedWebPartManager fails to add Web Part. Since First of January 2014. the question was edited from "Add programmatically custom Web Part to page" to "Add programmatically custom Web Part to page without Web Part Zone"

1
  • I see you have already identified that the issue is related to adding a web part to a non web part zone. I'll be updating my answer shortly to reflect the change.
    – beavel
    Commented Jan 2, 2014 at 13:43

1 Answer 1

8

I've successfully done this in SP 2010 with PowerShell. I've done things slightly different, so let me try to translate and see if it works out for you.

Adding a Web Part to a WebPartZone

For your first section, add an .Update() on the page creation to commit the change to the DB:

PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(web);
string pageName = "NewPage.aspx";
PageLayout[] pageLayouts = pWeb.GetAvailablePageLayouts();
PageLayout newPage = pageLayouts[0]; //Body only type of page layout
PublishingPageCollection pages = pWeb.GetPublishingPages();
PublishingPage nPage = pages.Add(pageName, newPage);
nPage.Update();

For the second section, assuming it is continuing from the first:

//Skip grabbing the file again and use the reference you already have. To make sure 
//everything is aware of the changes you have made so far grab the SPLimitedWebPartManager off of the page object.
SPLimitedWebPartManager manager = nPage.ListItem.File.GetLimitedWebPartManager(PersonalizationScope.Shared);

//I instantiated the webpart differently, but this should work. I'm assuming it is valid.
string err = string.Empty;
string wPartURL = web.Url + "/_catalogs/wp/MyWebPart.webpart";
XmlTextReader reader = new XmlTextReader(new StringReader(web.GetFileAsString(wPartURL)));
System.Web.UI.WebControls.WebParts.WebPart wp = (System.Web.UI.WebControls.WebParts.WebPart)manager.ImportWebPart(reader, out err);

wp.Title = "Web Part Title";
manager.AddWebPart(wp, "Body", 0); //See the description below for how to determine Zone
manager.SaveChanges(wp);
nPage.Update();
pWeb.Update();
manager.Dispose(); // I don't do this line, but it may be alright
nPage.CheckIn("Checked in by Code");
nPage.ListItem.File.Publish("Publishing major version");

Adding a Web Part to a Rich Content Field (i.e. Page Content)

For this, I'll defer to a Microsoft MVP. Waldek Mastykarz has a post covering this topic. Essentially, when adding a web part to a Rich Content field the code gets wrapped with some specific HTML. Waldek details this in his post, and provides the sample code required to accomplish this. His code is below:

using (SPSite site = new SPSite("http://win2008/sites/publishing"))
{
    SPWeb web = site.RootWeb;
    SPFile page = web.GetFile("Pages/Lipsum.aspx");
    page.CheckOut();

    using (SPLimitedWebPartManager wpmgr = page.GetLimitedWebPartManager(PersonalizationScope.Shared))
    {
        Guid storageKey = Guid.NewGuid();
        string wpId = String.Format("g_{0}", storageKey.ToString().Replace('-', '_'));

        XmlElement p = new XmlDocument().CreateElement("p");
        p.InnerText = "Hello World";
        ContentEditorWebPart cewp = new ContentEditorWebPart
        {
            Content = p,
            ID = wpId
        };
        wpmgr.AddWebPart(cewp, "wpz", 0);

        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>", new object[] { storageKey.ToString("D") });
        SPListItem item = page.Item;
        string content = item["PublishingPageContent"] as string;
        item["PublishingPageContent"] = content.Replace("|", marker);
        item.Update();
    }

    page.CheckIn(String.Empty);
}

Identifying the Zone for SPLimitedWebPartManager.AddWebPart()

To find the 'Zone', look at the source of the Page Layout. It should the Id of the WebPartZone control. Another option is to use the .GetZoneID() method on the SPLimitedWebPartManager class. This will require having a page with a web part in the zone in question, but that should get you the ZoneID. Using the manager from the above example, it would look something like this:

string zoneId = manager.GetZoneID(manager.WebParts[0]);
2
  • Nice trick with GetZoneID (+1), however, it still doesn't add web part to the page for some reason
    – StupidOne
    Commented Dec 31, 2013 at 7:44
  • The SPListItem Property "PublishingPageContent" doesn't exist and setting a SPListItem property makes no sense since there's only one property and a page can contain multiple web parts. Commented Oct 18, 2017 at 17:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.