# Templates and Routing

> Save reusable merchant templates, build product and collection resource templates, and route store URLs to them

Canonical URL: https://77865786950d:3005/tools/templates-and-routing

This page covers two separate features:

- **Merchant templates** are reusable source-format sections that you own, such
  as a header, footer, announcement bar or product block. When you apply one,
  it is copied into a page as ordinary source.
- **Resource templates** are whole pages that render for many products or
  collections. Routes decide which template serves
  `/a/lp/products/<handle>` and `/a/lp/collections/<handle>`.

For the public section and kit catalog, see [Templates](/tools/templates).

## Merchant templates

A merchant template holds exactly one source-format section. It can contain
any supported island composition. Applying it never changes renderer-level
defaults, and archiving it never changes pages that already use it.

| Step | Tool · action | Access |
|---|---|---|
| List your templates | `lexsis_template_library` · `list_mine` | Read |
| Read one, with its current revision and source | `lexsis_template_library` · `get_mine` | Read |
| Save a section as a template | `lexsis_drafts` · `template_create` | Draft |
| Change metadata or add a new source revision | `lexsis_drafts` · `template_update` | Draft |
| Copy a template into a page | `lexsis_drafts` · `template_apply` | Draft |
| Publish the latest valid revision | `lexsis_live_ops` · `template_publish` | Live, needs approval |
| Archive a template | `lexsis_live_ops` · `template_archive` | Live, needs approval |

### Create a template

```json
{
  "name": "lexsis_drafts",
  "arguments": {
    "action": "template_create",
    "args": {
      "workspace_id": "workspace-uuid",
      "name": "Summer announcement bar",
      "source": "<!-- section: announcement --><section>...</section>",
      "visibility": "private",
      "tags": ["announcement", "summer"]
    }
  }
}
```

- `source` must compile to exactly one section. Compile warnings come back as
  `compile_warnings`.
- `slug` is optional. It defaults to a slug of `name` and must match
  `^[a-z0-9](?:[a-z0-9-]{0,126}[a-z0-9])?$`.
- `visibility` is `private` (default) or `workspace`.
- `section` (a category label) defaults to the source's section ID. You can add
  up to 30 `tags` and a `description` of up to 2,000 characters.

`template_update` takes `template_id` and `workspace_id`, plus any of `name`,
`description`, `visibility`, `section`, `tags`, or `source`. Passing `source`
creates a new immutable revision.

### Apply a template to a page

```json
{
  "name": "lexsis_drafts",
  "arguments": {
    "action": "template_apply",
    "args": {
      "template_id": "template-uuid",
      "page_id": "page-uuid",
      "expected_version": 7,
      "position": { "after": "hero" }
    }
  }
}
```

- `expected_version` is required. A stale version fails instead of
  overwriting a newer edit.
- `position` is `"first"`, `"last"`, `{ "before": "<section id>" }` or
  `{ "after": "<section id>" }`. New sections go last by default.
- Pass `section_id` to choose the section's ID on the page. If that ID already
  exists, the section is replaced in place unless you also pass `position`.
- Applying creates exactly one new page version. Once applied, the section is
  ordinary page source; later template revisions don't change it.

`template_publish` publishes the latest valid revision, or a specific
`revision_id`.

## Resource templates

A resource template is an ordinary Lexsis page, with full CSS, JS and islands,
that renders for whichever product or collection the URL names.

### 1. Build and mark the template

- To create a new template, pass `resource_type: "product"` or
  `"collection"` to `lexsis_pages` · `compile` and to `lexsis_page_create` ·
  `create`. Compile warns with check `resource_template_hardcoded` when an
  island is pinned to one resource.
- To mark an existing draft, use `lexsis_drafts` · `set_resource_template`
  with `{ page_id, resource_type, preview_resource_handle? }`. Pass
  `resource_type: null` to unmark it.

Marking is draft-level and reversible. It doesn't route any traffic.

### 2. Bind content to the resource

- Product islands such as BuyBox, ProductGallery, StickyBar and QuickAdd bind
  to the routed product automatically. Leave out `productId` and `product`.
- CollectionGrid and CollectionSwipe: set `"collection": "$resource"`, or
  leave it out.
- ReviewList and ReviewCarousel: set `"productIds": "$resource"`. See
  [Reviews](/tools/reviews#no-reviews-fallback).
- Page-level text: put `data-lx-product="<path>"` on any element. Use
  `data-lx-product-src`, `data-lx-product-href` or `data-lx-product-alt` for
  attributes. Paths are the same as in collection card templates: `id`,
  `handle`, `url`, `title`, `type`, `vendor`, `description`, `price`,
  `compareAt`, `available`, `images.N.url`, `images.N.alt`,
  `metafields.<ns>.<key>`.
- Conditions: `data-lx-product-if="tag:sale"` or
  `data-lx-product-unless="available"`.

### 3. Preview

```text
<renderer>/v/<template slug>?preview=1&resource=product:<handle>
```

Use `collection:<handle>` for collection templates. `preview_resource_handle`
sets the default handle.

## Route live traffic

Routing moves live traffic, so `resource_route_upsert` and
`resource_route_delete` need explicit approval.

```json
{
  "name": "lexsis_live_ops",
  "arguments": {
    "action": "resource_route_upsert",
    "args": {
      "resource_type": "product",
      "match_kind": "tag",
      "match_value": "bundle",
      "priority": 50,
      "page_id": "template-page-uuid"
    }
  }
}
```

| Field | Values |
|---|---|
| `resource_type` | `product` or `collection` |
| `match_kind` | `default`, `handle`, `collection`, `tag`, `product_type`, `vendor` |
| `match_value` | Omit for `default`. A handle for `handle` and `collection`. Otherwise the tag, product type or vendor. |
| `priority` | 0–10000, default 100. Lower numbers are checked first. |
| `page_id` or `experiment_id` | Exactly one. An experiment's variants must be template pages. |
| `status` | `active` or `paused` |

Routes are unique per store, `resource_type`, `match_kind` and `match_value`.
An upsert with the same key updates the existing route.
`resource_route_delete` takes a `route_id` from `resource_routes`.

### Precedence

When a shopper opens a product or collection URL, the first match wins:

1. A dedicated page whose handle is that resource's handle.
2. A `handle` route.
3. Other rules, by `priority` (lower first). Ties go to the oldest route.
4. The `default` route.
5. Otherwise, 404.

### Check routing before going live

- `lexsis_pages` · `resource_routes` lists the store's routes.
- `lexsis_pages` · `resolve_resource` with `{ resource_type, handle }` is a dry
  run. It returns the page or experiment that would serve the handle and why
  (`page`, `handle`, `rule` or `default`).

## Related

- [Tool Reference](/tools/reference)
- [Templates](/tools/templates)
- [Reviews](/tools/reviews)
- [Collection Grid](/islands/commerce/collection-grid)
- [Publishing](/pages/publishing)
