Custom wildcard URL route with page builder support

2024/11/01 10:31 AM

Hi there! I came across a need to create a custom dynamic route with a wildcard segment to render data from third-party system by ID, and ideally the layout of this page should be managed by the page builder, below are more detailed requirements:

  1. There needs to be a single page in the website channel representing these dynamic pages, so that content editors can configure page builder template, components, and configure personalization
  2. The URL of these dynamic pages will be something like /third-party-details/
  3. Custom controller will take this identifier, fetch the object from the external API, and populate the context object
  4. Some of the components will render data from this fetched context object, other components will be just normal content
  5. In my custom controller I need to initialize page builder from that particular single page in the tree (I can store this dynamic page ID somewhere in the config or even hardcode, doesn't matter much)

Points 1-4 are fairly straightforward and I know how to achieve this. But I've got issues with implementing number 5.

In previous versions of Kentico because we had a lot more control of the routing this was easily achievable:

  • In portal engine you could create a page with dynamic in the URL and just edit it's template
  • In version 12 you could call HttpContext.Kentico().PageBuilder().Initialize(myDynamicPage.DocumentID); to init it from your custom route controller
  • In version 13 you could still call IPageDataContextInitializer.Initialize(myDynamicPage);
  • But in XbyK most of the routing classes are internal and I can't seem to find an alternative ways of achieving this.

Remember that importing this third-party data into Kentico to create pages with page builder is not an option. The dataset is large and there's no chance content editors will go into every single page to manage the components. Instead, they need to be able to change layout and components for all these pages in one go.


Environment

  • Xperience by Kentico version: 29.6.0
  • .NET version: 8

Answers

2024/11/01 1:14 PM
Answer

Apparently, I figured this out.

Below is the POC controller I did inside Dancing Goat, which renders coffee samples landing page on a custom URL /dynamicdata/index:

using System.Threading.Tasks;
using DancingGoat.Models;
using Kentico.Content.Web.Mvc;
using Kentico.Content.Web.Mvc.Routing;
using Kentico.PageBuilder.Web.Mvc.PageTemplates;
using Microsoft.AspNetCore.Mvc;

namespace DancingGoat.Controllers;

public class DynamicDataController : Controller
{
    private readonly IWebPageDataContextInitializer pageDataContextInitializer;
    private readonly LandingPageRepository landingPageRepository;
    private readonly IPreferredLanguageRetriever currentLanguageRetriever;

    public DynamicDataController(IWebPageDataContextInitializer pageDataContextInitializer,
        LandingPageRepository landingPageRepository, IPreferredLanguageRetriever currentLanguageRetriever)
    {
        this.pageDataContextInitializer = pageDataContextInitializer;
        this.landingPageRepository = landingPageRepository;
        this.currentLanguageRetriever = currentLanguageRetriever;
    }

    public async Task<ActionResult> Index()
    {
        var webPageItemId = 14;
        var languageName = currentLanguageRetriever.Get();

        var landingPage = await landingPageRepository.GetLandingPage(webPageItemId, languageName, cancellationToken: HttpContext.RequestAborted);

        // This is the key bit - initialize page with page builder by ID and language
        pageDataContextInitializer.Initialize(new RoutedWebPage
        {
            WebPageItemID = landingPage.SystemFields.WebPageItemID,
            LanguageName = languageName
        });
        
        return new TemplateResult(landingPage);
    }
}
2024/11/01 2:19 PM

Partial widget pages was ported over by a user, I think the package just needs to be published. Then you can load the widget page into yours. I'll be working it shortly

To answer this question, you have to login first.