Hi !
I have built several Kirby websites in the past months and it’s been a breeze .
Now the main thing I have really struggled with has been routing. Seems like I can’t wrap my head around it.
I’m trying to change a few URLs in the structure of my website.
Context: it’s v4 website, using multilanguage configuration for english (en) and french (fr). I have two collections: products, and blog posts, alongside normal pages. I have the Retour plugin installed.
The first question I guess is : is routing the good thing to use or should I just redirects in Retour? I feel like routing is a more maintainable way of doing it. Also I’d love to understand routing. My default language is configured to not show the /fr/ in the url.
Currently I have: in FR:
example.com/produits/
=> it’s the shop landing pageexample.com/produits/nom-du-produit
=> an individual productexample.com/articles/
=> the blog page with the list of latest publicationsexample.com/articles/un-titre-article-de-blog
=> an individual article
Those urls are translated as in EN;
example.com/en/products/
example.com/en/products/product-name
example.com/en/news/
example.com/en/news/a-blog-post-title
Here is what I’m trying to do:
Parent pages and their translation stay the same
example.com/produits/
stays the same, pluralexample.com/articles/
same
And then I want to change:
Product is still a child of /produits/ but the url is singular. Similar in english:
example.com/produits/nom-du-produit
=>example.com/produit/nom-du-produit
example.com/en/products/product-name
=>example.com/en/product/product-name
Blog posts are still children of /articles/ and /en/news but site in the root url:
example.com/articles/un-article-de-blog
=>example.com/un-article-de-blog
example.com/en/news/a-blog-post-title
=>example.com/en/a-blog-post-title
For those who wonder why I’d do that, it’s an old website with years of history and we’d like to reproduce the url structure from the previous website (wordpress). If that’s the only way/best way I can concede to putting back the blog posts in the root folder but i’d rather not.
Thanks in advance a lot for any guidance about the errors I could have made…
Here is what I tried but I get 404s.
For example for a singular product I get 404 on /vin/product-name and on /vins/product-name
I tried to use the docs, the examples and even code llm but to no effect. I get 404s all around in a way or another or with only one of the cases working.
// /site/config/config.php
'routes' => [
[
// Route to change the French product URL from plural to singular
'pattern' => 'produits/(:any)', // Match any product under /produits/
'language' => 'fr', // Apply only for the French version
'action' => function ($productSlug) {
// Redirect to the singular /produit/ slug
$productPage = page('produits/' . $productSlug);
if ($productPage) {
return $productPage;
}
return false; // Return false to allow Kirby to show a 404 error
}
],
[
// Route to change the English product URL from plural to singular
'pattern' => 'en/products/(:any)',
'language' => 'en', // Apply only for the English version
'action' => function ($productSlug) {
$productPage = page('en/products/' . $productSlug);
if ($productPage) {
return $productPage;
}
return false;
}
],
// Route to remove the parent "articles" slug from French blog posts
[
'pattern' => '(:any)',
'language' => 'fr',
'action' => function($slug) {
// First, try to find the page at the root level (e.g., /un-article-de-blog)
$page = page($slug);
// If not found at the root, try to find it under the "articles" parent page
if(!$page) {
$page = page('articles/' . $slug);
}
// If still not found, show the error page
if (!$page) {
$page = site()->errorPage();
}
// Visit the resolved page (either root, articles, or error page)
return site()->visit($page);
}
],
// Route to handle redirects for old French URLs (e.g., /articles/un-article-de-blog => /un-article-de-blog)
[
'pattern' => 'articles/(:any)',
'language' => 'fr',
'action' => function($slug) {
// Redirect to the new root-level URL
go('/' . $slug);
}
],
// Route to remove the parent "news" slug from English blog posts
[
'pattern' => 'en/(:any)',
'language' => 'en',
'action' => function($slug) {
// First, try to find the page at the root level (e.g., /en/a-blog-post-title)
$page = page('en/' . $slug);
// If not found at the root, try to find it under the "en/news" parent page
if(!$page) {
$page = page('en/news/' . $slug);
}
// If still not found, show the error page
if (!$page) {
$page = site()->errorPage();
}
// Visit the resolved page (either root, en/news, or error page)
return site()->visit($page);
}
],
// Route to handle redirects for old English URLs (e.g., /en/news/a-blog-post-title => /en/a-blog-post-title)
[
'pattern' => 'en/news/(:any)',
'language' => 'en',
'action' => function($slug) {
// Redirect to the new root-level URL for English articles
go('/en/' . $slug);
}
],
]
Here is my fr.php config
// /site/languages/fr.php
return [
'code' => 'fr',
'default' => true,
'direction' => 'ltr',
'locale' => [
'LC_ALL' => 'fr_FR'
],
'name' => 'Français',
'url' => '/'
];