Setting available and default page layouts in SharePoint Online

In a SharePoint 2013 on-premise solution, it’s pretty easy to use the server-side object model to set the available page layouts and default page layout. All you have to do is get a handle to the PublishingWeb object that wraps a publishing SPWeb, and then use the method or the property.

Unfortunately, this functionality isn’t supported in the client-side object model, which is what we’re restricted to if we are using SharePoint Online.  However, it turns out that it is still possible to set both of these properties.  The list of available page layouts and the default page layout properties are hidden in the AllProperties property bag of the Web object (confusingly, not the PublishingWeb object).

The “Available Page Layouts” property is stored in a property called __PageLayouts (with 2 underscores in front of the name).  The “Default Page Layouts” is stored in a property called __DefaultPageLayout (again, with 2 underscores in front of the name).

Both properties are stored in XML format.  The __PageLayouts property needs to be formatted like this:

<pagelayouts>
	<layout guid="8a0ccb96-58d2-4d15-b57c-27e8c78bd175" url="_catalogs/masterpage/Landing-12.aspx">
		<layout guid="4173f002-f4b2-4b19-a9a8-3653aa0f646c" url="_catalogs/masterpage/NewsPage.aspx"></layout>
	</layout>
</pagelayouts>

The __DefaultPageLayout property is formatted as a single layout, like this:

<layout guid="4173f002-f4b2-4b19-a9a8653aa0f646c" url="_catalogs/masterpage/News.aspx" />

In both cases, the “url” property is the url of the page layout file in the master page gallery.  The “guid” is the “UniqueId” of the list item associated with the file.

I had to do this for a project recently, so I wrote a small function to handle the work of looking up the file and the guid.  You call the function passing in the ClientContext object, the Web object you want to modify, plus an array of the page layout URLs, and a string representing the default page layout URL.

Here’s the PowerShell function – but you could easily adapt this into a C# or VB method too:

Function Set-AvailableAndDefaultPageLayouts
{
	param
	(
		[Microsoft.SharePoint.Client.ClientContext]$context,
		[Microsoft.SharePoint.Client.Web]$web,
		[array]$pageLayoutUrls,
		[string]$defaultPageLayoutUrl
	)
	process
	{
		Write-Host "Setting available page layouts and default page layout on " $web.Url -NoNewLine
		$allProps = $web.AllProperties
		$context.Load($web)
		$context.Load($allProps)
		$context.ExecuteQuery()
		$defaultPageLayoutGuid = ""
		$pageLayoutXml = "<pagelayouts>"
		$pageLayoutUrls | % {
			$fileUrl = $_
			$file = $context.Site.RootWeb.GetFileByServerRelativeUrl($fileUrl)
			$context.Load($file)
			$context.ExecuteQuery()
			$listItemFields = $file.ListItemAllFields
			$context.Load($listItemFields)
			$context.ExecuteQuery()
			$guid = $listItemFields.FieldValues["UniqueId"]
			
			# if this is going to be the default page, save the guid so we avoid another call to get the File object a second time
			if ($_ -eq $defaultPageLayoutUrl)
			{
				$defaultPageLayoutGuid = $guid
			}
			
			$pageLayoutXml = $pageLayoutXml + "<layout>"
		}
		$pageLayoutXml += "</layout></pagelayouts>"
		$allProps["__PageLayouts"] = $pageLayoutXml
		$defaultPageLayoutXml = "<layout>"
		$allProps["__DefaultPageLayout"] = $defaultPageLayoutXml
		$web.Update()
		$context.ExecuteQuery()
		Write-Host " done" -ForegroundColor Green
	}
}

By the way, if you want to set either property to inherit from the parent web, then it’s even easier. Just set the value of the appropriate property to “__inherit” (with 2 underscores before the word).

Stories say it best.

Are you ready to make your workplace awesome? We're keen to hear what you have in mind.

Interested in learning more about the work we do?

Explore our culture and transformation services.