Provisioning Engine (Client-Side Pages) — Vertical section controls exported with wrong Column index
Describe the bug
When exporting a SharePoint page that contains a vertical section layout (e.g. TwoColumnRightVerticalSection) to a PnP provisioning template, controls in the vertical section column are assigned an incorrect Column index. This causes the controls to be placed in the wrong column when the template is later applied to a new site.
The root cause is in ClientSidePageContentsHelper.cs where the column index for vertical section controls is computed using:
Column = column.IsVerticalSectionColumn ? section.Columns.IndexOf(column) + 1 : column.Order
The Columns list order is determined by HTML parsing order, which is not guaranteed. The vertical section column (layoutIndex=2) can appear at any position in the Columns list — for example at index 0 — resulting in Column = 1.
During import (in ObjectClientSidePages.cs), the CanvasSection constructor creates columns in a fixed order for each template type. For TwoColumnRightVerticalSection, the columns are always created as:
- Narrow column (columnFactor=4)
- Wide column (columnFactor=8)
- Vertical section column (columnFactor=12)
So Column = 1 maps to the narrow column, not the vertical section. The vertical section controls end up in the wrong column, producing an incorrect page layout.
Steps to reproduce
- Create a SharePoint Online team site using the standard Employee onboarding team template — the home page (
Employee-onboarding-team-home.aspx) uses a TwoColumnRightVerticalSection layout with controls in the vertical section column
- Alternatively, create any modern page with a
TwoColumnRightVerticalSection layout and add web parts to the vertical section column (e.g. News, Events, People web parts)
- Export the page to a PnP provisioning template using PnP Framework
- Inspect the exported template XML — vertical section controls may have
Column="1" instead of Column="3" (the vertical column index)
- Apply the template to a new site
- The vertical section controls appear in the narrow left column instead of the vertical section column
Expected behavior
Controls in the vertical section column should always be exported with a Column value that maps to the vertical section column during import. Since the import creates the vertical section column as the last column, the export should use an index matching that position.
Environment details
- PnP Framework version: 1.18.x / current dev branch
- OS: Windows 11
- Framework: .NET 8.0
- Tooling: Visual Studio 2022
Additional context
File: src/lib/PnP.Framework/Provisioning/ObjectHandlers/Utilities/ClientSidePageContentsHelper.cs
Original code:
Column = column.IsVerticalSectionColumn ? section.Columns.IndexOf(column) + 1 : column.Order
Fix — use section.Columns.Count for vertical section columns:
Column = column.IsVerticalSectionColumn ? section.Columns.Count : column.Order
This works because:
- During import, the
CanvasSection constructor always creates the vertical section column last (at index Columns.Count - 1)
- Import looks up columns via
page.Sections[sectionCount].Columns[control.Column - 1], so Column = Columns.Count correctly maps to the last column (the vertical section)
Columns.Count is stable regardless of HTML parsing order during export
Related PnP Core issue: Section type detection also fails for vertical sections due to the same HTML ordering problem — see the corresponding issue in pnp/pnpcore.
Thanks for your contribution! Sharing is caring.
Provisioning Engine (Client-Side Pages) — Vertical section controls exported with wrong Column index
Describe the bug
When exporting a SharePoint page that contains a vertical section layout (e.g.
TwoColumnRightVerticalSection) to a PnP provisioning template, controls in the vertical section column are assigned an incorrectColumnindex. This causes the controls to be placed in the wrong column when the template is later applied to a new site.The root cause is in
ClientSidePageContentsHelper.cswhere the column index for vertical section controls is computed using:The
Columnslist order is determined by HTML parsing order, which is not guaranteed. The vertical section column (layoutIndex=2) can appear at any position in theColumnslist — for example at index 0 — resulting inColumn = 1.During import (in
ObjectClientSidePages.cs), theCanvasSectionconstructor creates columns in a fixed order for each template type. ForTwoColumnRightVerticalSection, the columns are always created as:So
Column = 1maps to the narrow column, not the vertical section. The vertical section controls end up in the wrong column, producing an incorrect page layout.Steps to reproduce
Employee-onboarding-team-home.aspx) uses aTwoColumnRightVerticalSectionlayout with controls in the vertical section columnTwoColumnRightVerticalSectionlayout and add web parts to the vertical section column (e.g. News, Events, People web parts)Column="1"instead ofColumn="3"(the vertical column index)Expected behavior
Controls in the vertical section column should always be exported with a
Columnvalue that maps to the vertical section column during import. Since the import creates the vertical section column as the last column, the export should use an index matching that position.Environment details
Additional context
File:
src/lib/PnP.Framework/Provisioning/ObjectHandlers/Utilities/ClientSidePageContentsHelper.csOriginal code:
Fix — use
section.Columns.Countfor vertical section columns:This works because:
CanvasSectionconstructor always creates the vertical section column last (at indexColumns.Count - 1)page.Sections[sectionCount].Columns[control.Column - 1], soColumn = Columns.Countcorrectly maps to the last column (the vertical section)Columns.Countis stable regardless of HTML parsing order during exportRelated PnP Core issue: Section type detection also fails for vertical sections due to the same HTML ordering problem — see the corresponding issue in pnp/pnpcore.
Thanks for your contribution! Sharing is caring.