diff --git a/core/core.services.yml b/core/core.services.yml index 65882af..5027e0e 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -522,6 +522,7 @@ services: arguments: ['@image.toolkit'] breadcrumb: class: Drupal\Core\Breadcrumb\BreadcrumbManager + arguments: ['@module_handler'] token: class: Drupal\Core\Utility\Token arguments: ['@module_handler'] diff --git a/core/includes/menu.inc b/core/includes/menu.inc index ccc40f8..ff5ce21 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -144,7 +144,7 @@ */ /** - * Menu type -- A "normal" menu item that's shown in menu and breadcrumbs. + * Menu type -- A "normal" menu item that's shown in menus. * * Normal menu items show up in the menu tree and can be moved/hidden by * the administrator. Use this for most menu items. It is the default value if @@ -156,7 +156,7 @@ * Menu type -- A hidden, internal callback, typically used for API calls. * * Callbacks simply register a path so that the correct function is fired - * when the URL is accessed. They do not appear in menus or breadcrumbs. + * when the URL is accessed. They do not appear in menus. */ const MENU_CALLBACK = 0x0000; @@ -198,7 +198,7 @@ /** * Menu type -- A task specific to the parent, which is never rendered. * - * Sibling local tasks are not rendered themselves, but affect the breadcrumb + * Sibling local tasks are not rendered themselves, but affect the active * trail and need their sibling tasks rendered as tabs. */ define('MENU_SIBLING_LOCAL_TASK', MENU_IS_LOCAL_TASK | MENU_IS_LOCAL_ACTION | MENU_VISIBLE_IN_BREADCRUMB); @@ -435,7 +435,7 @@ function menu_unserialize($data, $map) { * @param $router_item * The router item. Usually a router entry from menu_get_item() is either * modified or set to a different path. This allows the navigation block, - * the page title, the breadcrumb, and the page help to be modified in one + * the page title, the active trail, and the page help to be modified in one * call. */ function menu_set_item($path, $router_item) { @@ -1257,7 +1257,7 @@ function menu_tree_get_path($menu_name) { * @param $only_active_trail * (optional) Whether to only return the links in the active trail (TRUE) * instead of all links on every level of the menu link tree (FALSE). Defaults - * to FALSE. Internally used for breadcrumbs only. + * to FALSE. * * @return * An array of menu links, in the order they should be rendered. The array @@ -1286,7 +1286,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail = // template_preprocess_page(). So in order to not build a giant menu tree // that needs to be checked for access on all levels, we simply check // whether we have the menu already in cache, or otherwise, build a minimum - // tree containing the breadcrumb/active trail only. + // tree containing the active trail only. // @see menu_set_active_trail() if (!isset($tree[$cid]) && $only_active_trail) { $cid .= ':trail'; @@ -1388,8 +1388,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail = * - active_trail: An array of mlids, representing the coordinates of the * currently active menu link. * - only_active_trail: Whether to only return links that are in the active - * trail. This option is ignored, if 'expanded' is non-empty. Internally - * used for breadcrumbs. + * trail. This option is ignored, if 'expanded' is non-empty. * - min_depth: The minimum depth of menu links in the resulting tree. * Defaults to 1, which is the default to build a whole tree for a menu * (excluding menu container itself). @@ -1599,7 +1598,7 @@ function _menu_tree_data(&$links, $parents, $depth) { $tree = array(); while ($item = array_pop($links)) { // We need to determine if we're on the path to root so we can later build - // the correct active trail and breadcrumb. + // the correct active trail. $item['in_active_trail'] = in_array($item['mlid'], $parents); // Add the current link to the tree. $tree[$item['mlid']] = array( @@ -2410,9 +2409,7 @@ function menu_set_active_item($path) { * * Any trail set by this function will only be used for functionality that calls * menu_get_active_trail(). Drupal core only uses trails set here for - * breadcrumbs and the page title and not for menu trees or page content. - * Additionally, breadcrumbs set by drupal_set_breadcrumb() will override any - * trail set here. + * the page title and not for menu trees or page content. * * To affect the trail used by menu trees, use menu_tree_set_path(). To affect * the page content, use menu_set_active_item() instead. diff --git a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php index 5396e9e..77501eb 100644 --- a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php +++ b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php @@ -7,6 +7,8 @@ namespace Drupal\Core\Breadcrumb; +use Drupal\Core\Extension\ModuleHandlerInterface; + /** * Provides a breadcrumb manager. * @@ -16,6 +18,13 @@ class BreadcrumbManager implements BreadcrumbBuilderInterface { /** + * The module handler to invoke the alter hook. + * + * @var \Drupal\Core\Extension\ModuleHandlerInterface + */ + protected $moduleHandler; + + /** * Holds arrays of breadcrumb builders, keyed by priority. * * @var array @@ -32,6 +41,16 @@ class BreadcrumbManager implements BreadcrumbBuilderInterface { protected $sortedBuilders; /** + * Constructs a \Drupal\Core\Breadcrumb\BreadcrumbManager object. + * + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + * The module handler. + */ + public function __construct(ModuleHandlerInterface $module_handler) { + $this->moduleHandler = $module_handler; + } + + /** * Adds another breadcrumb builder. * * @param \Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface $builder @@ -49,25 +68,30 @@ public function addBuilder(BreadcrumbBuilderInterface $builder, $priority) { * {@inheritdoc} */ public function build(array $attributes) { + $breadcrumb = array(); + $successful_builder = NULL; // Call the build method of registered breadcrumb builders, // until one of them returns an array. foreach ($this->getSortedBuilders() as $builder) { - $breadcrumb = $builder->build($attributes); - if (!isset($breadcrumb)) { + $build = $builder->build($attributes); + if (!isset($build)) { // The builder returned NULL, so we continue with the other builders. continue; } - elseif (is_array($breadcrumb)) { + elseif (is_array($build)) { // The builder returned an array of breadcrumb links. - return $breadcrumb; + $breadcrumb = $build; + $successful_builder = $builder; + break; } else { throw new \UnexpectedValueException(format_string('Invalid breadcrumb returned by !class::build().', array('!class' => get_class($builder)))); } } - + // Allow modules to alter the breadcrumb. + $this->moduleHandler->alter('system_breadcrumb', $breadcrumb, $attributes, $successful_builder); // Fall back to an empty breadcrumb. - return array(); + return $breadcrumb; } /** diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index 11645ea..1671c7f 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -1351,6 +1351,21 @@ function hook_module_implements_alter(&$implementations, $hook) { } /** + * Perform alterations to the breadcrumb built by \Drupal\Core\Breadcrumb\BreadcrumbManager. + * + * @param array $breadcrumb + * Array of breadcrumb links. + * @param array $attributes + * Attributes representing the current page. + * @param \Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface $builder + * The builder instance that constructed this breadcrumb, or NULL if no + * builder acted based on the current attributes. + */ +function hook_system_breadcrumb_alter(array &$breadcrumb, array $attributes, $builder = NULL) { + // Add an item to the end of the breadcrumb. +} + +/** * Return additional themes provided by modules. * * Only use this hook for testing purposes. Use a hidden MYMODULE_test.module