diff --git a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
index 1c745ed6a26..0a75387dd1d 100644
--- a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
+++ b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
@@ -83,16 +83,18 @@ class BreadcrumbManager implements ChainBreadcrumbBuilderInterface {
}
$breadcrumb = $builder->build($route_match);
-
if ($breadcrumb instanceof Breadcrumb) {
$context['builder'] = $builder;
- $breadcrumb->addCacheableDependency($cacheable_metadata);
break;
}
else {
throw new \UnexpectedValueException('Invalid breadcrumb returned by ' . get_class($builder) . '::build().');
}
}
+
+ // Ensure all collected cacheability is applied.
+ $breadcrumb->addCacheableDependency($cacheable_metadata);
+
// Allow modules to alter the breadcrumb.
$this->moduleHandler->alter('system_breadcrumb', $breadcrumb, $route_match, $context);
diff --git a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
index 4f3c9e28b1c..f427fe5fe87 100644
--- a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
+++ b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml
@@ -577,3 +577,11 @@ menu_test.breadcrumb3:
_title: 'Normal title'
requirements:
_access: 'TRUE'
+
+menu_test.skippable-breadcrumb:
+ path: '/menu-test/skippable-breadcrumb'
+ defaults:
+ _controller: '\Drupal\menu_test\Controller\MenuTestController::menuTestCallback'
+ _title: 'Normal title'
+ requirements:
+ _access: 'TRUE'
diff --git a/core/modules/system/tests/modules/menu_test/src/MenuTestServiceProvider.php b/core/modules/system/tests/modules/menu_test/src/MenuTestServiceProvider.php
new file mode 100644
index 00000000000..f6aad34ecf1
--- /dev/null
+++ b/core/modules/system/tests/modules/menu_test/src/MenuTestServiceProvider.php
@@ -0,0 +1,28 @@
+has('system.breadcrumb.default')) {
+ $container->register('menu_test.breadcrumb.default', SkippablePathBasedBreadcrumbBuilder::class)
+ ->setDecoratedService('system.breadcrumb.default')
+ ->addArgument(new Reference('menu_test.breadcrumb.default.inner'))
+ ->addArgument(new Reference('request_stack'));
+ }
+ }
+
+}
diff --git a/core/modules/system/tests/modules/menu_test/src/SkippablePathBasedBreadcrumbBuilder.php b/core/modules/system/tests/modules/menu_test/src/SkippablePathBasedBreadcrumbBuilder.php
new file mode 100644
index 00000000000..fc075042ad6
--- /dev/null
+++ b/core/modules/system/tests/modules/menu_test/src/SkippablePathBasedBreadcrumbBuilder.php
@@ -0,0 +1,40 @@
+addCacheContexts(['url.query_args:' . $query_arg]);
+ // Apply unless the query argument is present.
+ return !$this->requestStack->getCurrentRequest()->query->has($query_arg);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function build(RouteMatchInterface $route_match): Breadcrumb {
+ return $this->pathBasedBreadcrumbBuilder->build($route_match);
+ }
+
+}
diff --git a/core/modules/system/tests/src/Functional/Menu/BreadcrumbTest.php b/core/modules/system/tests/src/Functional/Menu/BreadcrumbTest.php
index ce5ebd448ee..e450a0de6e6 100644
--- a/core/modules/system/tests/src/Functional/Menu/BreadcrumbTest.php
+++ b/core/modules/system/tests/src/Functional/Menu/BreadcrumbTest.php
@@ -388,6 +388,15 @@ class BreadcrumbTest extends BrowserTestBase {
$this->drupalGet('menu-test/breadcrumb1/breadcrumb2/breadcrumb3');
$this->assertSession()->responseContains('');
$this->assertSession()->assertEscaped('');
+
+ // Assert that the breadcrumb cacheability is respected after not applying.
+ $this->assertBreadcrumb(Url::fromRoute('menu_test.skippable-breadcrumb', [], [
+ 'query' => [
+ 'menu_test_skip_breadcrumbs' => 'yes',
+ ],
+ ]), []);
+ $trail = $home + ['menu-test' => 'Menu test root'];
+ $this->assertBreadcrumb(Url::fromRoute('menu_test.skippable-breadcrumb'), $trail);
}
/**