Setting the new page header in a modern SharePoint page using C# or PowerShell

This week a question came up about how to set the Header in a modern page using code. Normally in these cases you could go to the PnP Provisioning library. Using the PnP Schema you can provision a page and specify some properties of the header that shows up when deployed. You can specify:

  • Title
  • ServerRelativeImageUrl
  • Translate X
  • Translate Y

Unfortunately, there has been some updates to the modern pages which allows for a new layout for headers and the current PnP library doesn’t have support for them yet. Notice the image below, we have a few new layouts and a new field called “Topic Header”.

So what I am going to do, is explain how we can achieve the new layout with the Topic Header field. I looked into the existing PnP codebase to see how the current header implementation was done, and it gave me a lot of insight into how to solve this problem.

How to achieve this

In order to create a new page and specify a new page header we actually have to create a new page in the Site Pages list and then update some of the hidden properties of the site page. Specifically we need to update the following fields:

  • LayoutWebpartsContent
  • PageLayoutType
  • CanvasContent1
  • _TopicHeader
  • ClientSideApplicationId

Where do the properties for a header live?

The thing about modern web parts is that a lot of them store the properties that are being rendered within the web part itself. Because of this, I actually have to set the HTML and JSON object of the web part on the site page’s LayoutsWebpartsContent field. It’s quite complex, so in order to be as safe as possible and get the correct HTML, I decided the best approach  would be to create a template page (pictured above) and use that as a way to get the proper data for my newly provisioned pages.

C# Implementation

This C# example is actually going to use the PnP Core library (not required). We’ll get a reference to my template page and grab the LayoutWebpartsContent property. This will return all of the HTML required for the header. Then, we’ll create a new article page, update a few required properties and then update the LayoutWebpartsContent property from the template values.

Link to gist

  using (var ctx = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(newSiteUrl, clientId, clientSecret))
            {
                var pages = ctx.Web.Lists.GetByTitle("Site Pages");
                ctx.Load(pages);
                
                //get template page
                var templatePage = pages.RootFolder.GetFile("Project-Home.aspx").ListItemAllFields;
                ctx.Load(templatePage);
                ctx.ExecuteQuery();
                
                //this is our template page content
                var _customPageHeader = templatePage[ClientSidePage.PageLayoutContentField]; //LayoutWebpartsContent
                var _canvasContent = templatePage["CanvasContent1"];

                //create new page in site page library
                var item = pages.RootFolder.Files.AddTemplateFile("/sites/test/sitepages/BeauTest.aspx", TemplateFileType.ClientSidePage).ListItemAllFields;
              
               //update page header from template information
                item[ClientSidePage.PageLayoutContentField] = _customPageHeader;        
                item[ClientSidePage.ClientSideApplicationId] = ClientSidePage.SitePagesFeatureId; //ClientSideApplicationId - b6917cb1-93a0-4b97-a84d-7cf49975d4ec
                item["CanvasContent1"] = _canvasContent; //"

“; item[“_TopicHeader”] = “Service Line”; item.Update(); ctx.Load(item); ctx.ExecuteQuery(); }

 

PowerShell Implementation

The following example is the equivalent of the C# code using CSOM, and instead of using a template file, I’ve hard coded the HTML into the code itself. This way, if you wanted to add some tokens in your HTML to dynamically replace the “Topic Header”, or change the layout you could do so directly in that HTML string.

Link to Gist

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
 

$admin = 'youraccount@tenant.OnMicrosoft.Com'
$password = Read-Host 'Enter Password' -AsSecureString

$context = New-Object Microsoft.SharePoint.Client.ClientContext("https://tenant.sharepoint.com/sites/testpnp");
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($admin , $password)
$context.Credentials = $credentials


$pagesLibrary = $context.Web.Lists.GetByTitle('Site Pages');
$context.Load($pagesLibrary);

$newPageitem = $pagesLibrary.RootFolder.Files.AddTemplateFile("/sites/testpnp/sitepages/TestPage.aspx", "ClientSidePage").ListItemAllFields;

$newPageitem["Title"] = "Project Home";
$newPageitem["ClientSideApplicationId"] = "b6917cb1-93a0-4b97-a84d-7cf49975d4ec";
$newPageitem["PageLayoutType"] = "Article";
$newPageitem["LayoutWebpartsContent"] = '
'; $newPageitem["CanvasContent1"] = "
"; $newPageitem["_TopicHeader"] = "Service Line"; $newPageitem.Update(); $context.Load($newPageitem); $context.ExecuteQuery();

 

A special thanks

I’d like to thank Garry Trinder for mentioning the current limitation and providing me with the idea on figuring out how to solve this issue and subsequently creating this post!

Thanks to the PnP Team for setting up a lot of the framework and for making this post possible. Sharing is caring.

5 thoughts on “Setting the new page header in a modern SharePoint page using C# or PowerShell

  1. Ami April 9, 2019 / 6:34 am

    Great article thank you! Only issue I run into is that setting the _TopicHeader doesn’t seem to work. Everything seems to work: setting the value, executing the query etc. but when I load the item again the _TopicHeader remains empty. Setting the other page header values, setting the canvas content with the webparts, everything works fine except for the topic header.

    Like

    • Beau Cameron April 9, 2019 / 8:19 am

      Hi Ami, the definition of the topic header is also contained in the HTML. Are you using a layout for the header that includes a topic header?

      Like

      • Aram Gulzadian April 9, 2019 / 9:19 am

        Hi Beau, thanks for your reply. Yep, as far as I know all page header layouts allow for a topic header. I’m able to set the topic header, and set showTopicHeader to true in the LayoutWebpartsContent if that’s what you mean. The values I set in the LayoutWebpartsContent remain after executing the query and reloading the item, only the _TopicHeader field gets reset to empty. I’m able to provision fully customised webparts on the page and can fully customise the page header (layout, header author etc.), everything works except for that darn topic header somehow hehe

        Like

      • Beau Cameron April 9, 2019 / 11:14 am

        That is strange. Are you using C# or the PowerShell example? I took the Gist linked for the PowerShell example, and it worked successfully for me. Maybe there is something wrong with the HTML and properties for the LayoutWebPartsContent?

        Like

      • Ami April 10, 2019 / 1:47 am

        I was using the c# example. I figured it out: it seems you can’t change the _TopicHeader field after setting a initial value during the creation of the page. For our business case we first need to create the page itself and later update its values for the CanvasContent1 and _TopicHeader etc.

        I’ve only encountered this problem so far for _TopicHeader. The canvas content and other elements of the page header can be changed after initial creation without problems. Funny thing is, I can confirm the topicHeader value in the html for the page header is updated (by inspecting the html with SpInsider), but the page renders the unchanged _TopicHeader nonetheless.

        Thanks for your help!

        Like

Leave a comment