The breadcrumb markup

Target group: Developers

Introduction

A breadcrumb is an essential part of a web page. It gives the user an idea of where he is on the web site. He can also navigate to parent pages. But for search engines a breadcrumb is also essential to understand the structure of a web site. Last but not least, the breadcrumb is shown in the search result snippet if structured markup for the breadcrumb is available.

There can also be more than one breadcrumb on a page, Google gives an example in his guidelines for a breadcrumb.

Using the API

You can define a breadcrumb with the API as you may already guessed. For example, you have defined a breadcrumb somewhere:

$breadcrumb = [
   'Some product category' => 'https://example.org/some-product-category/',
   'Some product subcategory' => 'https://example.org/some-product-subcategory/',
   'Some fancy product' => 'https://example.org/some-fancy-product/',
];
Copied!

Now you can iterate over the pages:

EXT:my_extension/Classes/Controller/MyController.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Controller;

use Brotkrueml\Schema\Manager\SchemaManager;
use Brotkrueml\Schema\Type\TypeFactory;

final class MyController
{
    public function __construct(
        private readonly SchemaManager $schemaManager,
        private readonly TypeFactory $typeFactory,
    ) {}

    public function createBreadcrumb(array $breadcrumb): void
    {
        // ...

        $breadcrumbList = $this->typeFactory->create('BreadcrumbList');
        $counter = 0;
        foreach ($breadcrumb as $name => $url) {
            $counter++;

            $breadcrumbList->addProperty(
                'itemListElement',
                $this->typeFactory->create('ListItem')
                    ->setProperties([
                        'name' => $name,
                        'item' => $url,
                        'position' => $counter,
                    ]),
            );
        }
        $this->schemaManager->addType($breadcrumbList);

        // ...
    }
}
Copied!

This results in the following schema markup:

{
   "@context": "https://schema.org/",
   "@type": "WebPage",
   "breadcrumb": {
      "@type": "BreadcrumbList",
      "itemListElement": [
         {
            "@type": "ListItem",
            "item": "https://example.org/some-product-category/",
            "name": "Some product category",
            "position": "1"
         },
         {
            "@type": "ListItem",
            "item": "https://example.org/some-product-subcategory/",
            "name": "Some product subcategory",
            "position": "2"
         },
         {
            "@type": "ListItem",
            "item": "https://example.org/some-fancy-product/",
            "name": "Some fancy product",
            "position": "3"
         }
      ]
   }
}
Copied!

As you can see, the breadcrumb is embedded in a WebPage automatically.

Using the view helpers

View helper <schema:type.breadcrumbList>

The schema markup can also be achieved by a view helper in a Fluid template:

<schema:type.breadcrumbList>
   <f:for each="{breadcrumb}" as="item" iteration="iterator">
      <schema:type.listItem
         -as="itemListElement"
         name="{item.title}"
         item="{item.link}"
         position="{iterator.cycle}"
      />
   </f:for>
</schema:type.breadcrumbList>
Copied!

It is also possible to use it in combination with one of the WebPage types:

<schema:type.itemPage>
   <schema:type.breadcrumbList -as="breadcrumb">
      <f:for each="{breadcrumb}" as="item" iteration="iterator">
         <schema:type.listItem
            -as="itemListElement"
            name="{item.title}"
            item="{item.link}"
            position="{iterator.cycle}"
         />
      </f:for>
   </schema:type.breadcrumbList>
</schema:type.itemPage>
Copied!

View helper <schema:breadcrumb>

But mostly you will have the breadcrumb structure in a Fluid variable created by a MenuProcessor in TypoScript:

EXT:my_extension/Configuration/TypoScript/setup.typoscript
page = PAGE
page {
   # ... some other configuration ...

   10 = FLUIDTEMPLATE
   10 {
      # ... some other configuration ...
      dataProcessing {
         10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor
         10 {
             special = rootline
             as = breadcrumb
         }
      }
   }
}
Copied!

Wouldn't it be cool to use this variable as input for the schema markup without iterating over the structure? So, let's use the breadcrumb view helper for that:

<schema:breadcrumb breadcrumb="{breadcrumb}"/>
Copied!

That is it.

The best place to use this view helper is in the template where you generate the visual representation of the breadcrumb for your users.

Normally the home page is part of the generated breadcrumb, but this is not necessary for the schema markup - so the home page is omitted. But if you really want to have it in the markup (or you have a breadcrumb generated on your own without the home page), you can use the attribute renderFirstItem and set it to 1:

<schema:breadcrumb breadcrumb="{breadcrumb}" renderFirstItem="1"/>
Copied!

You can build your own breadcrumb array and assign it to the template. It should have the following structure:

$breadcrumb = [
   [
      'title' => 'Home page',
      'link' => '/',
      'data' => [
         'tx_schema_webpagetype' => 'WebPage',
      ],
   ],
   [
      'title' => 'Some product category',
      'link' => '/some-product-category/',
      'data' => [
         'tx_schema_webpagetype' => 'CollectionPage',
      ],
   ],
   [
      'title' => 'Some product subcategory',
      'link' => '/some-product-subcategory/',
      'data' => [
         'tx_schema_webpagetype' => 'CollectionPage',
      ],
   ],
   [
      'title' => 'Some fancy product',
      'link' => '/some-fancy-product/',
      'data' => [
         'tx_schema_webpagetype' => 'ItemPage',
      ],
   ],
];
Copied!

If the key tx_schema_webpagetype is omitted, it defaults to WebPage.

Remarks

  • The home page should not be included into the markup.
  • Please keep in mind that according to the Google Structured Data Testing Tool, only the type BreadcrumbList is allowed for the breadcrumb property - either the schema.org definition allows strings. Other types than the BreadcrumbList are ignored by the schema manager.
  • It is intended that the breadcrumb is not automatically rendered out of the page structure of your TYPO3 installation, because it is possible to extend the breadcrumb with own MenuProcessors like in the news extension.