Kentico / xperience-by-kentico-kentico-migration-tool

A customizable tool that migrates older Kentico solutions to the latest version of Xperience by Kentico.
MIT License
7 stars 4 forks source link

Support migration of page type URL patterns #245

Closed liamgold closed 1 month ago

liamgold commented 2 months ago

Motivation

In Kentico Xperience 13, you could create page types that had their own URL pattern rather than using content tree-based routing. This meant that URLs could be based off patterns instead of the content tree.

Although the KX13 documentation recommends content tree routing, some websites will have been built using custom routing with URL patterns. Especially if they have previously migrated from Kentico 12 MVC as content tree-based routing was not available at the time.

These existing clients should be able to use the migration toolkit, they should not be left out.

Proposed solution

As Xperience by Kentico does not support page type URL patterns, it obviously can't be mapped 1:1. I think a suitable solution would be to resolve the URL of the existing page, store it as a vanity URL when that is released, and set that URL as the canonical. This way, migrated pages will keep the existing URL and not break when switching to Xperience by Kentico.

The expectation then would be that new pages using these page types would start to use the content tree-based routing.

If the team managing the website wanted to continue using page type URL patterns, it would be their responsibility to implement a bespoke solution to handle this going forward.

liparova commented 1 month ago

Thank you for your recommendation. We'll evaluate its feasibility and provide regular updates on its integration progress.

Sapphirress commented 1 month ago

Hi Liam, technically this could be added into the migration tool, however we think that this is not a best practice for utilizing Vanity URLs and therefore we decided not to go on with the implementation. Instead, we will recommend to achieve this scenario through customization and offer an example for this purpose.

liamgold commented 1 month ago

That's fine with me - as long as there is a recommended approach to follow that supports these clients then I am happy.

If we're no longer using Vanity URLs for this, do you know how long it will take for the recommended approach to be published?

tkrch commented 1 month ago

Hi @liamgold, one option is to use dynamic route transformer. Simplistic sample for Dancing Goat project:

1) create class MyDynamicRouteTransformer as follows:

namespace DancingGoat;

using System;
using System.Linq;
using System.Threading.Tasks;
using CMS.ContentEngine.Internal;
using CMS.Core;
using CMS.DataEngine;
using CMS.Websites.Internal;
using CMS.Websites.Routing;
using Kentico.Content.Web.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;

public class MyDynamicRouteTransformer : DynamicRouteValueTransformer
{
    private readonly IWebPageDataContextInitializer _contextInitializer;
    private readonly IWebsiteChannelContext _websiteChannelContext;

    public MyDynamicRouteTransformer(IWebPageDataContextInitializer contextInitializer, IWebsiteChannelContext websiteChannelContext)
    {
        _contextInitializer = contextInitializer;
        _websiteChannelContext = websiteChannelContext;
    }

    public override async ValueTask<RouteValueDictionary> TransformAsync(HttpContext
        httpContext, RouteValueDictionary values)
    {
        return await Task.Run(async () =>
        {
            // TODO: retrieve web page You want to display
            var webPageItem = WebPageItemInfo.Provider.Get().WhereEquals(nameof(WebPageItemInfo.WebPageItemTreePath), "/Home").FirstOrDefault() 
                ?? throw new InvalidOperationException("Page not found!");

            // TODO: get language from route
            var contentLanguage = await Service.Resolve<IContentLanguageRetriever>().GetDefaultContentLanguage();
            // TODO: get contenttype of desired content item
            var contentItemInfo = ContentItemInfo.Provider.Get(webPageItem.WebPageItemContentItemID);
            var webPage = new RoutedWebPage
            {
                WebPageItemID = webPageItem.WebPageItemID,
                WebPageItemGUID = webPageItem.WebPageItemGUID,
                LanguageID = contentLanguage.ContentLanguageID,
                LanguageName = contentLanguage.ContentLanguageName,
                ContentTypeID = contentItemInfo.ContentItemContentTypeID,
                ContentTypeName = DataClassInfoProvider.GetClassName(contentItemInfo.ContentItemContentTypeID),
                WebsiteChannelID = _websiteChannelContext.WebsiteChannelID,
                WebsiteChannelName = _websiteChannelContext.WebsiteChannelName,    
            };

            // Initialize WebPageDataContext in order to get WebPageRetriever work
            _contextInitializer.Initialize(webPage);

            // TODO: select controller
            values["controller"] = "DancingGoatHome";
            // TODO: select controller action
            values["action"] = "Index";
            return values;
        });
    }
}

2) Register it in ServiceCollection: builder.Services.AddTransient<MyDynamicRouteTransformer>();

3) map transformer: `app.MapDynamicControllerRoute("/dynamic-route-test/{foo?}/{bar?}");``

4) open ./Controllers/DancingGoatHomeController.cs

change

public async Task<IActionResult> Index()

to

public async Task<IActionResult> Index([FromRoute] string foo, [FromRoute] string bar)

then put breakpoint into Index method

5) run project and open url: http://[domain]/dynamic-route-test/testvalue1/testvalue2

6) values populated: image continue and page should render correctly

let me know, if this helped

liamgold commented 1 month ago

Thanks @tkrch - this would only correct it from a routing perspective, right?

How do you suggest correcting the URL being displayed on the page in the web channel?

When resolving the page's URL through Kentico's APIs will the content-tree based URL still be used?

When a URL has been previously added to rich text blocks, and in the future, which URL will be used?

tkrch commented 1 month ago

@liamgold I'm currently testing alternative solution. I'll notify You when i confirm that it is feasible and implemented.

tkrch commented 1 month ago

@liamgold preview of feature is in PR #249 - there may be some additional changes to catch edge-cases (if some occur), but this is general idea of solving challenges of KX13 page type url patterns.

Note that https://github.com/Kentico/xperience-by-kentico-kentico-migration-tool/blob/master/Migration.Toolkit.CLI/README.md#source-instance-api-discovery is required.

tkrch commented 1 month ago

Thanks @tkrch - this would only correct it from a routing perspective, right?

How do you suggest correcting the URL being displayed on the page in the web channel?

When resolving the page's URL through Kentico's APIs will the content-tree based URL still be used?

When a URL has been previously added to rich text blocks, and in the future, which URL will be used?

this approach is usable when you want to handle old URLs and migrate to content tree based routing

i may have previously misunderstood

The expectation then would be that new pages using these page types would start to use the content tree-based routing.

I see 3 options: