Setting Default Page Layout, Available Page Layouts, and Available Web Templates via CSOM (JSOM)




The publishing infrastructure provides a site with many features including page layouts. A default page layout, a restricted set of available page layouts, and a restricted set of web templates can be set. The page in the UI looks like this:

config_pageLayouts

In order to perform these configurations programmatically, methods are provided as part of the the server side object model via the PublishingWeb object. However setting these properties via CSOM is less obvious. The equivalent methods are not available (at least not at the time of writing. It is worth noting that the CSOM model gets extended as part of CUs as well as in SPO).
The property information is stored solely as web properties. I have verified this by reflecting the Microsoft.SharePoint.Publishing assembly, and ensured that the server side object model methods perform no other action than this.

The following JSOM code demonstrates how to set the web properties with valid XML values.

The methods can be called like this:

// The page layout is defined by its filename
var filename = "NewsArticlePage.aspx";
setDefaultPageLayout(filename, onSuccess, onFailure);


// The page layouts are defined by an array of filenames
var filenames = ["NewsArticlePage.aspx"];
setAvailablePageLayouts(filenames, onSuccess, onFailure);

// The web templates are defined by their long name,
//the guid is that of the feature which deploys the web template
var webTemplates = ["{BDACFFF5-05DF-4446-9907-B4C39F15F1D7}#WT_VanitySite"];
setAvailableWebTemplates(webTemplates, onSuccess, onFailure);

 Note – these samples reference both the jQuery and underscore libraries.

    /*
    Web Property:
    __PageLayouts
    
    Web Property Value:
    <pagelayouts>
        <layout guid="e87b7c1d-4a23-4ca1-8fb8-36314cabb7c4" url="_catalogs/masterpage/NewsArticlePage.aspx" />
    </pagelayouts>
    */
    var setAvailablePageLayouts = function (availablePageLayoutFilenames, onSuccess, onFailure) {
        var ctx = SP.ClientContext.get_current();
        var web = ctx.get_web();

        if (jQuery.isArray(availablePageLayoutFilenames) && availablePageLayoutFilenames.length > 0) {
            var gallery = ctx.get_site().get_rootWeb().get_lists().getByTitle("Master Page Gallery");
            getFilesByName(gallery, availablePageLayoutFilenames, availablePageLayoutFilenames.length, function (listItems) {
                var lis = CC.CORE.Utilities.CastSPCollectionToArray(listItems);
                if (lis.length < 1) {
                    onFailure("Found " + lis.length + " page layouts with filenames: " + availablePageLayoutFilenames.join(", "));
                }
                else {
                    var xmlEl = jQuery("<pagelayouts></pagelayouts>");
                    _.each(lis, function (li) {
                        xmlEl.append(getLayoutXml(li));
                    });
                    updatePropertyBag(web, "__PageLayouts", xmlEl[0].outerHTML, onSuccess, onFailure);
                }
            },
            onFailure);
        }
        else {
            updatePropertyBag(web, "__PageLayouts", "__Inherit", onSuccess, onFailure);
        }
    };

    /*
    Web Property:
    __DefaultPageLayout
    
    Web Property Value:
    <layout guid="e87b7c1d-4a23-4ca1-8fb8-36314cabb7c4" url="_catalogs/masterpage/NewsArticlePage.aspx" />
    */
    var setDefaultPageLayout = function (defaultPageLayoutFilename, onSuccess, onFailure) {
        var ctx = SP.ClientContext.get_current();
        var web = ctx.get_web();

        if (typeof defaultPageLayoutFilename === "string" && defaultPageLayoutFilename.length > 0) {
            var gallery = ctx.get_site().get_rootWeb().get_lists().getByTitle("Master Page Gallery");
            getFilesByName(gallery, [defaultPageLayoutFilename], 1, function (listItems) {
                var lis = CC.CORE.Utilities.CastSPCollectionToArray(listItems);
                if (lis.length !== 1) {
                    onFailure("Found " + lis.length+ " page layouts with filename: " + defaultPageLayoutFilename);
                }
                else {
                    var li = lis[0];
                    var xml = getLayoutXml(li);
                    updatePropertyBag(web, "__DefaultPageLayout", xml, onSuccess, onFailure);
                }
            },
            onFailure);
        }
        else {
            updatePropertyBag(web, "__DefaultPageLayout", "__Inherit", onSuccess, onFailure);
        }
    };

    /*
    Web Property:
    __WebTemplates
    
    Web Property Value:
    <webtemplates>
        <lcid id="1033">
            <webtemplate name="{BDACFFF5-05DF-4446-9907-B4C39F15F1D7}#WT_NewsHubSite" />
        </lcid>
        <lcid id="all">
            <webtemplate name="{BDACFFF5-05DF-4446-9907-B4C39F15F1D7}#WT_NewsHubSite" />
        </lcid>
    </webtemplates>
    */
    var setAvailableWebTemplates = function (availableWebTemplates, onSuccess, onFailure) {
        var ctx = SP.ClientContext.get_current();
        var web = ctx.get_web();
        var xml = "";
        var inheritWebTemplates = "False";

        if (jQuery.isArray(availableWebTemplates) && availableWebTemplates.length > 0) {
            var xmlEl = jQuery("<webtemplates><lcid id='all'></lcid></webtemplates>");
            var lcidAll = xmlEl.find("lcid");
            _.each(availableWebTemplates, function (availableWebTemplate) {
                var wtEl = jQuery("<webtemplate />").attr("name", availableWebTemplate);
                lcidAll.append(wtEl);
            });
            xml = xmlEl[0].outerHTML;
        }
        else {
            xml = "";
            inheritWebTemplates = "True";
        }

        updatePropertyBag(web, "__WebTemplates", xml, function () {
            updatePropertyBag(web, "__InheritWebTemplates", inheritWebTemplates, onSuccess, onFailure);
        }, onFailure);
    };

   /*
   Utility methods to support the above
   */
    var getLayoutXml = function (li) {
        var xml = "<layout guid='" + li.get_item("UniqueId") + "' url='" + li.get_item("FileRef") + "' />";
        return xml;
    };

    var getFilesByName = function (list, filenames, rowLimit, onSuccess, onFailure) {
        var camlQuery = new SP.CamlQuery();
        var camlQueryXml = getViewXml("FileLeafRef", "Text", filenames, rowLimit);
        camlQuery.set_viewXml(camlQueryXml);
        var collListItem = list.getItems(camlQuery);
        ctx.load(collListItem, "Include(UniqueId, FileRef)");
        ctx.executeQueryAsync(function () {
            onSuccess(collListItem);
        },
        onFailure);
    };

    var getViewXml = function (fieldName, fieldType, fieldValues, rowLimit) {
        var caml = "<View><Query><Where><In><FieldRef Name='" + fieldName + "' /><Values>";
        _.each(fieldValues, function (fieldValue) {
            caml += "<Value Type='Text'>" + fieldValue + "</Value>";
        });
        caml += "</Values></In></Where></Query><RowLimit>" + rowLimit + "</RowLimit></View>";
        return caml;
    };
    
    var updatePropertyBag = function (propertyBagWeb, key, value, successCallback, failedCallback) {
        var ctx = SP.ClientContext.get_current();
        var properties = propertyBagWeb.get_allProperties();
        properties.set_item(key, value);
        propertyBagWeb.update();

        ctx.load(propertyBagWeb);
        ctx.load(properties);

        ctx.executeQueryAsync(successCallback, failedCallback);
    }





4 thoughts on “Setting Default Page Layout, Available Page Layouts, and Available Web Templates via CSOM (JSOM)”

  1. Woah! I’m really diggng the template/theme of this blog. It’s simple, yet effective.

    A lot of times it’s difficult to get that “perfect balance” between superb
    usability and appearance. I must say you have done a awesome
    job with this. In addition, the blog loads extremely fast for me on Safari.
    Exceptional Blog!

    1. Thanks! Your PowerShell rendition of this is good stuff.
      (For anyone wanting to achieve what is described here in PowerShell see the Pingback in the comments below)

Leave a Reply

Your email address will not be published.