Using Page Builder With Custom Routing in Xperience by Kentico

When our team encountered challenges integrating Xperience’s Page Builder with custom routing for status code pages, one of our developers resolved the issue by manually retrieving page data and initializing the context. Read on to learn how he overcame this hurdle and enabled seamless custom routing.

Recently, I was working on a project that I needed to implement status code pages that had page builder enabled on them. Since these were status code pages, I needed custom routing and could not use Content Tree routing provided by Xperience by Kentico. Once I enabled page builder for this content type and added editable areas to the view, I quickly realized I was missing something.

When I ran the project and hit my newly created status code pages, I received the following error:

				
					Missing web page context data. If required use IWebPageDataContextInitializer.Initialize method to initialize the context manually. For POST actions use HtmlHelper extension method Html.Kentico().PageData() to persist the page context.
				
			

The Problem

When using custom routing, Xperience does not have context into which content tree page is connected to the custom route URL. Therefore, it cannot provide the page builder widgets associated with the page you are trying to reach.

To provide a little insight into the data behind the scenes: each web page item has a widget field where the page builder configuration is stored in. This can be found in the CMS_ContentItemCommonData database table, in the ContentItemCommonDataPageBuilderWidgets and ContentItemCommonDataPageTemplateConfiguration columns.

If Xperience doesn’t know which web page is associated with the request, then it cannot render the corresponding widgets.

The Solution

With the information from above in mind, we can infer that we need two things. We need to retrieve the web page item associated with the request, and the page context, or in other words, the data associated with that page (page builder widgets).

We will use the ContentItemQueryBuilder and GetWebPageResult to retrieve the web page item. In order to grab the correct web page item, we need to limit the results by the WebPageItemId. We can do this by getting the page context using the IWebPageDataContextRetriever. The code below shows how we can build the query to retrieve the page.

				
					var pageContext = webPageDataContextRetriever.Retrieve().WebPage;
var query = new ContentItemQueryBuilder().ForContentType(
    StatusCodePage.CONTENT_TYPE_NAME,
    config =>
        config
        .ForWebsite(XperienceConstants.WebsiteChannelName)
        .Where(query =>
            query.WhereEquals(nameof(StatusCodePage.SystemFields.WebPageItemID), pageContext.WebPageItemID)
        )
        .TopN(topN: 1)
);
				
			

We are limiting the result to only the web page item whose WebPageItemID matches the page context WebPageItemID.

The final step in retrieving the web page item is the execution of the query using GetWebPageResult. If you want to read more about Xperience’s Content item API and retrieving pages, you can reference their documentation here.

				
					var page = (
    await executor.GetWebPageResult(
        builder: query,
        options: queryOptions,
        resultSelector: queryMapper.Map<StatusCodePage>
    )
).FirstOrDefault();
				
			

Finally, we need to pass the context of the web page item to Xperience. This can be accomplished by using the IWebPageDataContextInitializer interface, which provides an Initialize method that takes a RoutedWebPage item as an argument. We can construct the RoutedWebPage object from the page data that we retrieved.

				
					var languageQuery = ContentLanguageInfo.Provider.Get()
    .WhereEquals(columnName: "ContentLanguageID", page.SystemFields.ContentItemCommonDataContentLanguageID);
var language = languageQuery.ToList().FirstOrDefault();
var pageDataContext = new RoutedWebPage()
{
    WebPageItemID = page.SystemFields.WebPageItemID,
    WebPageItemGUID = page.SystemFields.WebPageItemGUID,
    LanguageID = page.SystemFields.ContentItemCommonDataContentLanguageID,
    LanguageName = language.ContentLanguageName,
    ContentTypeID = page.SystemFields.ContentItemContentTypeID,
    ContentTypeName = StatusCodePage.CONTENT_TYPE_NAME,
    WebsiteChannelName = XperienceConstants.WebsiteChannelName
};

webPageDataContextInitializer.Initialize(pageDataContext);
				
			

Final Thoughts

To wrap it up, integrating page builder with custom routing in Xperience may require some extra steps, but the process is straightforward once you understand the underlying mechanics. By manually retrieving the page data and initializing the context, you can get your custom-routed pages working seamlessly with the page builder. This approach not only resolves the context issue but also keeps your custom-routed pages flexible and fully integrated with Xperience’s powerful content management features.

About the Author

Tyler Stirtz

Tyler began his career in healthcare but quickly realized he was missing out on the creativity and logical aspect that computer programming provides. Shortly after that realization, Tyler decided to pursue his long-running interest in coding as a career, and he loves every second of it! Outside of BizStream, you can find Tyler backpacking, coding up a new project at home, playing video games, or exploring new breweries with friends. 

Migrate to Xperience by Kentico

We can help make your migration easy.

Visit Our Booth!

We’ll be at Event Title in City, ST on Month D-D

Subscribe to Our Blog

Stay up to date on what BizStream is doing and keep in the loop on the latest in marketing & technology.