How-to library · Developer docs

How-to library

Task-shaped pages: a title that starts with a verb, the situation in a few lines, the steps, the working code in both engines, and why this way rather than another. Found from a search, done, and left.

Build a breadcrumb trail from a record's ancestors

getAllParents() returns a page's ancestors from the root down. Label the root "Home" yourself, link the rest with getFullPath(), and build a post's or record's trail from its container instead.

Context

Context. A page's breadcrumb is its ancestors in order, then itself. getAllParents() returns exactly that list, from the root page down to the immediate parent. The root page is the home page: it has no slug and whatever name the editor gave it, so label it yourself. Blog posts, FAQ questions and custom entity records have no page ancestors; their trail is their container, so build it from the blog, the FAQ page or the listing path instead.

Steps

  1. Loop over getAllParents(), printing the first as "Home" and the rest by name.
  2. Link every ancestor with getFullPath().
  3. Print the current page as text, marked aria-current="page", not as a link.
  4. For a blog post, print Home, the blog, then the post.

Template code

Template code
<nav aria-label="Breadcrumb"><ol class="breadcrumb">
{foreach $page->getAllParents() as $ancestor}
  <li><a href="{$ancestor->getFullPath()}">{if $ancestor@first}Home{else}{$ancestor->getName()|escape}{/if}</a></li>
{/foreach}
  <li aria-current="page">{$page->getName()|escape}</li>
</ol></nav>

{* a blog post *}
{$blog = $post->getBlog()}
<ol class="breadcrumb">
  <li><a href="/">Home</a></li>
  <li><a href="{$blog->getFullPath()}">{$blog->getName()|escape}</a></li>
  <li aria-current="page">{$post->getName()|escape}</li>
</ol>
<nav aria-label="Breadcrumb"><ol class="breadcrumb">
{% for ancestor in page.getAllParents() %}
  <li><a href="{{ ancestor.getFullPath() }}">{% if loop.first %}Home{% else %}{{ ancestor.getName()|e }}{% endif %}</a></li>
{% endfor %}
  <li aria-current="page">{{ page.getName()|e }}</li>
</ol></nav>

{# a blog post #}
{% set blog = post.getBlog() %}
<ol class="breadcrumb">
  <li><a href="/">Home</a></li>
  <li><a href="{{ blog.getFullPath() }}">{{ blog.getName()|e }}</a></li>
  <li aria-current="page">{{ post.getName()|e }}</li>
</ol>

Why this and not that

Not the URL split on slashes: slugs are not names, a custom URL has no ancestors in it, and a page reached through a custom URL would show the wrong trail. Not getParent() in a loop of your own: getAllParents() is one call and already ordered. Book pages have neither method; walk getUnit() and getBook() for those.

Go deeper

Was this page helpful?

Your answer goes to the docs team.