Links and blocks
Page templates rarely contain plain URLs. Instead of hardcoding a path, you point at a page or a reusable block and let the engine resolve it for the current storefront. This page covers the page_link and block_ref helpers, and how to read the link field from a loop item.
Link to another page
{page_link id=<page_id>} renders the URL path of another page in the same project. Place it where the URL belongs, usually in an href.
<a href="{page_link id=10}">Continue shopping</a>
<a href="{page_link id=85}" class="btn">Checkout</a>
| Helper | Meaning | Example |
|---|---|---|
{page_link id=<page_id>} | URL path of the page with that numeric page id | <a href="{page_link id=85}">Checkout</a> |
How the URL resolves:
- The default (home) page resolves to
/; every other page resolves to/{slug}. - An id that does not match a page resolves to
/.
In a page template, declare a page_link variable and use {{key}} in the markup instead. The entry value can be a numeric page id or a page slug.
Embed a reusable block
A block is a section you create once and reuse, such as a product card, call to action, or newsletter signup. Embed one where it should appear:
| Tag | Meaning | Example |
|---|---|---|
{block_ref id=<id>} | Embeds the block with that numeric block id | {block_ref id=284} |
{block_ref code=<code>} | Embeds the block whose code matches | {block_ref code=product_item} |
<main class="mx-auto max-w-7xl px-4">
{block_ref id=284}
<section>
<h1>Browse products</h1>
<p>{brand.tagline}</p>
</section>
</main>
A reference renders the block's markup in place, so the same section appears on every page that references it. Update the block once and every page changes.
- A code is matched against the block's code and its normalized name, so a block named "Product Item" and the code
product_itempoint at the same block. - A reference that does not resolve renders nothing, so keep codes accurate.
- Avoid circular references: a block that embeds itself, directly or through another block, is skipped.
- Header and footer blocks are placed automatically for every page by the layout, so you do not embed them with
block_refin page content.
Links from loop items
Some collections give each item a link of its own, so you read the URL from the current item alias instead of building a path by hand. A navigation loop reads the link and its label from the alias:
{each nav_links as=link}
<a href="{link.href}">{link.label}</a>
{/each}
The same pattern works for any collection whose items carry a link field: open the loop with an alias, then read that field from the alias. A field that does not resolve renders nothing, so keep the element and let the value fill in. See Loops for the loop syntax.
Product, category, and other extension collections expose their own link and media fields, and the storefront resolves them to the matching view page and slug instead of a hardcoded path. They are documented with the extension that provides them:
- Commerce products covers product link, image, and price fields.
- Portfolio categories covers category and project link fields.
Combining page links, blocks, and tokens
Helpers and tokens work together in the same markup. This section links to pages by id, shows a brand value, and pulls in a shared block:
<section class="border-t">
<a href="{page_link id=10}">Shop</a>
<a href="{page_link id=79}">Account</a>
<a href="{page_link id=108}">Terms</a>
<p>{brand.store_name}</p>
{block_ref id=284}
</section>

