Core Breadcrumb Architecture
When to Use
Read this before writing any custom builder or alter hook. The
BreadcrumbManageris the chain dispatcher; every breadcrumb request routes through it.
Decision
| Component | Role | Key method |
|---|---|---|
BreadcrumbBuilderInterface |
Contract all builders implement | applies(), build() |
BreadcrumbManager |
Chain dispatcher, sorted by priority | build() calls getSortedBuilders(), iterates, takes first applies() === TRUE |
Breadcrumb |
Value object: links + cache metadata | addLink(), addCacheContexts(), addCacheableDependency() |
BreadcrumbPreprocess |
Template preprocessor | Converts Link objects to [text, url] arrays for Twig |
hook_system_breadcrumb_alter |
Post-build hook | Fires after winning builder; receives Breadcrumb, RouteMatchInterface, $context |
Pattern
// BreadcrumbManager::build() — simplified
$cacheable_metadata = new CacheableMetadata();
$breadcrumb = new Breadcrumb();
foreach ($this->getSortedBuilders() as $builder) {
if (!$builder->applies($route_match, $cacheable_metadata)) {
continue;
}
$breadcrumb = $builder->build($route_match);
$context['builder'] = $builder;
break;
}
$breadcrumb->addCacheableDependency($cacheable_metadata); // merge applies() metadata
$this->moduleHandler->alter('system_breadcrumb', $breadcrumb, $route_match, $context);
return $breadcrumb;
Key behaviors:
- Breadcrumb uses RefinableCacheableDependencyTrait — cacheability added in applies() is automatically merged into the returned breadcrumb
- Builders are tagged with breadcrumb_builder in *.services.yml; the RegisterBreadcrumbBuilderPass compiler pass collects them by priority
- Higher priority number = checked first; only the first applies() === TRUE builder's build() is called
Common Mistakes
- Wrong: Adding cache metadata in both
applies()andbuild()→ Right:applies()metadata is merged automatically; double-adding is redundant but harmless - Wrong: Returning
NULLfrombuild()→ Right: Always return aBreadcrumbinstance; the manager throwsUnexpectedValueExceptiononNULL - Wrong: Assuming all builders run → Right: Only the winning builder's
build()is called; all other builders only haveapplies()checked
See Also
- Core Breadcrumb Builders
- Custom Breadcrumb Builder
- Reference:
core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php - Reference:
core/lib/Drupal/Core/Breadcrumb/Breadcrumb.php