Creating a Publishing Page in SharePoint using JavaScript

June 22, 2014

I was tasked with creating a Publishing Page in SharePoint using JavaScript (JSOM), and found it wasn’t an easy task. Looking through forums, blogs and other publications, I could not find a hint as to how to accomplish this task, and has to use bits and pieces (as well as my own knowledge) to build the solution.

The requirement is this: create a publishing page based on a specific page layout.

The solutions requires 2 major steps:

1. Get the required page layout
2. Create the page using the page layout

The code relies on an article in MSDN – SharePoint 2013: Create publishing pages in apps for SharePoint, and some bits of code adapted from CSOM in Waldek Mastykarz’s article Provisioning Publishing Pages and Web Parts using the App Model.

Using SharePoint’s JSOM is a bit complex and requires multiple round-trips of loading information, because each level requires loading the previous level. For example, if you would like to load a list item, you’ll have to load the current web and the list you require, then load the list item and get its properties. This routine get even more complex when you require a list item from another site or web (see the code for loadPageLayout );

Another thing to note is loading SODs – loading he required JavaScript files because they are loaded on demand. There are a couple of ways to accomplish this, and I tend to use SP.SOD.executeFunc because it supports the executing of anonymous functions, and it’s easy to write and maintain.

The code below was tested on a SharePoint 2013 farm and was debugged only to get it working. Error handling is minimal, so if you’re going to use it in a production environment, it will require some work.

Update: I updated the createPublishingPage function to include property values that will be set for the new page after creation. Let me know if you need the updated version.

