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); } /**