Try our conversational search powered by Generative AI!

Setting CMS content for custom URL

Vote:
 

Hi, 

I have a question related to custom URLs that I want to have a content. 

Basically, for pages in CMS, we extend PageController<TPage> where TPage : PageData

Then the said page comes to a controller in a method public async Task<ActionResult> Index(CustomPage currentContent) 

I'm wondering if we can have that CustomPage currentContent for URLs that don't match the CMS url? 

For example if page /Custom-Page1 is a content in CMS them the Index will have the currentContent set. But if I want /Custom-Page1-green and /Custom-Page2-blue then is no match and currentContent is null. Is there a way to load /Custom-Page1-green and /Custom-Page2-blue with the same currentContent as  /Custom-Page1?

I've tried to override IUrlResolverPipelineStep also IPageRouteHelper and IContentRouteHelper and yet something is not updating that currentContent. I tried IContentUrlResolver but I wasn't able to implement  it

Below are some of my attempts The code seems to work, but is executed after the Index method is called in both cases

public class UpdatedContentRouteHelper : IPageRouteHelper, IContentRouteHelper
{

    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IContentLoader _contentLoader;
    public PageData ComputedPage { get; set; }

    public UpdatedContentRouteHelper(IHttpContextAccessor httpContextAccessor, IContentLoader contentLoader)
    {
        this._httpContextAccessor = httpContextAccessor;
        _contentLoader = contentLoader;
    }

    public PageReference PageLink => this.ContentLink.ToPageReference();

    public PageData Page => this.Content as PageData;

    public string LanguageID => this._httpContextAccessor.HttpContext?.Features.Get<IContentRouteFeature>()?.RoutedContentData?.RouteLanguage;

    public ContentReference ContentLink => ModifyContent(this._httpContextAccessor.HttpContext?.Features.Get<IContentRouteFeature>()?.RoutedContentData)?.ContentLink;

    public IContent Content => ModifyContent( this._httpContextAccessor.HttpContext?.Features.Get<IContentRouteFeature>()?.RoutedContentData);

    private IContent ModifyContent(ContentRouteData originalContent)
    {
        if (originalContent?.Content == null)
        {
            TransformUrl transformUrl = new TransformUrl();
            var originalUrl = _httpContextAccessor.HttpContext.Request.GetDisplayUrl();
            var pageId = TransformUrl.GetPageId(originalUrl);
            if (pageId != 0)
            {
                ComputedPage = _contentLoader.Get<CustomPage>(new ContentReference(pageId));
                return ComputedPage;
            }
        }
        return originalContent?.Content;
    }
}
public class CustomPipelineStep: IUrlResolverPipelineStep
{
    private readonly IContentLoader _contentLoader;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CustomPipelineStep(IContentLoader contentLoader, IHttpContextAccessor httpContextAccessor)
    {
        _contentLoader = contentLoader;
        _httpContextAccessor = httpContextAccessor;
    }

    public RoutingState Resolve(UrlResolverContext context, UrlResolverOptions options)
    {
        var originalUrl = _httpContextAccessor.HttpContext.Request.GetDisplayUrl();
        if (TransformUrl.IsUpdatedUrl(originalUrl))
        {
            
            var pageId = TransformUrl.GetPageId(originalUrl);
            if (pageId != 0)
            {
                var page = _contentLoader.Get<CustomPage>(new ContentReference(pageId));
                context.Content = page;
                
                return RoutingState.Continue;
            }
        }
        return RoutingState.Continue;
    }

}

My solution was to get the currentContent in the Index action based on the request URL, but I feel like some functionality is missing (for example Edit Page admin link when logged as administrator doesn't work but I expect other issues too)

(Not sure if it matters, but we want to do this to avoid having query strings and move them in the URL path to avoid some issues with encoding/special characters/improve SEO)

#323413
Jun 11, 2024 13:02
Vote:
 

It'd help if you can provide more context on your use case for the different URLs for a page. Are the URLs /Custom-Page1-green and /Custom-Page2-blue simply aliases for /Custom-Page1? Do you need to pass any values from the URL path to the page controller?

#323456
Jun 12, 2024 6:05
Vote:
 

Hi Ronil,  I think they can be aliases, but it also must be somehow generic. The idea is that we had query strings and URLs like /Custom-Page1?color=green and now we want to get rid of query strings. 

I can access the full URL path in any request/ page controller so I'm not worried about passing those values. I also can get the currentContent in a custom route controller based on URL. But I was hoping I can insert that content somewhere else so that all default functionality works the same - edit page for logged users - or other functionality that uses the content. 

#323458
Jun 12, 2024 7:26
Vote:
 

Hello

it sounds like you need PartialRouter

https://docs.developers.optimizely.com/content-management-system/docs/partial-routing

#323459
Jun 12, 2024 10:14
Vote:
 

Hi Sergiu, you can use URL paths instead of query strings (E.g. /Custom-Page1/green, /Custom-Page2/blue), and extend the content routing to handle the remaining paths in the URL. 

One way is through a custom PartialRouter as suggested by Vincent above. This allows you to handle routing of the remaining path of an URL after matching the page type.

However, if you want to route to the same page type with parameters then you can simply register route parameters for a page controller in your Startup.cs 

E.g.

//Startup
app.UseEndpoints(endpoints => {
  endpoints.MapContent()
    .MapTemplate<CustomPageController>("{color}");
});

// Add matching action parameter in your Page controller:
// public Task<ActionResult>Index(CustomPage currentContent, string color)

It really depends on what you want to achieve with your custom routes

#323501
Edited, Jun 13, 2024 4:00
Vote:
 

Thank you Vincent and Ronil. 

I tried your suggestions

The PartialRoute didn't work for me some reason event though I followed the documentation.

The endpoints.MapContent().MapTemplate<CustomPageController>("{color}"); seems to work. I just have a following question. Can we have  the URL changed to /green/Custom-Page1 I'm thinking similar with language Maybe that pattern "{color}" can handle that, but I can't find the documentation. 

#323507
Jun 13, 2024 10:02
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.