function loadPageLayout (pageLayoutName, callback) {
        var pageFromDocLayout, pageLayoutItem;

        SP.SOD.executeFunc('SP.js', 'SP.ClientContext', function () {
            var context = SP.ClientContext.get_current();
            var site = context.get_site();

            context.executeQueryAsync(function () {
                var rootWeb = site.get_rootWeb();
                context.load(rootWeb, 'ServerRelativeUrl');

                context.executeQueryAsync(function () {
                    var rootUrl = rootWeb.get_serverRelativeUrl();
                    pageFromDocLayout = rootWeb.getFileByServerRelativeUrl(rootUrl + "_catalogs/masterpage/" + pageLayoutName);

                    context.executeQueryAsync(function () {
                        pageLayoutItem = pageFromDocLayout.get_listItemAllFields();

                        context.executeQueryAsync(function () {
                            if (typeof callback == "function") {
                                callback(pageLayoutItem);
                            }
                        });
                    });
                });
            });
        });
    };

    function createPublishingPage (filename, pageLayoutName, callback) {
        SP.SOD.executeFunc('SP.js', 'SP.ClientContext', function () {
            SP.SOD.executeFunc('SP.Publishing.js', 'SP.Publishing.PublishingWeb', function () {
                var web, pubWeb, pageInfo, newPage, listItem;
                var context = SP.ClientContext.get_current();

                web = context.get_web();
                context.load(web);
                context.executeQueryAsync(function () {
                    pubWeb = SP.Publishing.PublishingWeb.getPublishingWeb(context, web);
                    context.load(web);
                    context.load(pubWeb);
                    context.executeQueryAsync(function () {

                        // load page layout and create the new page
                        DataAccess.loadPageLayout(pageLayoutName, function (pageLayoutItem) {
                            pageInfo = new SP.Publishing.PublishingPageInformation();
                            pageInfo.set_pageLayoutListItem(pageLayoutItem);
                            pageInfo.set_name(filename);

                            newPage = pubWeb.addPublishingPage(pageInfo);
                            context.load(newPage);

                            context.executeQueryAsync(function () {
                                // Success callback after adding a new Publishing Page.
                                // We want to get the actual list item that is represented by the Publishing Page.
                                listItem = newPage.get_listItem();
                                context.load(listItem);
                                context.executeQueryAsync(

                                    // Success callback after getting the actual list item that is 
                                    // represented by the Publishing Page.
                                    // We can now get its FieldValues, one of which is its FileLeafRef value.
                                    // We can then use that value to build the Url to the new page
                                    // and set the href or our link to that Url.
                                    function () {
                                        if (typeof callback == "function") {
                                            callback(listItem);
                                        }
                                    },

                                    // Failure callback after getting the actual list item that is 
                                    // represented by the Publishing Page.
                                    function (sender, args) {
                                        alert('Failed to get new page: ' + args.get_message());
                                    }
                                    );
                            },
                                // Failure callback after trying to add a new Publishing Page.
                                function (sender, args) {
                                    alert('Failed to Add Page: ' + args.get_message());
                                }
                                );
                        });
                    },
                        // Failure callback after trying to get the host Web as a PublishingWeb.
                        function (sender, args) {
                            alert('Failed to get the PublishingWeb: ' + args.get_message());
                        });
                });
            });
        });
Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

7 comments

  1. LongJanuary 14, 2015 ב 13:14

    Thank you very much. This code work very well.
    But when I change var context = new SP.ClientContext.get_current() to var context = new SP.ClientContext(siteUrl);
    it has error 2T$ undefined. It so strange cause I use the same url with the site I call the get_current.

    Reply
    1. Adi LevinshteinFebruary 5, 2016 ב 10:12

      I’m glad you found this useful, but this is a very old post, and I don’t have the code anymore.

      Reply
  2. FlavJanuary 5, 2016 ב 12:18

    could it be more simple if you get directly the layout item using CamL on the gallery?
    I think somethink like that can do the work :


    function GetPageLayoutAsync(webTargetUrl, listTemplateType, pageLayoutName) {
    var d = $.Deferred();
    var webTargetContext = new SP.ClientContext(window.COB.appHelper.getRelativeUrlFromAbsolute(webTargetUrl))
    var siteTarget = webTargetContext.get_site();

    var liste = siteTarget.get_rootWeb().getCatalog(listTemplateType);

    var camlQuery = new SP.CamlQuery();
    camlQuery.set_viewXml("" + pageLayoutName + "1");

    var collListItem = liste.getItems(camlQuery);

    webTargetContext.load(collListItem);

    var o = { d: d, items: collListItem };

    webTargetContext.executeQueryAsync(Function.createDelegate(o, onGetPageLayoutSucceeded), Function.createDelegate(o, onGetPageLayoutFailed));

    return d.promise();

    function onGetPageLayoutSucceeded() {
    this.d.resolve(this.items);
    }

    function onGetPageLayoutFailed(sender, args) {
    this.d.reject(args.get_message());
    }
    }

    An use like this :

    var getLayouts = GetPageLayoutsAsync(url, listName, pageLayoutName);
    getLayouts.done(function (result) {
    //continue your code and can reuse result as LayoutItem with is own context
    }
    });

    getLayouts.fail(function (result) {
    alert("Error : " + result);
    });

    Reply
    1. FlavJanuary 5, 2016 ב 12:21

      sorry for the use, my bad.
      The code is :


      var getLayouts = GetPageLayoutsAsync(url, SP.ListTemplateType.masterPageCatalog, "searchresults.aspx");
      getLayouts.done(function (result) {
      //continue your code and can reuse result as LayoutItem with is own context
      }
      });
      getLayouts.fail(function (result) {
      alert("Error : " + result);
      });

      Reply
  3. RakeshFebruary 5, 2016 ב 07:32

    Thanks Adi for this post. Could you please share the updated ‘createPublishingPage’ function to set property values.

    Reply
  4. EuanMarch 8, 2016 ב 13:46

    I would also like the updated createPublishingPage if you have it? Thanks.

    Reply
    1. Adi LevinshteinMarch 8, 2016 ב 13:51

      I don’t have the code anymore.
      Try this blog post:
      http://deepakkumarsahoo88.blogspot.co.il/2015/01/creating-publishing-page.html

      Reply