2002-12-24 15:40:32 +00:00
< ? php
2003-12-27 21:29:20 +00:00
2004-07-22 16:06:54 +00:00
/**
* @ file
* API for the Drupal menu system .
*/
2013-10-07 05:34:09 +00:00
use Drupal\Component\Utility\String ;
2014-01-22 20:35:48 +00:00
use Drupal\Core\Cache\Cache ;
2013-05-25 20:12:45 +00:00
use Drupal\Core\Language\Language ;
2012-09-04 13:32:47 +00:00
use Drupal\Core\Template\Attribute ;
2014-02-26 10:53:29 +00:00
use Drupal\menu_link\MenuLinkInterface ;
2013-09-06 20:53:28 +00:00
use Symfony\Cmf\Component\Routing\RouteObjectInterface ;
2012-09-04 13:32:47 +00:00
2003-12-17 22:15:35 +00:00
/**
2013-10-18 04:08:20 +00:00
* @ defgroup menu Menu and routing system
2003-12-17 22:15:35 +00:00
* @ {
2004-09-09 05:51:08 +00:00
* Define the navigation menus , and route page requests to code based on URLs .
2004-07-10 18:10:36 +00:00
*
2013-10-18 04:08:20 +00:00
* The Drupal routing system defines how Drupal responds to URLs passed to the
* browser . The menu system , which depends on the routing system , is used for
* navigation . The Menu module allows menus to be created in the user interface
* as hierarchical lists of links .
*
* @ section registering_paths Registering router paths
* To register a path , you need to add lines similar to this in a
* module . routing . yml file :
* @ code
* block . admin_display :
* path : '/admin/structure/block'
* defaults :
* _content : '\Drupal\block\Controller\BlockListController::listing'
* requirements :
* _permission : 'administer blocks'
* @ endcode
* @ todo Add more information here , especially about controllers and what all
* the stuff in the routing . yml file means .
*
* @ section Defining menu links
2014-03-01 04:58:58 +00:00
* Once you have a route defined , you can use hook_menu_link_defaults () to
* define links for your module ' s paths in the main Navigation menu or other
* menus . See the hook_menu_link_defaults () documentation for more details .
2013-10-18 04:08:20 +00:00
*
* @ todo The rest of this topic has not been reviewed or updated for Drupal 8. x
* and is not correct !
* @ todo It is quite likely that hook_menu () will be replaced with a different
* hook , configuration system , or plugin system before the 8.0 release .
2004-07-10 18:10:36 +00:00
*
* Drupal ' s menu system follows a simple hierarchy defined by paths .
* Implementations of hook_menu () define menu items and assign them to
* paths ( which should be unique ) . The menu system aggregates these items
* and determines the menu hierarchy from the paths . For example , if the
* paths defined were a , a / b , e , a / b / c / d , f / g , and a / b / h , the menu system
* would form the structure :
* - a
* - a / b
* - a / b / c / d
* - a / b / h
* - e
* - f / g
* Note that the number of elements in the path does not necessarily
* determine the depth of the menu item in the tree .
*
* When responding to a page request , the menu system looks to see if the
* path requested by the browser is registered as a menu item with a
* callback . If not , the system searches up the menu tree for the most
* complete match with a callback it can find . If the path a / b / i is
* requested in the tree above , the callback for a / b would be used .
*
2005-11-24 22:04:10 +00:00
* The found callback function is called with any arguments specified
2007-05-16 13:45:17 +00:00
* in the " page arguments " attribute of its menu item . The
2005-11-24 22:04:10 +00:00
* attribute must be an array . After these arguments , any remaining
* components of the path are appended as further arguments . In this
* way , the callback for a / b above could respond to a request for
* a / b / i differently than a request for a / b / j .
2004-07-10 18:10:36 +00:00
*
* For an illustration of this process , see page_example . module .
*
* Access to the callback functions is also protected by the menu system .
2007-05-16 13:45:17 +00:00
* The " access callback " with an optional " access arguments " of each menu
* item is called before the page callback proceeds . If this returns TRUE ,
2010-12-08 06:48:39 +00:00
* then access is granted ; if FALSE , then access is denied . Default local task
* menu items ( see next paragraph ) may omit this attribute to use the value
* provided by the parent item .
2004-07-10 18:10:36 +00:00
*
* In the default Drupal interface , you will notice many links rendered as
* tabs . These are known in the menu system as " local tasks " , and they are
* rendered as tabs by default , though other presentations are possible .
* Local tasks function just as other menu items in most respects . It is
* convention that the names of these tasks should be short verbs if
* possible . In addition , a " default " local task should be provided for
* each set . When visiting a local task ' s parent menu item , the default
* local task will be rendered as if it is selected ; this provides for a
* normal tab user experience . This default task is special in that it
* links not to its provided path , but to its parent item ' s path instead .
* The default task ' s path is only used to place it appropriately in the
* menu hierarchy .
2007-05-16 13:45:17 +00:00
*
* Everything described so far is stored in the menu_router table . The
* menu_links table holds the visible menu links . By default these are
2007-07-04 21:33:55 +00:00
* derived from the same hook_menu definitions , however you are free to
2007-05-16 13:45:17 +00:00
* add more with menu_link_save () .
2003-12-17 22:15:35 +00:00
*/
2004-06-18 15:04:37 +00:00
/**
2010-10-08 05:07:53 +00:00
* @ defgroup menu_flags Menu flags
2004-07-10 15:51:48 +00:00
* @ {
2004-06-18 15:04:37 +00:00
* Flags for use in the " type " attribute of menu items .
*/
2004-09-09 05:51:08 +00:00
2008-05-26 17:12:55 +00:00
/**
* Internal menu flag -- menu item is the root of the menu tree .
*/
2011-11-29 09:56:53 +00:00
const MENU_IS_ROOT = 0x0001 ;
2008-05-26 17:12:55 +00:00
/**
* Internal menu flag -- menu item is visible in the menu tree .
*/
2011-11-29 09:56:53 +00:00
const MENU_VISIBLE_IN_TREE = 0x0002 ;
2008-05-26 17:12:55 +00:00
/**
2010-01-25 10:38:35 +00:00
* Internal menu flag -- menu item links back to its parent .
2008-05-26 17:12:55 +00:00
*/
2011-11-29 09:56:53 +00:00
const MENU_LINKS_TO_PARENT = 0x0008 ;
2008-05-26 17:12:55 +00:00
/**
* Internal menu flag -- menu item can be modified by administrator .
*/
2011-11-29 09:56:53 +00:00
const MENU_MODIFIED_BY_ADMIN = 0x0020 ;
2008-05-26 17:12:55 +00:00
/**
* Internal menu flag -- menu item was created by administrator .
*/
2011-11-29 09:56:53 +00:00
const MENU_CREATED_BY_ADMIN = 0x0040 ;
2008-05-26 17:12:55 +00:00
/**
* Internal menu flag -- menu item is a local task .
*/
2011-11-29 09:56:53 +00:00
const MENU_IS_LOCAL_TASK = 0x0080 ;
2004-09-09 05:51:08 +00:00
2004-07-10 15:51:48 +00:00
/**
2012-05-17 12:58:49 +00:00
* @ } End of " defgroup menu_flags " .
2004-07-10 15:51:48 +00:00
*/
/**
2010-10-08 05:07:53 +00:00
* @ defgroup menu_item_types Menu item types
2004-07-10 15:51:48 +00:00
* @ {
2011-04-12 20:47:04 +00:00
* Definitions for various menu item types .
2011-01-03 18:03:54 +00:00
*
2004-07-10 15:51:48 +00:00
* Menu item definitions provide one of these constants , which are shortcuts for
2011-01-03 18:03:54 +00:00
* combinations of @ link menu_flags Menu flags @ endlink .
2004-07-10 15:51:48 +00:00
*/
2003-12-17 22:15:35 +00:00
2004-06-18 15:04:37 +00:00
/**
2013-09-26 08:32:39 +00:00
* Menu type -- A " normal " menu item that ' s shown in menus .
2008-05-26 17:12:55 +00:00
*
2004-06-18 15:04:37 +00:00
* Normal menu items show up in the menu tree and can be moved / hidden by
2004-07-10 18:10:36 +00:00
* the administrator . Use this for most menu items . It is the default value if
* no menu item type is specified .
2004-06-18 15:04:37 +00:00
*/
2014-03-01 04:58:58 +00:00
define ( 'MENU_NORMAL_ITEM' , MENU_VISIBLE_IN_TREE );
2004-04-15 20:49:42 +00:00
2004-06-18 15:04:37 +00:00
/**
2008-05-26 17:12:55 +00:00
* Menu type -- A hidden , internal callback , typically used for API calls .
*
2004-06-18 15:04:37 +00:00
* Callbacks simply register a path so that the correct function is fired
2013-09-26 08:32:39 +00:00
* when the URL is accessed . They do not appear in menus .
2004-06-18 15:04:37 +00:00
*/
2011-11-29 09:56:53 +00:00
const MENU_CALLBACK = 0x0000 ;
2002-12-24 15:40:32 +00:00
2004-06-18 15:04:37 +00:00
/**
2008-05-26 17:12:55 +00:00
* Menu type -- A normal menu item , hidden until enabled by an administrator .
*
2004-07-10 18:10:36 +00:00
* Modules may " suggest " menu items that the administrator may enable . They act
* just as callbacks do until enabled , at which time they act like normal items .
2007-11-24 20:59:32 +00:00
* Note for the value : 0x0010 was a flag which is no longer used , but this way
* the values of MENU_CALLBACK and MENU_SUGGESTED_ITEM are separate .
2004-06-18 15:04:37 +00:00
*/
2014-03-01 04:58:58 +00:00
define ( 'MENU_SUGGESTED_ITEM' , 0x0010 );
2013-05-28 01:20:55 +00:00
2004-06-18 15:04:37 +00:00
/**
2012-05-17 12:58:49 +00:00
* @ } End of " defgroup menu_item_types " .
2004-07-10 15:51:48 +00:00
*/
/**
2010-10-08 05:07:53 +00:00
* @ defgroup menu_status_codes Menu status codes
2004-07-10 15:51:48 +00:00
* @ {
2004-06-18 15:04:37 +00:00
* Status codes for menu callbacks .
*/
2004-09-09 05:51:08 +00:00
2008-05-26 17:12:55 +00:00
/**
* Internal menu status code -- Menu item inaccessible because site is offline .
*/
2011-11-29 09:56:53 +00:00
const MENU_SITE_OFFLINE = 4 ;
2004-09-09 05:51:08 +00:00
2010-07-07 08:05:01 +00:00
/**
* Internal menu status code -- Everything is working fine .
*/
2011-11-29 09:56:53 +00:00
const MENU_SITE_ONLINE = 5 ;
2010-07-07 08:05:01 +00:00
2004-07-10 15:51:48 +00:00
/**
2012-05-17 12:58:49 +00:00
* @ } End of " defgroup menu_status_codes " .
2004-07-10 15:51:48 +00:00
*/
2004-04-15 20:49:42 +00:00
2007-04-06 04:39:51 +00:00
/**
2010-10-08 05:07:53 +00:00
* @ defgroup menu_tree_parameters Menu tree parameters
2007-04-06 04:39:51 +00:00
* @ {
2011-01-03 18:03:54 +00:00
* Parameters for a menu tree .
2007-04-06 04:39:51 +00:00
*/
/**
2007-05-16 13:45:17 +00:00
* The maximum depth of a menu links tree - matches the number of p columns .
2013-02-08 23:55:25 +00:00
*
* @ todo Move this constant to MenuLinkStorageController along with all the tree
* functionality .
2007-04-06 04:39:51 +00:00
*/
2011-11-29 09:56:53 +00:00
const MENU_MAX_DEPTH = 9 ;
2007-05-16 13:45:17 +00:00
2007-04-06 04:39:51 +00:00
/**
2012-05-17 12:58:49 +00:00
* @ } End of " defgroup menu_tree_parameters " .
2007-02-11 09:30:51 +00:00
*/
2011-12-06 12:18:12 +00:00
/**
* Reserved key to identify the most specific menu link for a given path .
*
* The value of this constant is a hash of the constant name . We use the hash
* so that the reserved key is over 32 characters in length and will not
* collide with allowed menu names :
* @ code
* sha1 ( 'MENU_PREFERRED_LINK' ) = 1 cf698d64d1aa4b83907cf6ed55db3a7f8e92c91
* @ endcode
*
* @ see menu_link_get_preferred ()
*/
const MENU_PREFERRED_LINK = '1cf698d64d1aa4b83907cf6ed55db3a7f8e92c91' ;
2004-04-15 20:49:42 +00:00
/**
2014-03-01 04:58:58 +00:00
* Localizes a menu link title using t () if possible .
2008-01-28 19:09:19 +00:00
*
2008-01-10 20:04:19 +00:00
* Translate the title and description to allow storage of English title
* strings in the database , yet display of them in the language required
* by the current user .
*
* @ param $item
2014-03-01 04:58:58 +00:00
* A menu link entity .
*/
function _menu_item_localize ( & $item ) {
2014-02-26 10:53:29 +00:00
// Allow default menu links to be translated.
2008-02-04 12:07:23 +00:00
$item [ 'localized_options' ] = $item [ 'options' ];
2009-09-18 10:54:20 +00:00
// All 'class' attributes are assumed to be an array during rendering, but
// links stored in the database may use an old string value.
// @todo In order to remove this code we need to implement a database update
// including unserializing all existing link options and running this code
// on them, as well as adding validation to menu_link_save().
if ( isset ( $item [ 'options' ][ 'attributes' ][ 'class' ]) && is_string ( $item [ 'options' ][ 'attributes' ][ 'class' ])) {
$item [ 'localized_options' ][ 'attributes' ][ 'class' ] = explode ( ' ' , $item [ 'options' ][ 'attributes' ][ 'class' ]);
}
2014-03-01 04:58:58 +00:00
// If the menu link is defined in code and not customized, we can use t().
if ( ! empty ( $item [ 'machine_name' ]) && ! $item [ 'customized' ]) {
// @todo Figure out a proper way to support translations of menu links, see
// https://drupal.org/node/2193777.
$item [ 'title' ] = t ( $item [ 'link_title' ]);
2013-05-02 04:09:48 +00:00
}
else {
2014-03-01 04:58:58 +00:00
$item [ 'title' ] = $item [ 'link_title' ];
2007-05-16 13:45:17 +00:00
}
}
/**
2014-01-29 08:25:00 +00:00
* Provides menu link unserializing , access control , and argument handling .
2012-08-31 15:56:36 +00:00
*
2014-01-29 08:25:00 +00:00
* @ param array $item
* The passed in item has the following keys :
* - access : ( optional ) Becomes TRUE if the item is accessible , FALSE
* otherwise . If the key is not set , the access manager is used to
* determine the access .
* - options : ( required ) Is unserialized and copied to $item [ 'localized_options' ] .
* - link_title : ( required ) The title of the menu link .
* - route_name : ( required ) The route name of the menu link .
* - route_parameters : ( required ) The unserialized route parameters of the menu link .
* The passed in item is changed by the following keys :
* - href : The actual path to the link . This path is generated from the
* link_path of the menu link entity .
* - title : The title of the link . This title is generated from the
* link_title of the menu link entity .
*/
function _menu_link_translate ( & $item ) {
2010-09-24 00:37:45 +00:00
if ( ! is_array ( $item [ 'options' ])) {
2014-01-29 08:25:00 +00:00
$item [ 'options' ] = ( array ) unserialize ( $item [ 'options' ]);
2010-09-24 00:37:45 +00:00
}
2014-01-29 08:25:00 +00:00
$item [ 'localized_options' ] = $item [ 'options' ];
$item [ 'title' ] = $item [ 'link_title' ];
if ( $item [ 'external' ] || empty ( $item [ 'route_name' ])) {
2007-05-27 20:31:13 +00:00
$item [ 'access' ] = 1 ;
$item [ 'href' ] = $item [ 'link_path' ];
2014-01-29 08:25:00 +00:00
$item [ 'route_parameters' ] = array ();
// Set to NULL so that drupal_pre_render_link() is certain to skip it.
$item [ 'route_name' ] = NULL ;
2007-05-16 13:45:17 +00:00
}
else {
2014-01-29 08:25:00 +00:00
$item [ 'href' ] = NULL ;
if ( ! is_array ( $item [ 'route_parameters' ])) {
$item [ 'route_parameters' ] = ( array ) unserialize ( $item [ 'route_parameters' ]);
2007-05-16 13:45:17 +00:00
}
2007-07-04 15:49:44 +00:00
// menu_tree_check_access() may set this ahead of time for links to nodes.
2007-05-27 20:31:13 +00:00
if ( ! isset ( $item [ 'access' ])) {
2014-01-29 08:25:00 +00:00
$item [ 'access' ] = \Drupal :: getContainer () -> get ( 'access_manager' ) -> checkNamedRoute ( $item [ 'route_name' ], $item [ 'route_parameters' ], \Drupal :: currentUser ());
2007-05-16 13:45:17 +00:00
}
2008-06-12 20:49:39 +00:00
// For performance, don't localize a link the user can't access.
if ( $item [ 'access' ]) {
2014-03-01 04:58:58 +00:00
_menu_item_localize ( $item );
2008-06-12 20:49:39 +00:00
}
2007-05-16 13:45:17 +00:00
}
2008-02-06 19:52:54 +00:00
2008-02-06 19:41:24 +00:00
// Allow other customizations - e.g. adding a page-specific query string to the
// options array. For performance reasons we only invoke this hook if the link
// has the 'alter' flag set in the options array.
if ( ! empty ( $item [ 'options' ][ 'alter' ])) {
2014-02-24 10:10:52 +00:00
\Drupal :: moduleHandler () -> alter ( 'translated_menu_link' , $item , $map );
2008-02-06 19:41:24 +00:00
}
2003-09-26 10:04:09 +00:00
}
2007-05-16 13:45:17 +00:00
/**
2010-08-05 07:56:50 +00:00
* Renders a menu tree based on the current path .
2007-07-16 12:51:03 +00:00
*
2007-05-16 13:45:17 +00:00
* @ param $menu_name
* The name of the menu .
2010-03-26 17:14:46 +00:00
*
2007-05-16 13:45:17 +00:00
* @ return
2010-08-05 07:56:50 +00:00
* A structured array representing the specified menu on the current page , to
* be rendered by drupal_render () .
2007-05-16 13:45:17 +00:00
*/
2009-03-20 19:18:11 +00:00
function menu_tree ( $menu_name ) {
2009-04-25 15:19:12 +00:00
$menu_output = & drupal_static ( __FUNCTION__ , array ());
2007-05-16 13:45:17 +00:00
if ( ! isset ( $menu_output [ $menu_name ])) {
2007-05-27 20:31:13 +00:00
$tree = menu_tree_page_data ( $menu_name );
2007-05-16 13:45:17 +00:00
$menu_output [ $menu_name ] = menu_tree_output ( $tree );
}
return $menu_output [ $menu_name ];
}
2003-09-28 11:08:17 +00:00
/**
2014-03-11 08:30:10 +00:00
* Returns an output structure for rendering a menu tree .
2007-05-16 13:45:17 +00:00
*
2009-09-18 10:54:20 +00:00
* The menu item ' s LI element is given one of the following classes :
* - expanded : The menu item is showing its submenu .
* - collapsed : The menu item has a submenu which is not shown .
* - leaf : The menu item has no submenu .
*
2007-05-16 13:45:17 +00:00
* @ param $tree
* A data structure representing the tree as returned from menu_tree_data .
2010-03-26 17:14:46 +00:00
*
2007-05-16 13:45:17 +00:00
* @ return
2009-09-18 10:54:20 +00:00
* A structured array to be rendered by drupal_render () .
2003-09-28 11:08:17 +00:00
*/
2007-05-16 13:45:17 +00:00
function menu_tree_output ( $tree ) {
2009-09-18 10:54:20 +00:00
$build = array ();
2007-10-08 15:01:05 +00:00
$items = array ();
2007-05-16 13:45:17 +00:00
2009-09-18 10:54:20 +00:00
// Pull out just the menu links we are going to render so that we
2007-10-08 14:15:09 +00:00
// get an accurate count for the first/last classes.
2007-05-16 13:45:17 +00:00
foreach ( $tree as $data ) {
2010-09-24 00:37:45 +00:00
if ( $data [ 'link' ][ 'access' ] && ! $data [ 'link' ][ 'hidden' ]) {
2007-10-08 14:15:09 +00:00
$items [] = $data ;
}
}
2007-10-12 14:10:18 +00:00
Issue #1649780 by effulgentsia, jibran, Wim Leers, nod_, hefox, joelpittet, kaare, BarisW, sun, rbayliss, Cottser, fubhy: Remove first/last/odd/even classes in favor of CSS3 pseudo selectors.
2014-01-15 10:56:55 +00:00
foreach ( $items as $data ) {
2009-09-18 10:54:20 +00:00
$class = array ();
2010-07-19 21:57:49 +00:00
// Set a class for the <li>-tag. Since $data['below'] may contain local
// tasks, only set 'expanded' class if the link also has children within
// the current menu.
if ( $data [ 'link' ][ 'has_children' ] && $data [ 'below' ]) {
2009-09-18 10:54:20 +00:00
$class [] = 'expanded' ;
}
elseif ( $data [ 'link' ][ 'has_children' ]) {
$class [] = 'collapsed' ;
2007-10-08 14:15:09 +00:00
}
else {
2009-09-18 10:54:20 +00:00
$class [] = 'leaf' ;
2007-04-15 14:38:16 +00:00
}
2009-09-18 10:54:20 +00:00
// Set a class if the link is in the active trail.
if ( $data [ 'link' ][ 'in_active_trail' ]) {
$class [] = 'active-trail' ;
2010-09-24 00:37:45 +00:00
$data [ 'link' ][ 'localized_options' ][ 'attributes' ][ 'class' ][] = 'active-trail' ;
}
2009-09-18 10:54:20 +00:00
2010-01-08 07:30:34 +00:00
// Allow menu-specific theme overrides.
2011-05-18 00:12:11 +00:00
$element [ '#theme' ] = 'menu_link__' . strtr ( $data [ 'link' ][ 'menu_name' ], '-' , '_' );
2009-09-18 10:54:20 +00:00
$element [ '#attributes' ][ 'class' ] = $class ;
$element [ '#title' ] = $data [ 'link' ][ 'title' ];
2014-01-29 08:25:00 +00:00
// @todo Use route name and parameters to generate the link path, unless
// it is external.
$element [ '#href' ] = $data [ 'link' ][ 'link_path' ];
2009-12-08 07:09:43 +00:00
$element [ '#localized_options' ] = ! empty ( $data [ 'link' ][ 'localized_options' ]) ? $data [ 'link' ][ 'localized_options' ] : array ();
2009-09-18 10:54:20 +00:00
$element [ '#below' ] = $data [ 'below' ] ? menu_tree_output ( $data [ 'below' ]) : $data [ 'below' ];
$element [ '#original_link' ] = $data [ 'link' ];
// Index using the link's unique mlid.
$build [ $data [ 'link' ][ 'mlid' ]] = $element ;
2007-05-16 13:45:17 +00:00
}
2009-09-18 10:54:20 +00:00
if ( $build ) {
// Make sure drupal_render() does not re-order the links.
$build [ '#sorted' ] = TRUE ;
// Add the theme wrapper for outer markup.
2010-01-08 07:30:34 +00:00
// Allow menu-specific theme overrides.
2010-09-01 02:59:04 +00:00
$build [ '#theme_wrappers' ][] = 'menu_tree__' . strtr ( $data [ 'link' ][ 'menu_name' ], '-' , '_' );
2014-02-18 13:37:58 +00:00
// Set cache tag.
$menu_name = $data [ 'link' ][ 'menu_name' ];
$build [ '#cache' ][ 'tags' ][ 'menu' ][ $menu_name ] = $menu_name ;
2009-09-18 10:54:20 +00:00
}
return $build ;
2007-05-16 13:45:17 +00:00
}
2007-05-27 20:31:13 +00:00
/**
2012-08-31 15:56:36 +00:00
* Gets the data structure representing a named menu tree .
2007-07-16 12:51:03 +00:00
*
* Since this can be the full tree including hidden items , the data returned
* may be used for generating an an admin interface or a select .
2007-05-27 20:31:13 +00:00
*
* @ param $menu_name
* The named menu links to return
2009-08-24 01:49:41 +00:00
* @ param $link
2008-12-20 18:24:41 +00:00
* A fully loaded menu link , or NULL . If a link is supplied , only the
2009-08-24 01:49:41 +00:00
* path to root will be included in the returned tree - as if this link
2007-05-27 20:31:13 +00:00
* represented the current page in a visible menu .
2009-08-24 01:49:41 +00:00
* @ param $max_depth
* Optional maximum depth of links to retrieve . Typically useful if only one
* or two levels of a sub tree are needed in conjunction with a non - NULL
* $link , in which case $max_depth should be greater than $link [ 'depth' ] .
*
2007-05-27 20:31:13 +00:00
* @ return
* An tree of menu links in an array , in the order they should be rendered .
*/
2009-08-24 01:49:41 +00:00
function menu_tree_all_data ( $menu_name , $link = NULL , $max_depth = NULL ) {
2009-04-25 15:19:12 +00:00
$tree = & drupal_static ( __FUNCTION__ , array ());
2014-02-26 19:16:54 +00:00
$language_interface = \Drupal :: languageManager () -> getCurrentLanguage ();
2012-04-18 18:30:50 +00:00
2007-07-04 15:49:44 +00:00
// Use $mlid as a flag for whether the data being loaded is for the whole tree.
2009-08-24 01:49:41 +00:00
$mlid = isset ( $link [ 'mlid' ]) ? $link [ 'mlid' ] : 0 ;
2009-10-16 19:06:25 +00:00
// Generate a cache ID (cid) specific for this $menu_name, $link, $language, and depth.
2013-06-29 10:56:53 +00:00
$cid = 'links:' . $menu_name . ':all:' . $mlid . ':' . $language_interface -> id . ':' . ( int ) $max_depth ;
2007-05-27 20:31:13 +00:00
if ( ! isset ( $tree [ $cid ])) {
2014-03-26 13:19:28 +00:00
// If the static variable doesn't have the data, check {cache_data}.
$cache = \Drupal :: cache ( 'data' ) -> get ( $cid );
2007-05-27 20:31:13 +00:00
if ( $cache && isset ( $cache -> data )) {
2010-07-02 02:22:26 +00:00
// If the cache entry exists, it contains the parameters for
// menu_build_tree().
$tree_parameters = $cache -> data ;
2007-05-27 20:31:13 +00:00
}
2010-07-02 02:22:26 +00:00
// If the tree data was not in the cache, build $tree_parameters.
if ( ! isset ( $tree_parameters )) {
$tree_parameters = array (
'min_depth' => 1 ,
'max_depth' => $max_depth ,
);
2007-05-27 20:31:13 +00:00
if ( $mlid ) {
2007-07-04 15:49:44 +00:00
// The tree is for a single item, so we need to match the values in its
// p columns and 0 (the top level) with the plid values of other links.
2010-07-02 02:22:26 +00:00
$parents = array ( 0 );
2007-08-11 14:06:15 +00:00
for ( $i = 1 ; $i < MENU_MAX_DEPTH ; $i ++ ) {
2010-07-02 02:22:26 +00:00
if ( ! empty ( $link [ " p $i " ])) {
$parents [] = $link [ " p $i " ];
}
2007-08-11 14:06:15 +00:00
}
2010-07-02 02:22:26 +00:00
$tree_parameters [ 'expanded' ] = $parents ;
$tree_parameters [ 'active_trail' ] = $parents ;
$tree_parameters [ 'active_trail' ][] = $mlid ;
2008-03-14 08:51:37 +00:00
}
2010-07-02 02:22:26 +00:00
// Cache the tree building parameters using the page-specific cid.
2014-03-26 13:19:28 +00:00
\Drupal :: cache ( 'data' ) -> set ( $cid , $tree_parameters , Cache :: PERMANENT , array ( 'menu' => $menu_name ));
2007-05-27 20:31:13 +00:00
}
2010-07-02 02:22:26 +00:00
// Build the tree using the parameters; the resulting tree will be cached
// by _menu_build_tree()).
$tree [ $cid ] = menu_build_tree ( $menu_name , $tree_parameters );
2007-05-27 20:31:13 +00:00
}
return $tree [ $cid ];
}
2011-09-27 16:33:35 +00:00
/**
2012-08-31 15:56:36 +00:00
* Sets the path for determining the active trail of the specified menu tree .
2011-09-27 16:33:35 +00:00
*
* This path will also affect the breadcrumbs under some circumstances .
* Breadcrumbs are built using the preferred link returned by
* menu_link_get_preferred () . If the preferred link is inside one of the menus
* specified in calls to menu_tree_set_path (), the preferred link will be
* overridden by the corresponding path returned by menu_tree_get_path () .
*
* Setting this path does not affect the main content ; for that use
* menu_set_active_item () instead .
*
* @ param $menu_name
* The name of the affected menu tree .
* @ param $path
* The path to use when finding the active trail .
*/
function menu_tree_set_path ( $menu_name , $path = NULL ) {
$paths = & drupal_static ( __FUNCTION__ );
if ( isset ( $path )) {
$paths [ $menu_name ] = $path ;
}
return isset ( $paths [ $menu_name ]) ? $paths [ $menu_name ] : NULL ;
}
/**
2012-08-31 15:56:36 +00:00
* Gets the path for determining the active trail of the specified menu tree .
2011-09-27 16:33:35 +00:00
*
* @ param $menu_name
* The menu name of the requested tree .
*
* @ return
* A string containing the path . If no path has been specified with
* menu_tree_set_path (), NULL is returned .
*/
function menu_tree_get_path ( $menu_name ) {
return menu_tree_set_path ( $menu_name );
}
2007-05-16 13:45:17 +00:00
/**
2012-08-31 15:56:36 +00:00
* Gets the data structure for a named menu tree , based on the current page .
2007-07-16 12:51:03 +00:00
*
* The tree order is maintained by storing each parent in an individual
2007-05-16 13:45:17 +00:00
* field , see http :// drupal . org / node / 141866 for more .
*
* @ param $menu_name
2010-09-24 00:37:45 +00:00
* The named menu links to return .
2009-08-24 01:49:41 +00:00
* @ param $max_depth
2010-09-24 00:37:45 +00:00
* ( optional ) The maximum depth of links to retrieve .
* @ 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
2013-09-26 08:32:39 +00:00
* to FALSE .
2009-08-24 01:49:41 +00:00
*
2007-05-16 13:45:17 +00:00
* @ return
* An array of menu links , in the order they should be rendered . The array
* is a list of associative arrays -- these have two keys , link and below .
* link is a menu item , ready for theming as a link . Below represents the
2007-07-04 21:33:55 +00:00
* submenu below the link if there is one , and it is a subtree that has the
* same structure described for the top - level array .
2007-05-16 13:45:17 +00:00
*/
2010-09-24 00:37:45 +00:00
function menu_tree_page_data ( $menu_name , $max_depth = NULL , $only_active_trail = FALSE ) {
2009-04-25 15:19:12 +00:00
$tree = & drupal_static ( __FUNCTION__ , array ());
2007-05-16 13:45:17 +00:00
2014-02-26 19:16:54 +00:00
$language_interface = \Drupal :: languageManager () -> getCurrentLanguage ();
2012-04-18 18:30:50 +00:00
2011-09-27 16:33:35 +00:00
// Check if the active trail has been overridden for this menu tree.
$active_path = menu_tree_get_path ( $menu_name );
2014-03-01 04:58:58 +00:00
// Load the request corresponding to the current page.
2013-09-06 20:53:28 +00:00
$request = \Drupal :: request ();
$system_path = NULL ;
2013-09-09 10:10:33 +00:00
if ( $route_name = $request -> attributes -> get ( RouteObjectInterface :: ROUTE_NAME )) {
// @todo https://drupal.org/node/2068471 is adding support so we can tell
// if this is called on a 404/403 page.
$system_path = $request -> attributes -> get ( '_system_path' );
$page_not_403 = 1 ;
}
2013-09-06 20:53:28 +00:00
if ( isset ( $system_path )) {
2009-08-24 01:49:41 +00:00
if ( isset ( $max_depth )) {
$max_depth = min ( $max_depth , MENU_MAX_DEPTH );
}
2008-03-14 08:51:37 +00:00
// Generate a cache ID (cid) specific for this page.
2013-09-06 20:53:28 +00:00
$cid = 'links:' . $menu_name . ':page:' . $system_path . ':' . $language_interface -> id . ':' . $page_not_403 . ':' . ( int ) $max_depth ;
2010-09-24 00:37:45 +00:00
// If we are asked for the active trail only, and $menu_name has not been
// built and cached for this page yet, then this likely means that it
// won't be built anymore, as this function is invoked from
2013-07-19 18:15:13 +00:00
// template_preprocess_page(). So in order to not build a giant menu tree
2010-09-24 00:37:45 +00:00
// 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
2013-09-26 08:32:39 +00:00
// tree containing the active trail only.
2010-09-24 00:37:45 +00:00
// @see menu_set_active_trail()
if ( ! isset ( $tree [ $cid ]) && $only_active_trail ) {
$cid .= ':trail' ;
}
2007-05-16 13:45:17 +00:00
2007-05-27 20:31:13 +00:00
if ( ! isset ( $tree [ $cid ])) {
2014-03-26 13:19:28 +00:00
// If the static variable doesn't have the data, check {cache_data}.
$cache = \Drupal :: cache ( 'data' ) -> get ( $cid );
2007-05-27 20:31:13 +00:00
if ( $cache && isset ( $cache -> data )) {
2010-07-02 02:22:26 +00:00
// If the cache entry exists, it contains the parameters for
// menu_build_tree().
$tree_parameters = $cache -> data ;
2007-05-16 13:45:17 +00:00
}
2010-07-02 02:22:26 +00:00
// If the tree data was not in the cache, build $tree_parameters.
if ( ! isset ( $tree_parameters )) {
$tree_parameters = array (
'min_depth' => 1 ,
'max_depth' => $max_depth ,
);
2010-09-24 00:37:45 +00:00
// Parent mlids; used both as key and value to ensure uniqueness.
// We always want all the top-level links with plid == 0.
$active_trail = array ( 0 => 0 );
2013-09-06 20:53:28 +00:00
// If this page is accessible to the current user, build the tree
2010-07-02 02:22:26 +00:00
// parameters accordingly.
2013-09-06 20:53:28 +00:00
if ( $page_not_403 ) {
2011-09-27 16:33:35 +00:00
// Find a menu link corresponding to the current path. If $active_path
// is NULL, let menu_link_get_preferred() determine the path.
2011-12-06 12:18:12 +00:00
if ( $active_link = menu_link_get_preferred ( $active_path , $menu_name )) {
2010-09-24 00:37:45 +00:00
// The active link may only be taken into account to build the
// active trail, if it resides in the requested menu. Otherwise,
// we'd needlessly re-run _menu_build_tree() queries for every menu
// on every page.
if ( $active_link [ 'menu_name' ] == $menu_name ) {
// Use all the coordinates, except the last one because there
// can be no child beyond the last column.
for ( $i = 1 ; $i < MENU_MAX_DEPTH ; $i ++ ) {
if ( $active_link [ 'p' . $i ]) {
$active_trail [ $active_link [ 'p' . $i ]] = $active_link [ 'p' . $i ];
}
}
// If we are asked to build links for the active trail only, skip
// the entire 'expanded' handling.
if ( $only_active_trail ) {
$tree_parameters [ 'only_active_trail' ] = TRUE ;
}
}
2007-05-27 20:31:13 +00:00
}
2010-09-24 00:37:45 +00:00
$parents = $active_trail ;
2007-05-27 20:31:13 +00:00
2013-09-16 03:58:06 +00:00
$expanded = \Drupal :: state () -> get ( 'menu_expanded' );
2007-07-04 15:49:44 +00:00
// Check whether the current menu has any links set to be expanded.
2012-11-02 17:23:40 +00:00
if ( ! $only_active_trail && $expanded && in_array ( $menu_name , $expanded )) {
2007-07-04 21:33:55 +00:00
// Collect all the links set to be expanded, and then add all of
// their children to the list as well.
2007-05-27 20:31:13 +00:00
do {
2013-09-16 03:58:06 +00:00
$query = \Drupal :: entityQuery ( 'menu_link' )
2008-12-03 14:38:59 +00:00
-> condition ( 'menu_name' , $menu_name )
-> condition ( 'expanded' , 1 )
-> condition ( 'has_children' , 1 )
2010-07-02 02:22:26 +00:00
-> condition ( 'plid' , $parents , 'IN' )
2013-02-08 23:55:25 +00:00
-> condition ( 'mlid' , $parents , 'NOT IN' );
$result = $query -> execute ();
$parents += $result ;
} while ( ! empty ( $result ));
2007-05-27 20:31:13 +00:00
}
2010-07-02 02:22:26 +00:00
$tree_parameters [ 'expanded' ] = $parents ;
2010-09-24 00:37:45 +00:00
$tree_parameters [ 'active_trail' ] = $active_trail ;
2007-05-27 20:31:13 +00:00
}
2010-09-24 00:37:45 +00:00
// If access is denied, we only show top-level links in menus.
2007-05-27 20:31:13 +00:00
else {
2010-09-24 00:37:45 +00:00
$tree_parameters [ 'expanded' ] = $active_trail ;
$tree_parameters [ 'active_trail' ] = $active_trail ;
2008-03-14 08:51:37 +00:00
}
2010-07-02 02:22:26 +00:00
// Cache the tree building parameters using the page-specific cid.
2014-03-26 13:19:28 +00:00
\Drupal :: cache ( 'data' ) -> set ( $cid , $tree_parameters , Cache :: PERMANENT , array ( 'menu' => $menu_name ));
2007-05-16 13:45:17 +00:00
}
2010-07-02 02:22:26 +00:00
// Build the tree using the parameters; the resulting tree will be cached
// by _menu_build_tree().
$tree [ $cid ] = menu_build_tree ( $menu_name , $tree_parameters );
2007-04-15 14:38:16 +00:00
}
2007-05-27 20:31:13 +00:00
return $tree [ $cid ];
2007-02-11 09:30:51 +00:00
}
2007-05-27 20:31:13 +00:00
return array ();
2003-12-16 21:06:34 +00:00
}
2008-03-14 08:51:37 +00:00
/**
2012-08-31 15:56:36 +00:00
* Builds a menu tree , translates links , and checks access .
2010-07-02 02:22:26 +00:00
*
* @ param $menu_name
* The name of the menu .
* @ param $parameters
* ( optional ) An associative array of build parameters . Possible keys :
* - expanded : An array of parent link ids to return only menu links that are
* children of one of the plids in this list . If empty , the whole menu tree
2010-09-24 00:37:45 +00:00
* is built , unless 'only_active_trail' is TRUE .
2010-07-02 02:22:26 +00:00
* - active_trail : An array of mlids , representing the coordinates of the
* currently active menu link .
2010-09-24 00:37:45 +00:00
* - only_active_trail : Whether to only return links that are in the active
2013-09-26 08:32:39 +00:00
* trail . This option is ignored , if 'expanded' is non - empty .
2010-07-02 02:22:26 +00:00
* - min_depth : The minimum depth of menu links in the resulting tree .
2012-08-31 15:56:36 +00:00
* Defaults to 1 , which is the default to build a whole tree for a menu
* ( excluding menu container itself ) .
2010-07-02 02:22:26 +00:00
* - max_depth : The maximum depth of menu links in the resulting tree .
2011-12-14 03:17:05 +00:00
* - conditions : An associative array of custom database select query
* condition key / value pairs ; see _menu_build_tree () for the actual query .
2010-07-02 02:22:26 +00:00
*
* @ return
* A fully built menu tree .
2008-03-14 08:51:37 +00:00
*/
2010-07-02 02:22:26 +00:00
function menu_build_tree ( $menu_name , array $parameters = array ()) {
// Build the menu tree.
$data = _menu_build_tree ( $menu_name , $parameters );
// Check access for the current user to each item in the tree.
menu_tree_check_access ( $data [ 'tree' ], $data [ 'node_links' ]);
return $data [ 'tree' ];
}
/**
2012-08-31 15:56:36 +00:00
* Builds a menu tree .
2010-07-02 02:22:26 +00:00
*
* This function may be used build the data for a menu tree only , for example
* to further massage the data manually before further processing happens .
* menu_tree_check_access () needs to be invoked afterwards .
*
* @ see menu_build_tree ()
*/
function _menu_build_tree ( $menu_name , array $parameters = array ()) {
// Static cache of already built menu trees.
$trees = & drupal_static ( __FUNCTION__ , array ());
2014-02-26 19:16:54 +00:00
$language_interface = \Drupal :: languageManager () -> getCurrentLanguage ();
2012-04-18 18:30:50 +00:00
2010-07-02 02:22:26 +00:00
// Build the cache id; sort parents to prevent duplicate storage and remove
// default parameter values.
if ( isset ( $parameters [ 'expanded' ])) {
sort ( $parameters [ 'expanded' ]);
}
2013-06-29 10:56:53 +00:00
$tree_cid = 'links:' . $menu_name . ':tree-data:' . $language_interface -> id . ':' . hash ( 'sha256' , serialize ( $parameters ));
2010-07-02 02:22:26 +00:00
2014-03-26 13:19:28 +00:00
// If we do not have this tree in the static cache, check {cache_data}.
2010-07-02 02:22:26 +00:00
if ( ! isset ( $trees [ $tree_cid ])) {
2014-03-26 13:19:28 +00:00
$cache = \Drupal :: cache ( 'data' ) -> get ( $tree_cid );
2010-07-02 02:22:26 +00:00
if ( $cache && isset ( $cache -> data )) {
$trees [ $tree_cid ] = $cache -> data ;
}
}
if ( ! isset ( $trees [ $tree_cid ])) {
2013-09-16 03:58:06 +00:00
$query = \Drupal :: entityQuery ( 'menu_link' );
2010-07-02 02:22:26 +00:00
for ( $i = 1 ; $i <= MENU_MAX_DEPTH ; $i ++ ) {
2013-02-08 23:55:25 +00:00
$query -> sort ( 'p' . $i , 'ASC' );
2010-07-02 02:22:26 +00:00
}
2013-02-08 23:55:25 +00:00
$query -> condition ( 'menu_name' , $menu_name );
2010-07-02 02:22:26 +00:00
if ( ! empty ( $parameters [ 'expanded' ])) {
2013-02-08 23:55:25 +00:00
$query -> condition ( 'plid' , $parameters [ 'expanded' ], 'IN' );
2010-07-02 02:22:26 +00:00
}
2010-09-24 00:37:45 +00:00
elseif ( ! empty ( $parameters [ 'only_active_trail' ])) {
2013-02-08 23:55:25 +00:00
$query -> condition ( 'mlid' , $parameters [ 'active_trail' ], 'IN' );
2010-09-24 00:37:45 +00:00
}
2010-07-02 02:22:26 +00:00
$min_depth = ( isset ( $parameters [ 'min_depth' ]) ? $parameters [ 'min_depth' ] : 1 );
if ( $min_depth != 1 ) {
2013-02-08 23:55:25 +00:00
$query -> condition ( 'depth' , $min_depth , '>=' );
2010-07-02 02:22:26 +00:00
}
if ( isset ( $parameters [ 'max_depth' ])) {
2013-02-08 23:55:25 +00:00
$query -> condition ( 'depth' , $parameters [ 'max_depth' ], '<=' );
2010-07-02 02:22:26 +00:00
}
2011-12-14 03:17:05 +00:00
// Add custom query conditions, if any were passed.
if ( isset ( $parameters [ 'conditions' ])) {
foreach ( $parameters [ 'conditions' ] as $column => $value ) {
$query -> condition ( $column , $value );
}
}
2010-07-02 02:22:26 +00:00
// Build an ordered array of links using the query result object.
$links = array ();
2013-02-08 23:55:25 +00:00
if ( $result = $query -> execute ()) {
$links = menu_link_load_multiple ( $result );
2010-07-02 02:22:26 +00:00
}
2010-09-24 00:37:45 +00:00
$active_trail = ( isset ( $parameters [ 'active_trail' ]) ? $parameters [ 'active_trail' ] : array ());
$data [ 'tree' ] = menu_tree_data ( $links , $active_trail , $min_depth );
2010-07-02 02:22:26 +00:00
$data [ 'node_links' ] = array ();
menu_tree_collect_node_links ( $data [ 'tree' ], $data [ 'node_links' ]);
// Cache the data, if it is not already in the cache.
2014-03-26 13:19:28 +00:00
\Drupal :: cache ( 'data' ) -> set ( $tree_cid , $data , Cache :: PERMANENT , array ( 'menu' => $menu_name ));
2010-07-02 02:22:26 +00:00
$trees [ $tree_cid ] = $data ;
}
return $trees [ $tree_cid ];
2008-03-14 08:51:37 +00:00
}
2007-07-16 12:51:03 +00:00
/**
2012-08-31 15:56:36 +00:00
* Collects node links from a given menu tree recursively .
2009-03-21 17:58:14 +00:00
*
* @ param $tree
* The menu tree you wish to collect node links from .
* @ param $node_links
* An array in which to store the collected node links .
2007-07-16 12:51:03 +00:00
*/
function menu_tree_collect_node_links ( & $tree , & $node_links ) {
foreach ( $tree as $key => $v ) {
if ( $tree [ $key ][ 'link' ][ 'router_path' ] == 'node/%' ) {
$nid = substr ( $tree [ $key ][ 'link' ][ 'link_path' ], 5 );
if ( is_numeric ( $nid )) {
2007-10-01 09:53:03 +00:00
$node_links [ $nid ][ $tree [ $key ][ 'link' ][ 'mlid' ]] = & $tree [ $key ][ 'link' ];
2007-07-16 12:51:03 +00:00
$tree [ $key ][ 'link' ][ 'access' ] = FALSE ;
}
}
if ( $tree [ $key ][ 'below' ]) {
2007-07-17 06:13:34 +00:00
menu_tree_collect_node_links ( $tree [ $key ][ 'below' ], $node_links );
2007-07-16 12:51:03 +00:00
}
}
}
2007-07-04 15:49:44 +00:00
/**
2012-08-31 15:56:36 +00:00
* Checks access and performs dynamic operations for each link in the tree .
2009-03-21 17:58:14 +00:00
*
* @ param $tree
* The menu tree you wish to operate on .
* @ param $node_links
* A collection of node link references generated from $tree by
* menu_tree_collect_node_links () .
2007-07-04 15:49:44 +00:00
*/
2007-08-11 14:06:15 +00:00
function menu_tree_check_access ( & $tree , $node_links = array ()) {
2007-07-16 12:51:03 +00:00
if ( $node_links ) {
$nids = array_keys ( $node_links );
2013-05-26 20:18:10 +00:00
$select = db_select ( 'node_field_data' , 'n' );
2010-06-11 10:39:10 +00:00
$select -> addField ( 'n' , 'nid' );
2013-05-26 20:18:10 +00:00
// @todo This should be actually filtering on the desired node status field
// language and just fall back to the default language.
2010-06-16 05:07:16 +00:00
$select -> condition ( 'n.status' , 1 );
2013-05-26 20:18:10 +00:00
2010-06-11 10:39:10 +00:00
$select -> condition ( 'n.nid' , $nids , 'IN' );
2008-12-03 14:38:59 +00:00
$select -> addTag ( 'node_access' );
$nids = $select -> execute () -> fetchCol ();
foreach ( $nids as $nid ) {
2007-10-01 09:53:03 +00:00
foreach ( $node_links [ $nid ] as $mlid => $link ) {
$node_links [ $nid ][ $mlid ][ 'access' ] = TRUE ;
}
2007-07-16 12:51:03 +00:00
}
}
2007-08-11 14:06:15 +00:00
_menu_tree_check_access ( $tree );
2007-07-04 15:49:44 +00:00
}
/**
2012-08-31 15:56:36 +00:00
* Sorts the menu tree and recursively checks access for each item .
2007-07-04 15:49:44 +00:00
*/
2007-08-11 14:06:15 +00:00
function _menu_tree_check_access ( & $tree ) {
2007-07-16 12:51:03 +00:00
$new_tree = array ();
2007-05-27 20:31:13 +00:00
foreach ( $tree as $key => $v ) {
$item = & $tree [ $key ][ 'link' ];
2007-08-11 14:06:15 +00:00
_menu_link_translate ( $item );
2010-09-24 00:37:45 +00:00
if ( $item [ 'access' ] || ( $item [ 'in_active_trail' ] && strpos ( $item [ 'href' ], '%' ) !== FALSE )) {
2007-07-16 12:51:03 +00:00
if ( $tree [ $key ][ 'below' ]) {
2007-08-11 14:06:15 +00:00
_menu_tree_check_access ( $tree [ $key ][ 'below' ]);
2007-07-16 12:51:03 +00:00
}
// The weights are made a uniform 5 digits by adding 50000 as an offset.
// After _menu_link_translate(), $item['title'] has the localized link title.
// Adding the mlid to the end of the index insures that it is unique.
2008-04-14 17:48:46 +00:00
$new_tree [( 50000 + $item [ 'weight' ]) . ' ' . $item [ 'title' ] . ' ' . $item [ 'mlid' ]] = $tree [ $key ];
2007-05-27 20:31:13 +00:00
}
}
2007-07-16 12:51:03 +00:00
// Sort siblings in the tree based on the weights and localized titles.
ksort ( $new_tree );
$tree = $new_tree ;
2007-05-27 20:31:13 +00:00
}
2007-05-16 13:45:17 +00:00
2007-03-12 13:01:10 +00:00
/**
2012-08-31 15:56:36 +00:00
* Sorts and returns the built data representing a menu tree .
2007-03-12 13:01:10 +00:00
*
2009-08-24 01:49:41 +00:00
* @ param $links
2011-09-28 15:12:21 +00:00
* A flat array of menu links that are part of the menu . Each array element
* is an associative array of information about the menu link , containing the
* fields from the { menu_links } table , and optionally additional information
* from the { menu_router } table , if the menu item appears in both tables .
* This array must be ordered depth - first . See _menu_build_tree () for a sample
* query .
2007-05-16 13:45:17 +00:00
* @ param $parents
2011-09-28 15:12:21 +00:00
* An array of the menu link ID values that are in the path from the current
* page to the root of the menu tree .
2007-03-12 13:01:10 +00:00
* @ param $depth
2011-09-28 15:12:21 +00:00
* The minimum depth to include in the returned menu tree .
2010-03-26 17:14:46 +00:00
*
2007-03-12 13:01:10 +00:00
* @ return
2011-09-28 15:12:21 +00:00
* An array of menu links in the form of a tree . Each item in the tree is an
* associative array containing :
* - link : The menu link item from $links , with additional element
* 'in_active_trail' ( TRUE if the link ID was in $parents ) .
* - below : An array containing the sub - tree of this item , where each element
* is a tree item array with 'link' and 'below' elements . This array will be
* empty if the menu item has no items in its sub - tree having a depth
* greater than or equal to $depth .
2007-07-04 15:49:44 +00:00
*/
2009-08-24 01:49:41 +00:00
function menu_tree_data ( array $links , array $parents = array (), $depth = 1 ) {
// Reverse the array so we can use the more efficient array_pop() function.
$links = array_reverse ( $links );
return _menu_tree_data ( $links , $parents , $depth );
2007-07-04 15:49:44 +00:00
}
/**
2012-08-31 15:56:36 +00:00
* Builds the data representing a menu tree .
2007-07-04 15:49:44 +00:00
*
2009-08-24 01:49:41 +00:00
* The function is a bit complex because the rendering of a link depends on
* the next menu link .
2007-03-12 13:01:10 +00:00
*/
2009-08-24 01:49:41 +00:00
function _menu_tree_data ( & $links , $parents , $depth ) {
2007-05-16 13:45:17 +00:00
$tree = array ();
2009-09-11 01:28:34 +00:00
while ( $item = array_pop ( $links )) {
2007-05-16 13:45:17 +00:00
// We need to determine if we're on the path to root so we can later build
2013-09-26 08:32:39 +00:00
// the correct active trail.
2007-05-27 20:31:13 +00:00
$item [ 'in_active_trail' ] = in_array ( $item [ 'mlid' ], $parents );
2009-08-24 01:49:41 +00:00
// Add the current link to the tree.
$tree [ $item [ 'mlid' ]] = array (
'link' => $item ,
'below' => array (),
);
2009-09-11 01:28:34 +00:00
// Look ahead to the next link, but leave it on the array so it's available
// to other recursive function calls if we return or build a sub-tree.
$next = end ( $links );
2009-08-24 01:49:41 +00:00
// Check whether the next link is the first in a new sub-tree.
if ( $next && $next [ 'depth' ] > $depth ) {
// Recursively call _menu_tree_data to build the sub-tree.
$tree [ $item [ 'mlid' ]][ 'below' ] = _menu_tree_data ( $links , $parents , $next [ 'depth' ]);
2009-09-11 01:28:34 +00:00
// Fetch next link after filling the sub-tree.
$next = end ( $links );
2003-02-20 22:44:51 +00:00
}
2009-09-11 01:28:34 +00:00
// Determine if we should exit the loop and return.
if ( ! $next || $next [ 'depth' ] < $depth ) {
break ;
2004-07-10 15:51:48 +00:00
}
2002-12-24 15:40:32 +00:00
}
2009-08-24 01:49:41 +00:00
return $tree ;
2002-12-24 15:40:32 +00:00
}
2004-06-18 15:04:37 +00:00
/**
2012-10-05 18:12:56 +00:00
* Implements template_preprocess_HOOK () for theme_menu_tree () .
2004-06-18 15:04:37 +00:00
*/
2009-09-18 10:54:20 +00:00
function template_preprocess_menu_tree ( & $variables ) {
$variables [ 'tree' ] = $variables [ 'tree' ][ '#children' ];
2004-06-18 15:04:37 +00:00
}
2003-09-28 11:08:17 +00:00
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a wrapper for a menu sub - tree .
2007-12-06 09:58:34 +00:00
*
2009-10-09 01:00:08 +00:00
* @ param $variables
* An associative array containing :
2010-04-13 15:23:03 +00:00
* - tree : An HTML string containing the tree ' s items .
2009-10-09 01:00:08 +00:00
*
2010-04-13 15:23:03 +00:00
* @ see template_preprocess_menu_tree ()
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
2003-12-08 06:32:19 +00:00
*/
2009-10-09 01:00:08 +00:00
function theme_menu_tree ( $variables ) {
return '<ul class="menu">' . $variables [ 'tree' ] . '</ul>' ;
2007-03-12 13:01:10 +00:00
}
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a menu link and submenu .
2007-12-06 09:58:34 +00:00
*
2009-10-09 01:00:08 +00:00
* @ param $variables
* An associative array containing :
* - element : Structured array data for a menu link .
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
2009-09-18 10:54:20 +00:00
*/
2009-10-09 01:00:08 +00:00
function theme_menu_link ( array $variables ) {
$element = $variables [ 'element' ];
2009-09-18 10:54:20 +00:00
$sub_menu = '' ;
if ( $element [ '#below' ]) {
$sub_menu = drupal_render ( $element [ '#below' ]);
2007-05-27 20:31:13 +00:00
}
2014-01-23 18:04:41 +00:00
$element [ '#localized_options' ][ 'set_active_class' ] = TRUE ;
2009-09-18 10:54:20 +00:00
$output = l ( $element [ '#title' ], $element [ '#href' ], $element [ '#localized_options' ]);
2012-09-04 13:32:47 +00:00
return '<li' . new Attribute ( $element [ '#attributes' ]) . '>' . $output . $sub_menu . " </li> \n " ;
2007-02-11 09:30:51 +00:00
}
2007-07-04 15:49:44 +00:00
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a single local task link .
2007-12-06 09:58:34 +00:00
*
2009-10-09 01:00:08 +00:00
* @ param $variables
* An associative array containing :
2010-04-13 15:23:03 +00:00
* - element : A render element containing :
* - #link: A menu link array with 'title', 'href', and 'localized_options'
* keys .
* - #active: A boolean indicating whether the local task is active.
2009-09-18 10:54:20 +00:00
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
2007-07-04 15:49:44 +00:00
*/
2009-10-09 01:00:08 +00:00
function theme_menu_local_task ( $variables ) {
2009-10-11 06:05:53 +00:00
$link = $variables [ 'element' ][ '#link' ];
2013-02-18 17:03:05 +00:00
$link += array (
'localized_options' => array (),
);
2009-11-08 12:30:35 +00:00
$link_text = $link [ 'title' ];
if ( ! empty ( $variables [ 'element' ][ '#active' ])) {
// Add text to indicate active tab for non-visual users.
2013-06-17 19:58:27 +00:00
$active = '<span class="visually-hidden">' . t ( '(active tab)' ) . '</span>' ;
2009-11-08 12:30:35 +00:00
2013-10-07 05:34:09 +00:00
// If the link does not contain HTML already, String::checkPlain() it now.
2009-11-08 12:30:35 +00:00
// After we set 'html'=TRUE the link will not be sanitized by l().
if ( empty ( $link [ 'localized_options' ][ 'html' ])) {
2013-10-07 05:34:09 +00:00
$link [ 'title' ] = String :: checkPlain ( $link [ 'title' ]);
2009-11-08 12:30:35 +00:00
}
$link [ 'localized_options' ][ 'html' ] = TRUE ;
2010-05-04 20:29:57 +00:00
$link_text = t ( '!local-task-title!active' , array ( '!local-task-title' => $link [ 'title' ], '!active' => $active ));
2009-11-08 12:30:35 +00:00
}
2014-01-23 18:04:41 +00:00
$link [ 'localized_options' ][ 'set_active_class' ] = TRUE ;
2013-09-20 09:53:46 +00:00
if ( ! empty ( $link [ 'href' ])) {
// @todo - remove this once all pages are converted to routes.
$a_tag = l ( $link_text , $link [ 'href' ], $link [ 'localized_options' ]);
}
else {
2013-09-21 15:23:51 +00:00
$a_tag = \Drupal :: l ( $link_text , $link [ 'route_name' ], $link [ 'route_parameters' ], $link [ 'localized_options' ]);
2013-09-20 09:53:46 +00:00
}
2009-11-08 12:30:35 +00:00
2013-09-20 09:53:46 +00:00
return '<li' . ( ! empty ( $variables [ 'element' ][ '#active' ]) ? ' class="active"' : '' ) . '>' . $a_tag . '</li>' ;
2003-09-28 10:51:40 +00:00
}
2002-12-24 15:40:32 +00:00
2009-08-22 19:58:28 +00:00
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a single local action link .
2009-08-22 19:58:28 +00:00
*
2009-10-11 19:39:30 +00:00
* @ param $variables
2009-10-09 01:00:08 +00:00
* An associative array containing :
2010-04-13 15:23:03 +00:00
* - element : A render element containing :
* - #link: A menu link array with 'title', 'href', and 'localized_options'
* keys .
2009-09-18 10:54:20 +00:00
*
2009-08-22 19:58:28 +00:00
* @ ingroup themeable
*/
2009-10-09 01:00:08 +00:00
function theme_menu_local_action ( $variables ) {
2009-10-11 06:05:53 +00:00
$link = $variables [ 'element' ][ '#link' ];
2012-11-19 11:43:55 +00:00
$link += array (
'href' => '' ,
'localized_options' => array (),
2013-10-01 22:24:51 +00:00
'route_parameters' => array (),
2012-11-19 11:43:55 +00:00
);
$link [ 'localized_options' ][ 'attributes' ][ 'class' ][] = 'button' ;
2013-01-02 12:00:25 +00:00
$link [ 'localized_options' ][ 'attributes' ][ 'class' ][] = 'button-action' ;
2014-01-23 18:04:41 +00:00
$link [ 'localized_options' ][ 'set_active_class' ] = TRUE ;
2009-12-03 20:21:50 +00:00
$output = '<li>' ;
2013-10-01 22:24:51 +00:00
// @todo Remove this check and the call to l() when all pages are converted to
// routes.
// @todo Figure out how to support local actions without a href properly.
if ( $link [ 'href' ] === '' && ! empty ( $link [ 'route_name' ])) {
$output .= Drupal :: l ( $link [ 'title' ], $link [ 'route_name' ], $link [ 'route_parameters' ], $link [ 'localized_options' ]);
}
else {
$output .= l ( $link [ 'title' ], $link [ 'href' ], $link [ 'localized_options' ]);
}
2012-11-19 11:43:55 +00:00
$output .= " </li> " ;
2009-12-03 20:21:50 +00:00
return $output ;
2009-08-22 19:58:28 +00:00
}
2007-06-30 19:46:58 +00:00
/**
* Generates elements for the $arg array in the help hook .
*/
function drupal_help_arg ( $arg = array ()) {
// Note - the number of empty elements should be > MENU_MAX_PARTS.
return $arg + array ( '' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '' );
}
2007-07-25 14:44:03 +00:00
/**
2012-08-31 15:56:36 +00:00
* Returns an array containing the names of system - defined ( default ) menus .
2007-07-25 14:44:03 +00:00
*/
function menu_list_system_menus () {
2009-10-09 08:02:25 +00:00
return array (
2012-10-25 15:53:18 +00:00
'tools' => 'Tools' ,
'admin' => 'Administration' ,
'account' => 'User account menu' ,
'main' => 'Main navigation' ,
2012-11-20 11:36:51 +00:00
'footer' => 'Footer menu' ,
2009-10-09 08:02:25 +00:00
);
2007-07-25 14:44:03 +00:00
}
2007-07-04 15:49:44 +00:00
/**
2012-08-31 15:56:36 +00:00
* Returns an array of links to be rendered as the Main menu .
2007-07-04 15:49:44 +00:00
*/
2008-06-25 09:12:25 +00:00
function menu_main_menu () {
2014-02-18 13:37:58 +00:00
$main_links_source = _menu_get_links_source ( 'main_links' , 'main' );
2012-08-03 17:09:51 +00:00
return menu_navigation_links ( $main_links_source );
2004-06-18 15:04:37 +00:00
}
2007-08-23 16:41:19 +00:00
2007-07-04 15:49:44 +00:00
/**
2012-08-31 15:56:36 +00:00
* Returns an array of links to be rendered as the Secondary links .
2007-07-04 15:49:44 +00:00
*/
2008-06-25 09:12:25 +00:00
function menu_secondary_menu () {
2014-02-18 13:37:58 +00:00
$main_links_source = _menu_get_links_source ( 'main_links' , 'main' );
$secondary_links_source = _menu_get_links_source ( 'secondary_links' , 'account' );
2007-08-20 18:26:41 +00:00
2007-08-23 16:41:19 +00:00
// If the secondary menu source is set as the primary menu, we display the
2007-08-20 18:26:41 +00:00
// second level of the primary menu.
2012-08-03 17:09:51 +00:00
if ( $secondary_links_source == $main_links_source ) {
return menu_navigation_links ( $main_links_source , 1 );
2007-08-20 18:26:41 +00:00
}
else {
2012-08-03 17:09:51 +00:00
return menu_navigation_links ( $secondary_links_source , 0 );
2007-08-20 18:26:41 +00:00
}
}
2014-02-18 13:37:58 +00:00
/**
* Returns the source of links of a menu .
*
* @ param string $name
* A string configuration key of menu link source .
* @ param string $default
* Default menu name .
*
* @ return string
* Returns menu name , if exist
*/
function _menu_get_links_source ( $name , $default ) {
$config = \Drupal :: config ( 'menu.settings' );
return \Drupal :: moduleHandler () -> moduleExists ( 'menu' ) ? $config -> get ( $name ) : $default ;
}
2007-08-20 18:26:41 +00:00
/**
2012-08-31 15:56:36 +00:00
* Returns an array of links for a navigation menu .
2007-08-20 18:26:41 +00:00
*
* @ param $menu_name
* The name of the menu .
* @ param $level
* Optional , the depth of the menu to be returned .
2010-03-26 17:14:46 +00:00
*
2007-08-20 18:26:41 +00:00
* @ return
* An array of links of the specified menu and level .
*/
function menu_navigation_links ( $menu_name , $level = 0 ) {
// Don't even bother querying the menu table if no menu is specified.
2007-09-04 21:10:45 +00:00
if ( empty ( $menu_name )) {
2007-08-20 18:26:41 +00:00
return array ();
}
// Get the menu hierarchy for the current page.
2009-08-24 01:49:41 +00:00
$tree = menu_tree_page_data ( $menu_name , $level + 1 );
2007-08-20 18:26:41 +00:00
// Go down the active trail until the right level is reached.
while ( $level -- > 0 && $tree ) {
// Loop through the current level's items until we find one that is in trail.
while ( $item = array_shift ( $tree )) {
if ( $item [ 'link' ][ 'in_active_trail' ]) {
// If the item is in the active trail, we continue in the subtree.
$tree = empty ( $item [ 'below' ]) ? array () : $item [ 'below' ];
break ;
}
}
}
// Create a single level of links.
2007-05-27 20:31:13 +00:00
$links = array ();
foreach ( $tree as $item ) {
2007-08-11 14:06:15 +00:00
if ( ! $item [ 'link' ][ 'hidden' ]) {
2008-10-13 04:46:31 +00:00
$class = '' ;
2008-02-04 12:07:23 +00:00
$l = $item [ 'link' ][ 'localized_options' ];
2014-01-29 08:25:00 +00:00
$l [ 'href' ] = $item [ 'link' ][ 'link_path' ];
2007-08-11 14:06:15 +00:00
$l [ 'title' ] = $item [ 'link' ][ 'title' ];
2008-05-05 20:55:13 +00:00
if ( $item [ 'link' ][ 'in_active_trail' ]) {
2008-10-13 04:46:31 +00:00
$class = ' active-trail' ;
2010-09-24 00:37:45 +00:00
$l [ 'attributes' ][ 'class' ][] = 'active-trail' ;
}
2012-04-29 15:16:27 +00:00
// Normally, l() compares the href of every link with the current path and
// sets the active class accordingly. But local tasks do not appear in
// menu trees, so if the current path is a local task, and this link is
// its tab root, then we have to set the class manually.
2014-02-24 19:38:23 +00:00
if ( $item [ 'link' ][ 'href' ] != current_path ()) {
2010-09-24 00:37:45 +00:00
$l [ 'attributes' ][ 'class' ][] = 'active' ;
2008-05-05 20:55:13 +00:00
}
2014-02-07 04:28:14 +00:00
// Keyed with the unique mlid to generate classes in links.html.twig.
2008-10-13 04:46:31 +00:00
$links [ 'menu-' . $item [ 'link' ][ 'mlid' ] . $class ] = $l ;
2007-08-11 14:06:15 +00:00
}
2007-05-27 20:31:13 +00:00
}
return $links ;
2002-12-24 15:40:32 +00:00
}
2007-02-11 09:30:51 +00:00
/**
2009-08-22 19:58:28 +00:00
* Collects the local tasks ( tabs ), action links , and the root path .
2007-02-11 09:30:51 +00:00
*
2013-10-04 04:27:56 +00:00
* @ param int $level
2007-05-16 13:45:17 +00:00
* The level of tasks you ask for . Primary tasks are 0 , secondary are 1.
2010-03-26 17:14:46 +00:00
*
2013-10-04 04:27:56 +00:00
* @ return array
2009-08-22 19:58:28 +00:00
* An array containing
2013-02-18 17:03:05 +00:00
* - tabs : Local tasks for the requested level .
* - actions : Action links for the requested level .
2009-08-22 19:58:28 +00:00
* - root_path : The router path for the current page . If the current page is
* a default local task , then this corresponds to the parent tab .
2013-02-18 17:03:05 +00:00
*
* @ see hook_menu_local_tasks ()
* @ see hook_menu_local_tasks_alter ()
2009-08-22 19:58:28 +00:00
*/
function menu_local_tasks ( $level = 0 ) {
$data = & drupal_static ( __FUNCTION__ );
$root_path = & drupal_static ( __FUNCTION__ . ':root_path' , '' );
$empty = array (
2013-02-18 17:03:05 +00:00
'tabs' => array (),
'actions' => array (),
2009-08-22 19:58:28 +00:00
'root_path' => & $root_path ,
);
if ( ! isset ( $data )) {
2013-09-20 09:53:46 +00:00
// Look for route-based tabs.
$data [ 'tabs' ] = array ();
$data [ 'actions' ] = array ();
2013-09-21 15:23:51 +00:00
$route_name = \Drupal :: request () -> attributes -> get ( RouteObjectInterface :: ROUTE_NAME );
2013-09-20 09:53:46 +00:00
if ( ! empty ( $route_name )) {
2013-09-21 15:23:51 +00:00
$manager = \Drupal :: service ( 'plugin.manager.menu.local_task' );
2013-09-20 09:53:46 +00:00
$local_tasks = $manager -> getTasksBuild ( $route_name );
foreach ( $local_tasks as $level => $items ) {
$data [ 'tabs' ][ $level ] = empty ( $data [ 'tabs' ][ $level ]) ? $items : array_merge ( $data [ 'tabs' ][ $level ], $items );
}
}
2013-02-18 17:03:05 +00:00
// Allow modules to dynamically add further tasks.
2013-09-16 03:58:06 +00:00
$module_handler = \Drupal :: moduleHandler ();
2013-02-18 17:03:05 +00:00
foreach ( $module_handler -> getImplementations ( 'menu_local_tasks' ) as $module ) {
$function = $module . '_menu_local_tasks' ;
2013-10-04 04:27:56 +00:00
$function ( $data , $route_name );
2013-02-18 17:03:05 +00:00
}
// Allow modules to alter local tasks.
2013-10-04 04:27:56 +00:00
$module_handler -> alter ( 'menu_local_tasks' , $data , $route_name );
2007-01-31 21:26:56 +00:00
}
2007-06-30 19:46:58 +00:00
2009-08-22 19:58:28 +00:00
if ( isset ( $data [ 'tabs' ][ $level ])) {
return array (
'tabs' => $data [ 'tabs' ][ $level ],
'actions' => $data [ 'actions' ],
'root_path' => $root_path ,
);
2007-06-30 19:46:58 +00:00
}
2013-02-18 17:03:05 +00:00
elseif ( ! empty ( $data [ 'actions' ])) {
2009-12-03 20:21:50 +00:00
return array ( 'actions' => $data [ 'actions' ]) + $empty ;
}
2009-08-22 19:58:28 +00:00
return $empty ;
2007-02-11 09:30:51 +00:00
}
2007-07-04 15:49:44 +00:00
/**
* Returns the rendered local tasks at the top level .
*/
2007-02-11 09:30:51 +00:00
function menu_primary_local_tasks () {
2009-08-22 19:58:28 +00:00
$links = menu_local_tasks ( 0 );
// Do not display single tabs.
2013-02-18 17:03:05 +00:00
return count ( element_get_visible_children ( $links [ 'tabs' ])) > 1 ? $links [ 'tabs' ] : '' ;
2004-04-15 20:49:42 +00:00
}
2003-09-28 10:51:40 +00:00
2007-07-04 15:49:44 +00:00
/**
* Returns the rendered local tasks at the second level .
*/
2007-01-24 14:48:36 +00:00
function menu_secondary_local_tasks () {
2009-08-22 19:58:28 +00:00
$links = menu_local_tasks ( 1 );
// Do not display single tabs.
2013-02-18 17:03:05 +00:00
return count ( element_get_visible_children ( $links [ 'tabs' ])) > 1 ? $links [ 'tabs' ] : '' ;
2009-08-22 19:58:28 +00:00
}
/**
* Returns the rendered local actions at the current level .
*/
2013-05-28 01:20:55 +00:00
function menu_get_local_actions () {
2009-08-22 19:58:28 +00:00
$links = menu_local_tasks ();
2013-10-01 22:24:51 +00:00
$route_name = Drupal :: request () -> attributes -> get ( RouteObjectInterface :: ROUTE_NAME );
2013-09-16 03:58:06 +00:00
$manager = \Drupal :: service ( 'plugin.manager.menu.local_action' );
2013-10-13 12:40:37 +00:00
return $manager -> getActionsForRoute ( $route_name ) + $links [ 'actions' ];
2004-09-16 07:17:56 +00:00
}
2007-05-27 20:31:13 +00:00
/**
2012-08-31 15:56:36 +00:00
* Returns the router path , or the path for a default local task ' s parent .
2007-06-30 19:46:58 +00:00
*/
function menu_tab_root_path () {
2009-08-22 19:58:28 +00:00
$links = menu_local_tasks ();
return $links [ 'root_path' ];
2007-06-30 19:46:58 +00:00
}
/**
2010-11-20 04:03:51 +00:00
* Returns a renderable element for the primary and secondary tabs .
*/
function menu_local_tabs () {
2013-02-18 17:03:05 +00:00
$build = array (
2010-11-20 04:03:51 +00:00
'#theme' => 'menu_local_tasks' ,
'#primary' => menu_primary_local_tasks (),
'#secondary' => menu_secondary_local_tasks (),
);
2013-02-18 17:03:05 +00:00
return ! empty ( $build [ '#primary' ]) || ! empty ( $build [ '#secondary' ]) ? $build : array ();
2010-11-20 04:03:51 +00:00
}
/**
* Returns HTML for primary and secondary local tasks .
2007-05-27 20:31:13 +00:00
*
2012-10-05 18:12:56 +00:00
* @ param $variables
* An associative array containing :
* - primary : ( optional ) An array of local tasks ( tabs ) .
* - secondary : ( optional ) An array of local tasks ( tabs ) .
*
2007-05-27 20:31:13 +00:00
* @ ingroup themeable
2012-10-05 18:12:56 +00:00
* @ see menu_local_tasks ()
2007-05-27 20:31:13 +00:00
*/
2010-11-20 04:03:51 +00:00
function theme_menu_local_tasks ( & $variables ) {
$output = '' ;
2007-05-27 20:31:13 +00:00
2011-08-26 09:52:08 +00:00
if ( ! empty ( $variables [ 'primary' ])) {
2013-06-17 19:58:27 +00:00
$variables [ 'primary' ][ '#prefix' ] = '<h2 class="visually-hidden">' . t ( 'Primary tabs' ) . '</h2>' ;
2011-08-26 09:52:08 +00:00
$variables [ 'primary' ][ '#prefix' ] .= '<ul class="tabs primary">' ;
$variables [ 'primary' ][ '#suffix' ] = '</ul>' ;
$output .= drupal_render ( $variables [ 'primary' ]);
}
if ( ! empty ( $variables [ 'secondary' ])) {
2013-06-17 19:58:27 +00:00
$variables [ 'secondary' ][ '#prefix' ] = '<h2 class="visually-hidden">' . t ( 'Secondary tabs' ) . '</h2>' ;
2011-08-26 09:52:08 +00:00
$variables [ 'secondary' ][ '#prefix' ] .= '<ul class="tabs secondary">' ;
$variables [ 'secondary' ][ '#suffix' ] = '</ul>' ;
$output .= drupal_render ( $variables [ 'secondary' ]);
2007-07-05 08:48:58 +00:00
}
2007-05-27 20:31:13 +00:00
2007-07-05 08:48:58 +00:00
return $output ;
2007-05-27 20:31:13 +00:00
}
2007-07-04 15:49:44 +00:00
/**
2012-08-31 15:56:36 +00:00
* Sets ( or gets ) the active menu for the current page .
*
* The active menu for the page determines the active trail .
2011-12-06 12:18:12 +00:00
*
* @ return
* An array of menu machine names , in order of preference . The
Issue #2167109 by Berdir, sun, alexpott, ACF, acrollet, adamdicarlo, Albert Volkman, andreiashu, andyceo, andypost, anenkov, aspilicious, barbun, beejeebus, boombatower, cam8001, chriscalip, chx, cosmicdreams, dagmar, damiankloip, dawehner, deviance, disasm, dixon_, dstol, ebrowet, Gábor Hojtsy, heyrocker, Hydra, ianthomas_uk, japicoder, jcisio, jibran, julien, justafish, jvns, KarenS, kbasarab, kim.pepper, larowlan, Lars Toomre, leschekfm, Letharion, LinL, lirantal, Lukas von Blarer, marcingy, Mike Wacker, mrf, mtift, mtunay, n3or, nadavoid, nick_schuch, Niklas Fiekas, ParisLiakos, pcambra, penyaskito, pfrenssen, plopesc, Pol, Rok Žlender, rvilar, swentel, tim.plunkett, tobiasb, tsvenson, typhonius, vasi1186, vijaycs85, wamilton, webchick, webflo, wizonesolutions, xjm, yched, YesCT, znerol: Remove Variable subsystem.
2014-01-28 13:07:47 +00:00
* 'system.menu:active_menus_default' config item may be used to assert a menu
2012-11-02 17:23:40 +00:00
* order different from the order of creation , or to prevent a particular menu
* from being used at all in the active trail .
2007-07-04 15:49:44 +00:00
*/
2009-03-20 19:18:11 +00:00
function menu_set_active_menu_names ( $menu_names = NULL ) {
2009-04-25 15:19:12 +00:00
$active = & drupal_static ( __FUNCTION__ );
2007-05-16 13:45:17 +00:00
2009-03-20 19:18:11 +00:00
if ( isset ( $menu_names ) && is_array ( $menu_names )) {
$active = $menu_names ;
2007-05-16 13:45:17 +00:00
}
elseif ( ! isset ( $active )) {
2013-09-16 03:58:06 +00:00
$config = \Drupal :: config ( 'system.menu' );
2012-11-02 17:23:40 +00:00
$active = $config -> get ( 'active_menus_default' ) ? : array_keys ( menu_list_system_menus ());
2007-05-16 13:45:17 +00:00
}
return $active ;
}
2007-07-04 15:49:44 +00:00
/**
2012-08-31 15:56:36 +00:00
* Gets the active menu for the current page .
2007-07-04 15:49:44 +00:00
*/
2009-03-20 19:18:11 +00:00
function menu_get_active_menu_names () {
return menu_set_active_menu_names ();
2007-05-16 13:45:17 +00:00
}
2007-09-06 12:47:20 +00:00
/**
2012-08-31 15:56:36 +00:00
* Sets the active path , which determines which page is loaded .
2007-09-06 12:47:20 +00:00
*
* Note that this may not have the desired effect unless invoked very early
2013-02-06 11:50:46 +00:00
* in the page load or unless you do a subrequest to generate your page output .
2011-09-27 16:33:35 +00:00
*
* @ param $path
* A Drupal path - not a path alias .
2007-09-06 12:47:20 +00:00
*/
function menu_set_active_item ( $path ) {
2012-03-27 06:53:33 +00:00
// Since the active item has changed, the active menu trail may also be out
// of date.
drupal_static_reset ( 'menu_set_active_trail' );
2012-04-29 15:16:27 +00:00
// @todo Refactor to use the Symfony Request object.
_current_path ( $path );
2004-09-16 07:17:56 +00:00
}
2007-07-04 15:49:44 +00:00
/**
2012-08-31 15:56:36 +00:00
* Sets the active trail ( path to the menu tree root ) of the current page .
2011-09-27 16:33:35 +00:00
*
* 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
2013-09-26 08:32:39 +00:00
* the page title and not for menu trees or page content .
2011-09-27 16:33:35 +00:00
*
* To affect the trail used by menu trees , use menu_tree_set_path () . To affect
* the page content , use menu_set_active_item () instead .
2009-10-01 19:07:12 +00:00
*
* @ param $new_trail
2011-09-27 16:33:35 +00:00
* Menu trail to set ; the value is saved in a static variable and can be
* retrieved by menu_get_active_trail () . The format of this array should be
* the same as the return value of menu_get_active_trail () .
2010-03-26 17:14:46 +00:00
*
2009-10-01 19:07:12 +00:00
* @ return
2011-09-27 16:33:35 +00:00
* The active trail . See menu_get_active_trail () for details .
2007-07-04 15:49:44 +00:00
*/
2007-05-16 13:45:17 +00:00
function menu_set_active_trail ( $new_trail = NULL ) {
2009-04-25 15:19:12 +00:00
$trail = & drupal_static ( __FUNCTION__ );
2007-05-16 13:45:17 +00:00
if ( isset ( $new_trail )) {
$trail = $new_trail ;
}
elseif ( ! isset ( $trail )) {
$trail = array ();
2010-09-24 00:37:45 +00:00
$trail [] = array (
'title' => t ( 'Home' ),
'href' => '<front>' ,
'link_path' => '' ,
'localized_options' => array (),
'type' => 0 ,
);
// Try to retrieve a menu link corresponding to the current path. If more
// than one exists, the link from the most preferred menu is returned.
$preferred_link = menu_link_get_preferred ();
// There is a link for the current path.
if ( $preferred_link ) {
2014-01-29 08:25:00 +00:00
_menu_link_translate ( $preferred_link );
2010-09-24 00:37:45 +00:00
// Pass TRUE for $only_active_trail to make menu_tree_page_data() build
// a stripped down menu tree containing the active trail only, in case
// the given menu has not been built in this request yet.
$tree = menu_tree_page_data ( $preferred_link [ 'menu_name' ], NULL , TRUE );
list ( $key , $curr ) = each ( $tree );
2007-05-16 13:45:17 +00:00
}
2010-09-24 00:37:45 +00:00
// There is no link for the current path.
else {
$curr = FALSE ;
2009-03-20 19:18:11 +00:00
}
2007-05-16 13:45:17 +00:00
while ( $curr ) {
2010-09-24 00:37:45 +00:00
$link = $curr [ 'link' ];
if ( $link [ 'in_active_trail' ]) {
// Add the link to the trail, unless it links to its parent.
if ( ! ( $link [ 'type' ] & MENU_LINKS_TO_PARENT )) {
// The menu tree for the active trail may contain additional links
// that have not been translated yet, since they contain dynamic
// argument placeholders (%). Such links are not contained in regular
// menu trees, and have only been loaded for the additional
// translation that happens here, so as to be able to display them in
// the breadcumb for the current page.
// @see _menu_tree_check_access()
// @see _menu_link_translate()
if ( strpos ( $link [ 'href' ], '%' ) !== FALSE ) {
2014-01-29 08:25:00 +00:00
_menu_link_translate ( $link );
2010-09-24 00:37:45 +00:00
}
if ( $link [ 'access' ]) {
$trail [] = $link ;
}
2007-05-16 13:45:17 +00:00
}
2010-09-24 00:37:45 +00:00
$tree = $curr [ 'below' ] ? $curr [ 'below' ] : array ();
2007-05-16 13:45:17 +00:00
}
2010-09-24 00:37:45 +00:00
list ( $key , $curr ) = each ( $tree );
2007-05-16 13:45:17 +00:00
}
2011-04-21 02:29:38 +00:00
// Make sure the current page is in the trail to build the page title, by
// appending either the preferred link or the menu router item for the
// current page. Exclude it if we are on the front page.
2010-09-24 00:37:45 +00:00
$last = end ( $trail );
2012-03-27 06:53:33 +00:00
if ( $preferred_link && $last [ 'href' ] != $preferred_link [ 'href' ] && ! drupal_is_front_page ()) {
2010-09-24 00:37:45 +00:00
$trail [] = $preferred_link ;
2007-09-07 20:31:02 +00:00
}
2007-05-16 13:45:17 +00:00
}
return $trail ;
}
2010-09-24 00:37:45 +00:00
/**
2012-08-31 15:56:36 +00:00
* Looks up the preferred menu link for a given system path .
2010-09-24 00:37:45 +00:00
*
* @ param $path
2013-06-28 18:39:33 +00:00
* The path ; for example , 'node/5' . The function will find the corresponding
2010-09-24 00:37:45 +00:00
* menu link ( 'node/5' if it exists , or fallback to 'node/%' ) .
2011-12-06 12:18:12 +00:00
* @ param $selected_menu
* The name of a menu used to restrict the search for a preferred menu link .
* If not specified , all the menus returned by menu_get_active_menu_names ()
* will be used .
2010-09-24 00:37:45 +00:00
*
* @ return
2011-12-06 12:18:12 +00:00
* A fully translated menu link , or FALSE if no matching menu link was
2010-09-24 00:37:45 +00:00
* found . The most specific menu link ( 'node/5' preferred over 'node/%' ) in
* the most preferred menu ( as defined by menu_get_active_menu_names ()) is
* returned .
*/
2011-12-06 12:18:12 +00:00
function menu_link_get_preferred ( $path = NULL , $selected_menu = NULL ) {
2010-09-24 00:37:45 +00:00
$preferred_links = & drupal_static ( __FUNCTION__ );
if ( ! isset ( $path )) {
2012-04-29 15:16:27 +00:00
$path = current_path ();
2010-09-24 00:37:45 +00:00
}
2011-12-06 12:18:12 +00:00
if ( empty ( $selected_menu )) {
// Use an illegal menu name as the key for the preferred menu link.
$selected_menu = MENU_PREFERRED_LINK ;
}
2010-09-24 00:37:45 +00:00
2011-12-06 12:18:12 +00:00
if ( ! isset ( $preferred_links [ $path ])) {
2010-09-24 00:37:45 +00:00
// Look for the correct menu link by building a list of candidate paths,
// which are ordered by priority (translated hrefs are preferred over
// untranslated paths). Afterwards, the most relevant path is picked from
// the menus, ordered by menu preference.
$path_candidates = array ();
// 1. The current item href.
2014-01-29 08:25:00 +00:00
// @todo simplify this code and convert to using route names.
// @see https://drupal.org/node/2154949
$path_candidates [ $path ] = $path ;
2010-09-24 00:37:45 +00:00
// Retrieve a list of menu names, ordered by preference.
$menu_names = menu_get_active_menu_names ();
2011-12-06 12:18:12 +00:00
// Put the selected menu at the front of the list.
array_unshift ( $menu_names , $selected_menu );
2010-09-24 00:37:45 +00:00
2013-02-08 23:55:25 +00:00
$menu_links = entity_load_multiple_by_properties ( 'menu_link' , array ( 'link_path' => $path_candidates ));
2010-09-24 00:37:45 +00:00
// Sort candidates by link path and menu name.
$candidates = array ();
2013-02-08 23:55:25 +00:00
foreach ( $menu_links as $candidate ) {
2010-09-24 00:37:45 +00:00
$candidates [ $candidate [ 'link_path' ]][ $candidate [ 'menu_name' ]] = $candidate ;
2011-12-06 12:18:12 +00:00
// Add any menus not already in the menu name search list.
if ( ! in_array ( $candidate [ 'menu_name' ], $menu_names )) {
$menu_names [] = $candidate [ 'menu_name' ];
}
2010-09-24 00:37:45 +00:00
}
2011-12-06 12:18:12 +00:00
// Store the most specific link for each menu. Also save the most specific
// link of the most preferred menu in $preferred_link.
2010-09-24 00:37:45 +00:00
foreach ( $path_candidates as $link_path ) {
2011-12-06 12:18:12 +00:00
if ( isset ( $candidates [ $link_path ])) {
foreach ( $menu_names as $menu_name ) {
if ( empty ( $preferred_links [ $path ][ $menu_name ]) && isset ( $candidates [ $link_path ][ $menu_name ])) {
$candidate_item = $candidates [ $link_path ][ $menu_name ];
2014-03-01 04:58:58 +00:00
$candidate_item [ 'access' ] = \Drupal :: service ( 'access_manager' ) -> checkNamedRoute ( $candidate_item [ 'route_name' ], $candidate_item [ 'route_parameters' ], \Drupal :: currentUser ());
2011-12-06 12:18:12 +00:00
if ( $candidate_item [ 'access' ]) {
2014-03-01 04:58:58 +00:00
_menu_item_localize ( $candidate_item );
2011-12-06 12:18:12 +00:00
$preferred_links [ $path ][ $menu_name ] = $candidate_item ;
if ( empty ( $preferred_links [ $path ][ MENU_PREFERRED_LINK ])) {
// Store the most specific link.
$preferred_links [ $path ][ MENU_PREFERRED_LINK ] = $candidate_item ;
}
}
}
2010-09-24 00:37:45 +00:00
}
}
}
}
2011-12-06 12:18:12 +00:00
return isset ( $preferred_links [ $path ][ $selected_menu ]) ? $preferred_links [ $path ][ $selected_menu ] : FALSE ;
2010-09-24 00:37:45 +00:00
}
2007-07-04 15:49:44 +00:00
/**
2009-10-01 19:07:12 +00:00
* Gets the active trail ( path to root menu root ) of the current page .
*
2011-09-27 16:33:35 +00:00
* If a trail is supplied to menu_set_active_trail (), that value is returned . If
* a trail is not supplied to menu_set_active_trail (), the path to the current
* page is calculated and returned . The calculated trail is also saved as a
* static value for use by subsequent calls to menu_get_active_trail () .
*
* @ return
* Path to menu root of the current page , as an array of menu link items ,
* starting with the site ' s home page . Each link item is an associative array
* with the following components :
* - title : Title of the item .
* - href : Drupal path of the item .
* - localized_options : Options for passing into the l () function .
* - type : A menu type constant , such as MENU_DEFAULT_LOCAL_TASK , or 0 to
* indicate it ' s not really in the menu ( used for the home page item ) .
2007-07-04 15:49:44 +00:00
*/
2007-05-16 13:45:17 +00:00
function menu_get_active_trail () {
return menu_set_active_trail ();
}
/**
2012-08-31 15:56:36 +00:00
* Clears all cached menu data .
*
* This should be called any time broad changes
2007-07-04 15:49:44 +00:00
* might have been made to the router items or menu links .
2007-05-16 13:45:17 +00:00
*/
function menu_cache_clear_all () {
2014-03-26 13:19:28 +00:00
\Drupal :: cache ( 'data' ) -> deleteAll ();
#610234 by Gábor Hojtsy, ksenzee, cwgordon7, David_Rothstein, seutje, marcvangend, sun, JoshuaRogers, markus_petrux, Bojhan, Rob Loach, Everett Zufelt, drifter, markboulton, leisareichelt, et al: Added Overlay module to core, which shows administrative pages in a JS overlay, retaining context on the front-end site.
2009-12-02 07:28:22 +00:00
menu_reset_static_cache ();
}
/**
* Resets the menu system static cache .
*/
function menu_reset_static_cache () {
2013-09-16 03:58:06 +00:00
\Drupal :: entityManager ()
2013-02-08 23:55:25 +00:00
-> getStorageController ( 'menu_link' ) -> resetCache ();
2010-07-06 07:27:07 +00:00
drupal_static_reset ( '_menu_build_tree' );
#610234 by Gábor Hojtsy, ksenzee, cwgordon7, David_Rothstein, seutje, marcvangend, sun, JoshuaRogers, markus_petrux, Bojhan, Rob Loach, Everett Zufelt, drifter, markboulton, leisareichelt, et al: Added Overlay module to core, which shows administrative pages in a JS overlay, retaining context on the front-end site.
2009-12-02 07:28:22 +00:00
drupal_static_reset ( 'menu_tree' );
drupal_static_reset ( 'menu_tree_all_data' );
drupal_static_reset ( 'menu_tree_page_data' );
2010-09-24 00:37:45 +00:00
drupal_static_reset ( 'menu_link_get_preferred' );
2007-05-16 13:45:17 +00:00
}
2007-06-05 09:15:02 +00:00
/**
2014-01-29 08:25:00 +00:00
* Saves menu links recursively for menu_links_rebuild_defaults () .
*/
function _menu_link_save_recursive ( $controller , $machine_name , & $children , & $links ) {
$menu_link = $links [ $machine_name ];
if ( $menu_link -> isNew () || ! $menu_link -> customized ) {
if ( ! isset ( $menu_link -> plid ) && ! empty ( $menu_link -> parent ) && ! empty ( $links [ $menu_link -> parent ])) {
$parent = $links [ $menu_link -> parent ];
if ( empty ( $menu_link -> menu_name ) || $parent -> menu_name == $menu_link -> menu_name ) {
$menu_link -> plid = $parent -> id ();
$menu_link -> menu_name = $parent -> menu_name ;
}
}
$controller -> save ( $menu_link );
}
if ( ! empty ( $children [ $machine_name ])) {
foreach ( $children [ $machine_name ] as $next_name ) {
_menu_link_save_recursive ( $controller , $next_name , $children , $links );
}
}
// Remove processed link names so we can find stragglers.
unset ( $children [ $machine_name ]);
}
/**
* Gets all default menu link definitions .
2013-02-08 23:55:25 +00:00
*
2014-01-29 08:25:00 +00:00
* @ return array
* An array of default menu links .
2007-06-05 09:15:02 +00:00
*/
2014-01-29 08:25:00 +00:00
function menu_link_get_defaults () {
$module_handler = \Drupal :: moduleHandler ();
$all_links = $module_handler -> invokeAll ( 'menu_link_defaults' );
// Fill in the machine name from the array key.
foreach ( $all_links as $machine_name => & $link ) {
$link [ 'machine_name' ] = $machine_name ;
}
$module_handler -> alter ( 'menu_link_defaults' , $all_links );
return $all_links ;
}
/**
* Builds menu links for the items returned from hook_menu_link_defaults () .
*/
function menu_link_rebuild_defaults () {
2014-02-24 19:38:23 +00:00
// Ensure that all configuration used to build the menu items are loaded
// without overrides.
$old_state = \Drupal :: configFactory () -> getOverrideState ();
\Drupal :: configFactory () -> setOverrideState ( FALSE );
2014-01-29 08:25:00 +00:00
$module_handler = \Drupal :: moduleHandler ();
if ( ! $module_handler -> moduleExists ( 'menu_link' )) {
2013-08-12 13:28:56 +00:00
// The Menu link module may not be available during install, so rebuild
// when possible.
return ;
2009-12-14 20:23:01 +00:00
}
2014-01-29 08:25:00 +00:00
/** @var \Drupal\menu_link\MenuLinkStorageControllerInterface $menu_link_storage */
$menu_link_storage = \Drupal :: entityManager ()
2013-08-12 13:28:56 +00:00
-> getStorageController ( 'menu_link' );
2014-01-29 08:25:00 +00:00
$links = array ();
$children = array ();
$top_links = array ();
$all_links = menu_link_get_defaults ();
if ( $all_links ) {
foreach ( $all_links as $machine_name => $link ) {
2013-02-08 23:55:25 +00:00
// For performance reasons, do a straight query now and convert to a menu
// link entity later.
// @todo revisit before release.
2008-12-03 14:38:59 +00:00
$existing_item = db_select ( 'menu_links' )
2011-07-14 01:41:00 +00:00
-> fields ( 'menu_links' )
2014-01-29 08:25:00 +00:00
-> condition ( 'machine_name' , $machine_name )
2008-12-03 14:38:59 +00:00
-> condition ( 'module' , 'system' )
2014-01-29 08:25:00 +00:00
-> execute () -> fetchObject ();
2007-07-04 15:49:44 +00:00
if ( $existing_item ) {
2013-02-08 23:55:25 +00:00
$existing_item -> options = unserialize ( $existing_item -> options );
2013-10-01 12:09:08 +00:00
$existing_item -> route_parameters = unserialize ( $existing_item -> route_parameters );
2014-01-29 08:25:00 +00:00
$link [ 'mlid' ] = $existing_item -> mlid ;
$link [ 'plid' ] = $existing_item -> plid ;
$link [ 'uuid' ] = $existing_item -> uuid ;
$link [ 'customized' ] = $existing_item -> customized ;
$link [ 'updated' ] = $existing_item -> updated ;
$menu_link = $menu_link_storage -> createFromDefaultLink ( $link );
2014-01-24 10:23:53 +00:00
// Convert the existing item to a typed object.
2014-01-29 08:25:00 +00:00
/** @var \Drupal\menu_link\MenuLinkInterface $existing_item */
$existing_item = $menu_link_storage -> create ( get_object_vars ( $existing_item ));
if ( ! $existing_item -> customized ) {
// A change in hook_menu_link_defaults() may move the link to a
// different menu or parent.
if ( ! empty ( $link [ 'menu_name' ]) && ( $link [ 'menu_name' ] != $existing_item -> menu_name )) {
$menu_link -> plid = NULL ;
$menu_link -> menu_name = $link [ 'menu_name' ];
}
elseif ( ! empty ( $link [ 'parent' ])) {
$menu_link -> plid = NULL ;
}
$menu_link -> original = $existing_item ;
}
2007-07-04 15:49:44 +00:00
}
2013-02-08 23:55:25 +00:00
else {
2014-01-29 08:25:00 +00:00
if ( empty ( $link [ 'route_name' ]) && empty ( $link [ 'link_path' ])) {
watchdog ( 'error' , 'Menu_link %machine_name does neither provide a route_name nor a link_path, so it got skipped.' , array ( '%machine_name' => $machine_name ));
continue ;
}
$menu_link = $menu_link_storage -> createFromDefaultLink ( $link );
2013-02-08 23:55:25 +00:00
}
2014-01-29 08:25:00 +00:00
if ( ! empty ( $link [ 'parent' ])) {
$children [ $link [ 'parent' ]][ $machine_name ] = $machine_name ;
$menu_link -> parent = $link [ 'parent' ];
if ( empty ( $link [ 'menu_name' ])) {
2014-03-20 16:18:35 +00:00
// Reset the default menu name so it is populated from the parent.
$menu_link -> menu_name = NULL ;
2014-01-29 08:25:00 +00:00
}
2011-07-14 01:41:00 +00:00
}
else {
2014-01-29 08:25:00 +00:00
// A top level link - we need them to root our tree.
$top_links [ $machine_name ] = $machine_name ;
$menu_link -> plid = 0 ;
2007-07-04 15:49:44 +00:00
}
2014-01-29 08:25:00 +00:00
$links [ $machine_name ] = $menu_link ;
2007-05-16 13:45:17 +00:00
}
2007-05-06 05:47:52 +00:00
}
2014-01-29 08:25:00 +00:00
foreach ( $top_links as $machine_name ) {
_menu_link_save_recursive ( $menu_link_storage , $machine_name , $children , $links );
}
// Handle any children we didn't find starting from top-level links.
foreach ( $children as $orphan_links ) {
foreach ( $orphan_links as $machine_name ) {
// Force it to the top level.
$links [ $machine_name ] -> plid = 0 ;
_menu_link_save_recursive ( $menu_link_storage , $machine_name , $children , $links );
2007-08-29 20:46:18 +00:00
}
2007-08-19 09:46:15 +00:00
}
2013-02-08 23:55:25 +00:00
2014-01-29 08:25:00 +00:00
// Find any item whose entry in hook_menu_link_defaults() no longer exists.
if ( $all_links ) {
$query = \Drupal :: entityQuery ( 'menu_link' )
-> condition ( 'machine_name' , array_keys ( $all_links ), 'NOT IN' )
2014-02-26 10:53:29 +00:00
-> exists ( 'machine_name' )
2014-01-29 08:25:00 +00:00
-> condition ( 'external' , 0 )
-> condition ( 'updated' , 0 )
-> condition ( 'customized' , 0 )
-> sort ( 'depth' , 'DESC' );
$result = $query -> execute ();
}
else {
$result = array ();
}
2007-05-06 05:47:52 +00:00
2013-02-08 23:55:25 +00:00
// Remove all such items. Starting from those with the greatest depth will
// minimize the amount of re-parenting done by the menu link controller.
2014-01-29 08:25:00 +00:00
if ( $result ) {
2013-02-08 23:55:25 +00:00
menu_link_delete_multiple ( $result , TRUE );
2009-10-17 01:15:40 +00:00
}
2014-02-24 19:38:23 +00:00
\Drupal :: configFactory () -> setOverrideState ( $old_state );
2009-10-17 01:15:40 +00:00
}
/**
* Returns an array containing all links for a menu .
*
* @ param $menu_name
* The name of the menu whose links should be returned .
2010-07-16 02:54:09 +00:00
*
2009-10-17 01:15:40 +00:00
* @ return
* An array of menu links .
*/
function menu_load_links ( $menu_name ) {
2013-02-08 23:55:25 +00:00
$links = array ();
2013-09-16 03:58:06 +00:00
$query = \Drupal :: entityQuery ( 'menu_link' )
2013-02-08 23:55:25 +00:00
-> condition ( 'menu_name' , $menu_name )
2009-10-17 01:15:40 +00:00
// Order by weight so as to be helpful for menus that are only one level
// deep.
2013-02-08 23:55:25 +00:00
-> sort ( 'weight' );
$result = $query -> execute ();
2009-10-17 01:15:40 +00:00
2013-02-08 23:55:25 +00:00
if ( ! empty ( $result )) {
$links = menu_link_load_multiple ( $result );
2009-10-17 01:15:40 +00:00
}
2013-02-08 23:55:25 +00:00
2009-10-17 01:15:40 +00:00
return $links ;
}
/**
* Deletes all links for a menu .
*
* @ param $menu_name
* The name of the menu whose links will be deleted .
*/
function menu_delete_links ( $menu_name ) {
$links = menu_load_links ( $menu_name );
2013-02-08 23:55:25 +00:00
menu_link_delete_multiple ( array_keys ( $links ), FALSE , TRUE );
2010-11-20 07:19:15 +00:00
}
2007-11-26 08:49:03 +00:00
/**
2012-08-31 15:56:36 +00:00
* Clears the page and block caches at most twice per page load .
2007-12-08 14:06:23 +00:00
*/
2007-11-26 08:49:03 +00:00
function _menu_clear_page_cache () {
2009-04-25 15:19:12 +00:00
$cache_cleared = & drupal_static ( __FUNCTION__ , 0 );
2007-11-26 08:49:03 +00:00
2007-11-26 16:19:37 +00:00
// Clear the page and block caches, but at most twice, including at
2008-12-30 16:43:20 +00:00
// the end of the page load when there are multiple links saved or deleted.
2009-04-25 15:19:12 +00:00
if ( $cache_cleared == 0 ) {
2014-02-21 15:21:08 +00:00
Cache :: invalidateTags ( array ( 'content' => TRUE ));
2007-11-26 08:49:03 +00:00
// Keep track of which menus have expanded items.
_menu_set_expanded_menus ();
$cache_cleared = 1 ;
}
elseif ( $cache_cleared == 1 ) {
2014-02-21 15:21:08 +00:00
drupal_register_shutdown_function ( 'Drupal\Core\Cache\Cache::invalidateTags' , array ( 'content' => TRUE ));
2007-11-26 08:49:03 +00:00
// Keep track of which menus have expanded items.
2010-02-17 22:44:52 +00:00
drupal_register_shutdown_function ( '_menu_set_expanded_menus' );
2007-11-26 08:49:03 +00:00
$cache_cleared = 2 ;
}
}
/**
2012-08-31 15:56:36 +00:00
* Updates a list of menus with expanded items .
2007-12-08 14:06:23 +00:00
*/
2007-11-26 08:49:03 +00:00
function _menu_set_expanded_menus () {
2014-03-24 10:43:05 +00:00
$names = array ();
$result = Drupal :: entityQueryAggregate ( 'menu_link' )
-> condition ( 'expanded' , 0 , '<>' )
-> groupBy ( 'menu_name' )
-> execute ();
2014-03-24 11:28:22 +00:00
// Flatten the resulting array.
foreach ( $result as $k => $v ) {
2014-03-24 10:43:05 +00:00
$names [ $k ] = $v [ 'menu_name' ];
}
2013-09-16 03:58:06 +00:00
\Drupal :: state () -> set ( 'menu_expanded' , $names );
2007-05-16 13:45:17 +00:00
}
2007-05-26 10:54:12 +00:00
/**
2009-08-22 18:24:14 +00:00
* Checks whether the site is in maintenance mode .
2008-01-02 14:29:32 +00:00
*
* This function will log the current user out and redirect to front page
2009-08-22 18:24:14 +00:00
* if the current user has no 'access site in maintenance mode' permission .
2008-01-02 14:29:32 +00:00
*
2009-09-30 13:09:30 +00:00
* @ param $check_only
* If this is set to TRUE , the function will perform the access checks and
* return the site offline status , but not log the user out or display any
* messages .
2010-03-26 17:14:46 +00:00
*
2008-01-02 14:29:32 +00:00
* @ return
2009-08-22 18:24:14 +00:00
* FALSE if the site is not in maintenance mode , the user login page is
* displayed , or the user has the 'access site in maintenance mode'
* permission . TRUE for anonymous users not being on the login page when the
* site is in maintenance mode .
2007-05-26 10:54:12 +00:00
*/
2009-09-30 13:09:30 +00:00
function _menu_site_is_offline ( $check_only = FALSE ) {
2009-08-22 18:24:14 +00:00
// Check if site is in maintenance mode.
2013-09-16 03:58:06 +00:00
if ( \Drupal :: state () -> get ( 'system.maintenance_mode' )) {
2009-08-22 18:24:14 +00:00
if ( user_access ( 'access site in maintenance mode' )) {
// Ensure that the maintenance mode message is displayed only once
// (allowing for page redirects) and specifically suppress its display on
// the maintenance mode settings page.
2012-04-29 15:16:27 +00:00
if ( ! $check_only && current_path () != 'admin/config/development/maintenance' ) {
2009-08-22 18:24:14 +00:00
if ( user_access ( 'administer site configuration' )) {
drupal_set_message ( t ( 'Operating in maintenance mode. <a href="@url">Go online.</a>' , array ( '@url' => url ( 'admin/config/development/maintenance' ))), 'status' , FALSE );
}
else {
drupal_set_message ( t ( 'Operating in maintenance mode.' ), 'status' , FALSE );
}
2008-02-10 07:35:40 +00:00
}
2008-01-02 14:29:32 +00:00
}
else {
2010-07-07 08:05:01 +00:00
return TRUE ;
2007-05-26 10:54:12 +00:00
}
}
return FALSE ;
}
2008-01-03 09:59:00 +00:00
2008-01-28 16:05:17 +00:00
/**
* @ } End of " defgroup menu " .
*/