Custom routes with language variants
# help-with-umbraco
s
Hi all, I am trying to create some virtual product categories / pages that needs to live beneath a Products node. My planned structure should end up being:
Copy code
Frontpage
 ├── About us
 ├── Random Page
 ├── Products
 │   ├── Category #1 (Virtual)
 │   │   ├── Product #1.1 (Virtual)
 │   │   ├── Product #1.2 (Virtual)
 │   ├── Category #2 (Virtual)
 │   │   ├── Product #2.1 (Virtual)
 │   │   ├── Product #2.2 (Virtual)
 │   │   ├── Product #2.3 (Virtual)
After reading various posts in the forum, it seems that it can be done with either a Custom routes within the Umbraco pipeline (https://docs.umbraco.com/umbraco-cms/v/13.latest-lts/reference/routing/custom-routes#custom-routes-within-the-umbraco-pipeline) or a Content Finder (https://docs.umbraco.com/umbraco-cms/v/13.latest-lts/reference/routing/request-pipeline/icontentfinder). I currently have it working with a custom controller that implements the
IVirtualPageController
interface so I am able to request:
/en-us/products/category-1-virtual
/en-us/products/category-1-virtual/product-1-1
Since my site uses language variants, I need the routes to be dynamic so I can generate the routes for each language, so I have like:
/en-us/products/category-1-virtual
/en-us/products/category-1-virtual/product-1-1
/da-dk/produkter/category-1-virtual
/da-dk/produkter/category-1-virtual/product-1-1
Also, the routes must only live beneath existing nodes in Umbraco that is of the type
productsOverview
. In the example above, it would be the Products node Any suggestions as to how this might be achieved would be most welcome.
k
We do it through the UmbracoPipelineFilter like this
Copy code
csharp
public void Compose(IUmbracoBuilder builder)
{
        builder.Services.Configure<UmbracoPipelineOptions>(options =>
        {
            options.AddFilter(new UmbracoPipelineFilter(nameof(EventPageController))
            {
                Endpoints = app => app.UseEndpoints(e =>
                {
                    // danish
                    e.MapControllerRoute("EventPageController", "/dk/arrangementer/{eventName}/{id}", new { Controller = "EventPage", Action = "Index" });
                    e.MapControllerRoute("EventPageController", "/dk/arrangementer/{eventName}/{id}/tilmeld", new { Controller = "EventRegistrationPage", Action = "Index" });
                    e.MapControllerRoute("EventPageController", "/dk/arrangementer/{eventName}/{id}/tak", new { Controller = "EventConfirmationPage", Action = "Index" });
                    e.MapControllerRoute("EventPageController", "/dk/arrangementer/{eventName}/{id}/rediger", new { Controller = "EventUpdatePage", Action = "Index" });

                    // english
                    e.MapControllerRoute("EventPageController", "/en/events/{eventName}/{id}", new { Controller = "EventPage", Action = "Index" });
                    e.MapControllerRoute("EventPageController", "/en/evens/{eventName}/{id}/signup", new { Controller = "EventRegistrationPage", Action = "Index" });
                    e.MapControllerRoute("EventPageController", "/en/events/{eventName}/{id}/thanks", new { Controller = "EventConfirmationPage", Action = "Index" });
                    e.MapControllerRoute("EventPageController", "/dk/events/{eventName}/{id}/edit", new { Controller = "EventUpdatePage", Action = "Index" });
                })
            });
        });
    }
    
}
Culture is set by using the FindContent to dig out the "correct" page in Umbraco that backs the route, we just check on something known in the route whether we grab the english or the danish item in the FindContent
Copy code
csharp
 public IPublishedContent? FindContent(ActionExecutingContext actionExecutingContext)
 {
     _umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext);
     // danish or english ?
     var culture = actionExecutingContext.HttpContext.Request.RawUrl().Contains("arrangementer") ? "dk" : "en";
     var eventContainer = umbracoContext.Content.GetByContentType(EventContainer.GetModelContentType(_publishedSnapshotAccessor))
         .FirstOrDefault(x => (culture == "en" && x.Name == "Events") || (culture == "dk" && x.Name != "Events"));;
     var eventPage = eventContainer.Descendant<Finansforbundet.Code.Models.EventPage>();

     return eventPage;
 }
Note that this doesn't work proper from 13.3.1 through 13.3.2 but was fixed in 13.4
s
A few backticks could really make this code pop @Kaspar Boel Kjeldsen 😁 https://gist.github.com/matthewzring/9f7bbfd102003963f9be7dbcf7d40e51#syntax-highlighting
k
Duly noted, kinda new to discord 😉
s
Thanks @Kaspar Boel Kjeldsen! That was a push in the right direction. I really appreciate it!
2 Views