---
title: "Routes and pages"
space: "Commera"
url: "https://docs.bwh.tech/commera/theme-reference/routes-and-pages"
updated: "2026-10-08"
---

The **Themed Routes** table in **Shop Theme Settings** decides which page file renders a URL. This page lists the default routes and explains how to add a page.

## The Themed Routes table

Open **Shop Theme Settings** at `/desk/shop-theme-settings`. The **Routes** section has the **Themed Routes** table:

| Column | What it holds |
| --- | --- |
| URL Pattern | A Python regular expression. Commera matches it against the path without the first `/`, for example `en/products`. |
| Template Path | The page file, relative to the theme folder, for example `pages/products/list.html` |
| Requires Auth | When ticked, a guest gets a "not permitted" error before the page runs |

Commera tries the rows in order and uses the first match. It checks each pattern when you save, and refuses an invalid regular expression.

Commera matches from the start of the path only. End each pattern with `$`. Without it, `^(?P<lang>en|ar)/lookbook` also matches `en/lookbook/anything`.

A named group in a pattern, such as `(?P<route>.+)`, becomes a context variable and a request parameter with that name. The product controller reads `route` to find the product.

Commera matches the path of the request as the shopper typed it. Website route rules from other apps do not change it.

## Default routes

Commera adds these rows when you install it, and adds any missing row on each `bench migrate`. `<lang>` is `(?P<lang>en|ar)`.

| URL Pattern | Template Path | Requires Auth |
| --- | --- | --- |
| `^<lang>$` | `pages/index.html` | No |
| `^<lang>/products$` | `pages/products/list.html` | No |
| `^<lang>/products/(?P<route>.+)$` | `pages/products/details.html` | No |
| `^<lang>/cart$` | `pages/cart/cart.html` | No |
| `^<lang>/cart/checkout$` | `pages/cart/checkout.html` | No |
| `^<lang>/account/dashboard$` | `pages/account/dashboard.html` | Yes |
| `^<lang>/account/profile$` | `pages/account/profile.html` | Yes |
| `^<lang>/account/orders$` | `pages/account/orders/index.html` | Yes |
| `^<lang>/account/orders/detail$` | `pages/account/orders/detail.html` | No |
| `^<lang>/track-order$` | `pages/track_order.html` | No |
| `^<lang>/account/orders/confirmation$` | `pages/account/orders/confirmation.html` | No |
| `^<lang>/account/wishlist$` | `pages/account/wishlist.html` | Yes |
| `^<lang>/account/address$` | `pages/account/address.html` | Yes |
| `^<lang>/page/(?P<route>.+)$` | `pages/shop_web_page.html` | No |

Some pages are open to guests on purpose. Their controllers check access themselves:

- **Checkout** sends a guest to the cart.
- **Order detail** opens for a guest who has the private order link.
- **Order confirmation** is the page that the payment gateway returns to. It asks the shopper to sign in.
- **Content pages** under `/page/` are public. An editor can preview an unpublished page.

Do not tick **Requires Auth** on these rows. The check runs before the controller, so the controller cannot send the guest to the right place.

## Add a page with a new route

1. Create the page in your theme, for example `pages/lookbook.html`.
2. In **Themed Routes**, add a row: **URL Pattern** `^(?P<lang>en|ar)/lookbook$`, **Template Path** `pages/lookbook.html`.
3. Save **Shop Theme Settings**.

The route table belongs to the site, not to a theme. A row that you add applies to every theme. Themes without the file fall back to Commera's core page, or return "not found".

## Dynamic pages

When **Enable Dynamic Pages** is ticked, a URL that no route matches maps straight to a file. The file path includes the language:

| URL | File |
| --- | --- |
| `/en/about` | `pages/en/about.html` |
| `/ar/about` | `pages/ar/about.html` |
| `/en/help/returns` | `pages/en/help/returns.html` |

:::caution[Put dynamic pages under pages/en/ and pages/ar/]

A file at `pages/about.html` does not answer `/en/about`. Make one file for each language, under `pages/en/` and `pages/ar/`.

:::

A new Commera site has **Enable Dynamic Pages** ticked. The route table is the main way to add pages. Use dynamic pages for simple content pages.

Dynamic pages answer only paths that start with `en/` or `ar/`, and never a path that contains `..`.

## When Commera's core page answers

Commera's core page serves the URL when:

- No row in **Themed Routes** matches, and dynamic pages are off or no dynamic page file exists.
- A row matches, but no theme in the chain has the file in **Template Path**.
- **Active Theme** in **Shop Theme Settings** is empty.

## Languages

Routes and dynamic pages support two languages: English, `en`, and Arabic, `ar`. For `ar`, the context variable `is_rtl` is true, and `base.html` sets `dir="rtl"` on the page.

## Next steps

- [Templates](/commera/theme-reference/templates): the context that a page gets
- [Step 3: Add pages](/commera/build-a-theme/add-pages)
