I'm confused by the syntax for URL routes. Using Craft 3. I'm working with two separate category groups and have urls like this:


where 'abc' and 'xyz' are parent and child slugs from the same category group. And where 123 is the category slug from the second separate category group. Actual slugs consist of alphanumeric names with dashes replacing spaces.

Now I'd like to replace the parameter style url with a segment style url


Both categories use the same _category.html template. I need to have access to all category variables inside the template. I got as far as knowing I need to set up custom routes in config/routes.php but am lost on the syntax.

1 Answer 1


Using routes

You can define a route like this in your config/routes.php:

return [
    '<country:{slug}>/<city:{slug}>/<productType:{slug}>' => ['template' => '_category'],

This will match any URL with three slug-like segments in the path and load the specified template. Your template will have access to the named parameters (country, city and productType), but Craft will not check if those are actual categories. That's on you to check in the template, for example:

{% set countryCategory = craft.categories().slug(country).one() %}
{% set cityCategory = craft.categories().slug(city).ancestorOf(countryCategory).one() %}
{% set productTypeCategory = craft.categories().slug(productType).one() %}

{% if not countryCategory and not cityCategory and not productTypeCategory %}
    {% exit 404 %}
{% endif %}

To support URLs with only one or two segments in the path, you have two options:

  • Define two additional URL rules similar to this one with only one and two segments, respectively.
  • Use Default Parameter Values in the route definition (I never used that, but it should work).

Using URI formats (Original answer)

This only works if the categories are related and each category has a unique URL, see comments.

You don't need a custom route, you can do this with the Entry URI format (or Category URI format for categories) setting of the category group. The entry URI template can be a full Twig template and has access to all fields on the entry. For example, if the first category group has a field secondCategory you can pull the slug their slug in like this:

{{ object.parent.uri ?? '' }}/{{ object.slug }}/{{ object.secondCategory.one().slug ?? '' }}

{{ object.parent.uri ?? '' }} adds the parent's URI to the current categories URI, this is how you get hierarchical URLs for nested structures.
{{ object.secondCategory.one().slug ?? '' }} adds the slug of the second category related to the first category as the last URL segment.

  • Thanks but I can't get it functional yet. Following my example, I used this for the category URI field in both categories: {{ object.parent.uri ?? '' }}/{{ object.slug }}/{{ object.123.one().slug ?? '' }} throws error "template not found"
    – Jake
    Commented Aug 2, 2023 at 10:08
  • Maybe I should add this is needed for a category page, which is listing all entries related to a category. Each entry has a category ("abc"), an optional subcategory ("xyz") and mandatory second categorygroup category ("123"). I suppose I need to change the Category URI Format and not the Entry URI
    – Jake
    Commented Aug 2, 2023 at 10:18
  • @Jake What is object.123 supposed to do here? Yes, if /abc/xyz/123 is the URL of a category page, you need to set the URI format on the category group.
    – MoritzLost
    Commented Aug 2, 2023 at 10:19
  • In my example, secondCategory is the handle of the field connecting the categories to each other, not the slug of a specific category.
    – MoritzLost
    Commented Aug 2, 2023 at 10:20
  • If those two categories aren't related, I'm not sure your approach makes sense. If categories abc and 123 aren't related at all, how would you know which combinations of categories to use in your URI format?
    – MoritzLost
    Commented Aug 2, 2023 at 10:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.