547 lines
22 KiB
Plaintext
547 lines
22 KiB
Plaintext
<?php
|
|
|
|
/**
|
|
* @file
|
|
* Module file for menu_example.
|
|
*/
|
|
|
|
/**
|
|
* @defgroup menu_example Example: Menu
|
|
* @ingroup examples
|
|
* @{
|
|
* Demonstrates uses of the Menu APIs in Drupal.
|
|
*
|
|
* The Page Example module also talks about the menu system, as well
|
|
* as how to use menu arguments to generate pages.
|
|
*
|
|
* @see hook_menu()
|
|
* @see hook_menu_alter()
|
|
* @see hook_menu_link_alter()
|
|
* @see page_example
|
|
* @see page_example_menu()
|
|
*/
|
|
|
|
/**
|
|
* Implements hook_menu().
|
|
*
|
|
* A simple example which defines a page callback and a menu entry.
|
|
*/
|
|
function menu_example_menu() {
|
|
// Menu items are defined by placing them in an $items array. The array key
|
|
// (in this case 'menu_example') is the path that defines the menu router
|
|
// entry, so the page will be accessible from the URL
|
|
// example.com/examples/menu_example.
|
|
$items['examples/menu_example'] = array(
|
|
// We are using the default menu type, so this can be omitted.
|
|
// 'type' => MENU_NORMAL_ITEM,
|
|
//
|
|
// The menu title. Do NOT use t() which is called by default. You can
|
|
// override the use of t() by defining a 'title callback'. This is explained
|
|
// in the 'menu_example/title_callbacks' example below.
|
|
'title' => 'Menu Example',
|
|
|
|
// Description (hover flyover for menu link). Does NOT use t(), which is
|
|
// called automatically.
|
|
'description' => 'Simplest possible menu type, and the parent menu entry for others',
|
|
|
|
// Function to be called when this path is accessed.
|
|
'page callback' => '_menu_example_basic_instructions',
|
|
|
|
// Arguments to the page callback. Here's we'll use them just to provide
|
|
// content for our page.
|
|
'page arguments' => array(t('This page is displayed by the simplest (and base) menu example. Note that the title of the page is the same as the link title. You can also <a href="!link">visit a similar page with no menu link</a>. Also, note that there is a hook_menu_alter() example that has changed the path of one of the menu items.', array('!link' => url('examples/menu_example/path_only')))),
|
|
|
|
// If the page is meant to be accessible to all users, you can set 'access
|
|
// callback' to TRUE. This bypasses all access checks. For an explanation on
|
|
// how to use the permissions system to restrict access for certain users,
|
|
// see the example 'examples/menu_example/permissioned/controlled' below.
|
|
'access callback' => TRUE,
|
|
|
|
// If the page callback is located in another file, specify it here and
|
|
// that file will be automatically loaded when needed.
|
|
// 'file' => 'menu_example.module',
|
|
//
|
|
// We can choose which menu gets the link. The default is 'navigation'.
|
|
// 'menu_name' => 'navigation',
|
|
//
|
|
// Show the menu link as expanded.
|
|
'expanded' => TRUE,
|
|
);
|
|
|
|
// Show a menu link in a menu other than the default "Navigation" menu.
|
|
// The menu must already exist.
|
|
$items['examples/menu_example_alternate_menu'] = array(
|
|
'title' => 'Menu Example: Menu in alternate menu',
|
|
|
|
// Machine name of the menu in which the link should appear.
|
|
'menu_name' => 'main-menu',
|
|
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('This will be in the Main menu instead of the default Navigation menu')),
|
|
'access callback' => TRUE,
|
|
);
|
|
|
|
// A menu entry with simple permissions using user_access().
|
|
//
|
|
// First, provide a courtesy menu item that mentions the existence of the
|
|
// permissioned item.
|
|
$items['examples/menu_example/permissioned'] = array(
|
|
'title' => 'Permissioned Example',
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('A menu item that requires the "access protected menu example" permission is at <a href="!link">examples/menu_example/permissioned/controlled</a>', array('!link' => url('examples/menu_example/permissioned/controlled')))),
|
|
'access callback' => TRUE,
|
|
'expanded' => TRUE,
|
|
);
|
|
|
|
// Now provide the actual permissioned menu item.
|
|
$items['examples/menu_example/permissioned/controlled'] = array(
|
|
|
|
// The title - do NOT use t() as t() is called automatically.
|
|
'title' => 'Permissioned Menu Item',
|
|
'description' => 'This menu entry will not appear and the page will not be accessible without the "access protected menu example" permission.',
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('This menu entry will not show and the page will not be accessible without the "access protected menu example" permission.')),
|
|
|
|
// For a permissioned menu entry, we provide an access callback which
|
|
// determines whether the current user should have access. The default is
|
|
// user_access(), which we'll use in this case. Since it's the default,
|
|
// we don't even have to enter it.
|
|
// 'access callback' => 'user_access',
|
|
//
|
|
// The 'access arguments' are passed to the 'access callback' to help it
|
|
// do its job. In the case of user_access(), we need to pass a permission
|
|
// as the first argument.
|
|
'access arguments' => array('access protected menu example'),
|
|
|
|
// The optional weight element tells how to order the submenu items.
|
|
// Higher weights are "heavier", dropping to the bottom of the menu.
|
|
'weight' => 10,
|
|
);
|
|
|
|
/*
|
|
* We will define our own "access callback" function. We'll use
|
|
* menu_example_custom_access() rather than the default user_access().
|
|
*
|
|
* The function takes a "role" of the user as an argument.
|
|
*/
|
|
$items['examples/menu_example/custom_access'] = array(
|
|
'title' => 'Custom Access Example',
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('A menu item that requires the user to posess a role of "authenticated user" is at <a href="!link">examples/menu_example/custom_access/page</a>', array('!link' => url('examples/menu_example/custom_access/page')))),
|
|
'access callback' => TRUE,
|
|
'expanded' => TRUE,
|
|
'weight' => -5,
|
|
);
|
|
|
|
$items['examples/menu_example/custom_access/page'] = array(
|
|
'title' => 'Custom Access Menu Item',
|
|
'description' => 'This menu entry will not show and the page will not be accessible without the user being an "authenticated user".',
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('This menu entry will not be visible and access will result in a 403 error unless the user has the "authenticated user" role. This is accomplished with a custom access callback.')),
|
|
'access callback' => 'menu_example_custom_access',
|
|
'access arguments' => array('authenticated user'),
|
|
);
|
|
|
|
// A menu router entry with no menu link. This could be used any time we
|
|
// don't want the user to see a link in the menu. Otherwise, it's the same
|
|
// as the "simplest" entry above. MENU_CALLBACK is used for all menu items
|
|
// which don't need a visible menu link, including services and other pages
|
|
// that may be linked to but are not intended to be accessed directly.
|
|
//
|
|
// First, provide a courtesy link in the menu so people can find this.
|
|
$items['examples/menu_example/path_only'] = array(
|
|
'title' => 'MENU_CALLBACK example',
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('A menu entry with no menu link (MENU_CALLBACK) is at <a href="!link">!link</a>', array('!link' => url('examples/menu_example/path_only/callback')))),
|
|
'access callback' => TRUE,
|
|
'weight' => 20,
|
|
);
|
|
$items['examples/menu_example/path_only/callback'] = array(
|
|
|
|
// A type of MENU_CALLBACK means leave the path completely out of the menu
|
|
// links.
|
|
'type' => MENU_CALLBACK,
|
|
|
|
// The title is still used for the page title, even though it's not used
|
|
// for the menu link text, since there's no menu link.
|
|
'title' => 'Callback Only',
|
|
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('The menu entry for this page is of type MENU_CALLBACK, so it provides only a path but not a link in the menu links, but it is the same in every other way to the simplest example.')),
|
|
'access callback' => TRUE,
|
|
);
|
|
|
|
// A menu entry with tabs.
|
|
// For tabs we need at least 3 things:
|
|
// 1) A parent MENU_NORMAL_ITEM menu item (examples/menu_example/tabs in this
|
|
// example.)
|
|
// 2) A primary tab (the one that is active when we land on the base menu).
|
|
// This tab is of type MENU_DEFAULT_LOCAL_TASK.
|
|
// 3) Some other menu entries for the other tabs, of type MENU_LOCAL_TASK.
|
|
$items['examples/menu_example/tabs'] = array(
|
|
// 'type' => MENU_NORMAL_ITEM, // Not necessary since this is the default.
|
|
'title' => 'Tabs',
|
|
'description' => 'Shows how to create primary and secondary tabs',
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('This is the "tabs" menu entry.')),
|
|
'access callback' => TRUE,
|
|
'weight' => 30,
|
|
);
|
|
|
|
// For the default local task, we need very little configuration, as the
|
|
// callback and other conditions are handled by the parent callback.
|
|
$items['examples/menu_example/tabs/default'] = array(
|
|
'type' => MENU_DEFAULT_LOCAL_TASK,
|
|
'title' => 'Default primary tab',
|
|
'weight' => 1,
|
|
);
|
|
// Now add the rest of the tab entries.
|
|
foreach (array(t('second') => 2, t('third') => 3, t('fourth') => 4) as $tabname => $weight) {
|
|
$items["examples/menu_example/tabs/$tabname"] = array(
|
|
'type' => MENU_LOCAL_TASK,
|
|
'title' => $tabname,
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('This is the tab "@tabname" in the "basic tabs" example', array('@tabname' => $tabname))),
|
|
'access callback' => TRUE,
|
|
|
|
// The weight property overrides the default alphabetic ordering of menu
|
|
// entries, allowing us to get our tabs in the order we want.
|
|
'weight' => $weight,
|
|
);
|
|
}
|
|
|
|
// Finally, we'll add secondary tabs to the default tab of the tabs entry.
|
|
//
|
|
// The default local task needs very little information.
|
|
$items['examples/menu_example/tabs/default/first'] = array(
|
|
'type' => MENU_DEFAULT_LOCAL_TASK,
|
|
'title' => 'Default secondary tab',
|
|
// The additional page callback and related items are handled by the
|
|
// parent menu item.
|
|
);
|
|
foreach (array(t('second'), t('third')) as $tabname) {
|
|
$items["examples/menu_example/tabs/default/$tabname"] = array(
|
|
'type' => MENU_LOCAL_TASK,
|
|
'title' => $tabname,
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('This is the secondary tab "@tabname" in the "basic tabs" example "default" tab', array('@tabname' => $tabname))),
|
|
'access callback' => TRUE,
|
|
);
|
|
}
|
|
|
|
// All the portions of the URL after the base menu are passed to the page
|
|
// callback as separate arguments, and can be captured by the page callback
|
|
// in its argument list. Our _menu_example_menu_page() function captures
|
|
// arguments in its function signature and can output them.
|
|
$items['examples/menu_example/use_url_arguments'] = array(
|
|
'title' => 'Extra Arguments',
|
|
'description' => 'The page callback can use the arguments provided after the path used as key',
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('This page demonstrates using arguments in the path (portions of the path after "menu_example/url_arguments". For example, access it with <a href="!link1">!link1</a> or <a href="!link2">!link2</a>).', array('!link1' => url('examples/menu_example/use_url_arguments/one/two'), '!link2' => url('examples/menu_example/use_url_arguments/firstarg/secondarg')))),
|
|
'access callback' => TRUE,
|
|
'weight' => 40,
|
|
);
|
|
|
|
// The menu title can be dynamically created by using the 'title callback'
|
|
// which by default is t(). Here we provide a title callback which adjusts
|
|
// the menu title based on the current user's username.
|
|
$items['examples/menu_example/title_callbacks'] = array(
|
|
'title callback' => '_menu_example_simple_title_callback',
|
|
'title arguments' => array(t('Dynamic title: username=')),
|
|
'description' => 'The title of this menu item is dynamically generated',
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('The menu title is dynamically changed by the title callback')),
|
|
'access callback' => TRUE,
|
|
'weight' => 50,
|
|
);
|
|
|
|
// Sometimes we need to capture a specific argument within the menu path,
|
|
// as with the menu entry
|
|
// 'example/menu_example/placeholder_argument/3333/display', where we need to
|
|
// capture the "3333". In that case, we use a placeholder in the path provided
|
|
// in the menu entry. The (odd) way this is done is by using
|
|
// array(numeric_position_value) as the value for 'page arguments'. The
|
|
// numeric_position_value is the zero-based index of the portion of the URL
|
|
// which should be passed to the 'page callback'.
|
|
//
|
|
// First we provide a courtesy link with information on how to access
|
|
// an item with a placeholder.
|
|
$items['examples/menu_example/placeholder_argument'] = array(
|
|
'title' => 'Placeholder Arguments',
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('Demonstrate placeholders by visiting <a href="!link">examples/menu_example/placeholder_argument/3343/display</a>', array('!link' => url('examples/menu_example/placeholder_argument/3343/display')))),
|
|
'access callback' => TRUE,
|
|
'weight' => 60,
|
|
);
|
|
|
|
// Now the actual entry.
|
|
$items['examples/menu_example/placeholder_argument/%/display'] = array(
|
|
'title' => 'Placeholder Arguments',
|
|
'page callback' => '_menu_example_menu_page',
|
|
|
|
// Pass the value of '%', which is zero-based argument 3, to the
|
|
// 'page callback'. So if the URL is
|
|
// 'examples/menu_example/placeholder_argument/333/display' then the value
|
|
// 333 will be passed into the 'page callback'.
|
|
'page arguments' => array(3),
|
|
'access callback' => TRUE,
|
|
);
|
|
|
|
// Drupal provides magic placeholder processing as well, so if the placeholder
|
|
// is '%menu_example_arg_optional', the function
|
|
// menu_example_arg_optional_load($arg) will be called to translate the path
|
|
// argument to a more substantial object. $arg will be the value of the
|
|
// placeholder. Then the return value of menu_example_id_load($arg) will be
|
|
// passed to the 'page callback'.
|
|
// In addition, if (in this case) menu_example_arg_optional_to_arg() exists,
|
|
// then a menu link can be created using the results of that function as a
|
|
// default for %menu_example_arg_optional.
|
|
$items['examples/menu_example/default_arg/%menu_example_arg_optional'] = array(
|
|
'title' => 'Processed Placeholder Arguments',
|
|
'page callback' => '_menu_example_menu_page',
|
|
// Argument 3 (4rd arg) is the one we want.
|
|
'page arguments' => array(3),
|
|
'access callback' => TRUE,
|
|
'weight' => 70,
|
|
);
|
|
|
|
$items['examples/menu_example/menu_original_path'] = array(
|
|
'title' => 'Menu path that will be altered by hook_menu_alter()',
|
|
'page callback' => '_menu_example_menu_page',
|
|
'page arguments' => array(t('This menu item was created strictly to allow the hook_menu_alter() function to have something to operate on. hook_menu defined the path as examples/menu_example/menu_original_path. The hook_menu_alter() changes it to examples/menu_example/menu_altered_path. You can try navigating to both paths and see what happens!')),
|
|
'access callback' => TRUE,
|
|
'weight' => 80,
|
|
);
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Page callback for the simplest introduction menu entry.
|
|
*
|
|
* @param string $content
|
|
* Some content passed in.
|
|
*/
|
|
function _menu_example_basic_instructions($content = NULL) {
|
|
$base_content = t(
|
|
'This is the base page of the Menu Example. There are a number of examples
|
|
here, from the most basic (like this one) to extravagant mappings of loaded
|
|
placeholder arguments. Enjoy!');
|
|
return '<div>' . $base_content . '</div><br /><div>' . $content . '</div>';
|
|
}
|
|
|
|
/**
|
|
* Page callback for use with most of the menu entries.
|
|
*
|
|
* The arguments it receives determine what it outputs.
|
|
*
|
|
* @param string $content
|
|
* The base content to output.
|
|
* @param string $arg1
|
|
* First additional argument from the path used to access the menu
|
|
* @param string $arg2
|
|
* Second additional argument.
|
|
*/
|
|
function _menu_example_menu_page($content = NULL, $arg1 = NULL, $arg2 = NULL) {
|
|
$output = '<div>' . $content . '</div>';
|
|
|
|
if (!empty($arg1)) {
|
|
$output .= '<div>' . t('Argument 1=%arg', array('%arg' => $arg1)) . '</div>';
|
|
}
|
|
if (!empty($arg2)) {
|
|
$output .= '<div>' . t('Argument 2=%arg', array('%arg' => $arg2)) . '</div>';
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_permission().
|
|
*
|
|
* Provides a demonstration access string.
|
|
*/
|
|
function menu_example_permission() {
|
|
return array(
|
|
'access protected menu example' => array(
|
|
'title' => t('Access the protected menu example'),
|
|
),
|
|
);
|
|
|
|
}
|
|
|
|
/**
|
|
* Determine whether the current user has the role specified.
|
|
*
|
|
* @param string $role_name
|
|
* The role required for access
|
|
*
|
|
* @return bool
|
|
* True if the acting user has the role specified.
|
|
*/
|
|
function menu_example_custom_access($role_name) {
|
|
$access_granted = in_array($role_name, $GLOBALS['user']->roles);
|
|
return $access_granted;
|
|
}
|
|
|
|
/**
|
|
* Utility function to provide mappings from integers to some strings.
|
|
*
|
|
* This would normally be some database lookup to get an object or array from
|
|
* a key.
|
|
*
|
|
* @param int $id
|
|
* The integer key.
|
|
*
|
|
* @return string
|
|
* The string to which the integer key mapped, or NULL if it did not map.
|
|
*/
|
|
function _menu_example_mappings($id) {
|
|
$mapped_value = NULL;
|
|
static $mappings = array(
|
|
1 => 'one',
|
|
2 => 'two',
|
|
3 => 'three',
|
|
99 => 'jackpot! default',
|
|
);
|
|
if (isset($mappings[$id])) {
|
|
$mapped_value = $mappings[$id];
|
|
}
|
|
return $mapped_value;
|
|
}
|
|
|
|
/**
|
|
* The special _load function to load menu_example.
|
|
*
|
|
* Given an integer $id, load the string that should be associated with it.
|
|
* Normally this load function would return an array or object with more
|
|
* information.
|
|
*
|
|
* @param int $id
|
|
* The integer to load.
|
|
*
|
|
* @return string
|
|
* A string loaded from the integer.
|
|
*/
|
|
function menu_example_id_load($id) {
|
|
// Just map a magic value here. Normally this would load some more complex
|
|
// object from the database or other context.
|
|
$mapped_value = _menu_example_mappings($id);
|
|
if (!empty($mapped_value)) {
|
|
return t('Loaded value was %loaded', array('%loaded' => $mapped_value));
|
|
}
|
|
else {
|
|
return t('Sorry, the id %id was not found to be loaded', array('%id' => $id));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_menu_alter().
|
|
*
|
|
* Changes the path 'examples/menu_example/menu_original_path' to
|
|
* 'examples/menu_example/menu_altered_path'.
|
|
* Changes the title callback of the 'user/UID' menu item.
|
|
*
|
|
* Change the path 'examples/menu_example/menu_original_path' to
|
|
* 'examples/menu_example/menu_altered_path'. This change will prevent the
|
|
* page from appearing at the original path (since the item is being unset).
|
|
* You will need to go to examples/menu_example/menu_altered_path manually to
|
|
* see the page.
|
|
*
|
|
* Remember that hook_menu_alter() only runs at menu_rebuild() time, not every
|
|
* time the page is built, so this typically happens only at cache clear time.
|
|
*
|
|
* The $items argument is the complete list of menu router items ready to be
|
|
* written to the menu_router table.
|
|
*/
|
|
function menu_example_menu_alter(&$items) {
|
|
if (!empty($items['examples/menu_example/menu_original_path'])) {
|
|
$items['examples/menu_example/menu_altered_path'] = $items['examples/menu_example/menu_original_path'];
|
|
$items['examples/menu_example/menu_altered_path']['title'] = 'Menu item altered by hook_menu_alter()';
|
|
unset($items['examples/menu_example/menu_original_path']);
|
|
}
|
|
|
|
// Here we will change the title callback to our own function, changing the
|
|
// 'user' link from the traditional to always being "username's account".
|
|
if (!empty($items['user/%user'])) {
|
|
$items['user/%user']['title callback'] = 'menu_example_user_page_title';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Title callback to rewrite the '/user' menu link.
|
|
*
|
|
* @param string $base_string
|
|
* string to be prepended to current user's name.
|
|
*/
|
|
function _menu_example_simple_title_callback($base_string) {
|
|
global $user;
|
|
$username = !empty($user->name) ? $user->name : t('anonymous');
|
|
return $base_string . ' ' . $username;
|
|
}
|
|
|
|
/**
|
|
* Title callback to rename the title dynamically, based on user_page_title().
|
|
*
|
|
* @param object $account
|
|
* User account related to the visited page.
|
|
*/
|
|
function menu_example_user_page_title($account) {
|
|
return is_object($account) ? t("@name's account", array('@name' => format_username($account))) : '';
|
|
}
|
|
|
|
/**
|
|
* Implements hook_menu_link_alter().
|
|
*
|
|
* This code will get the chance to alter a menu link when it is being saved
|
|
* in the menu interface at admin/build/menu. Whatever we do here overrides
|
|
* anything the user/administrator might have been trying to do.
|
|
*/
|
|
function menu_example_menu_link_alter(&$item, $menu) {
|
|
// Force the link title to remain 'Clear Cache' no matter what the admin
|
|
// does with the web interface.
|
|
if ($item['link_path'] == 'devel/cache/clear') {
|
|
$item['link_title'] = 'Clear Cache';
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Loads an item based on its $id.
|
|
*
|
|
* In this case we're just creating a more extensive string. In a real example
|
|
* we would load or create some type of object.
|
|
*
|
|
* @param int $id
|
|
* Id of the item.
|
|
*/
|
|
function menu_example_arg_optional_load($id) {
|
|
$mapped_value = _menu_example_mappings($id);
|
|
if (!empty($mapped_value)) {
|
|
return t('Loaded value was %loaded', array('%loaded' => $mapped_value));
|
|
}
|
|
else {
|
|
return t('Sorry, the id %id was not found to be loaded', array('%id' => $id));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Utility function to provide default argument for wildcard.
|
|
*
|
|
* A to_arg() function is used to provide a default for the arg in the
|
|
* wildcard. The purpose is to provide a menu link that will function if no
|
|
* argument is given. For example, in the case of the menu item
|
|
* 'examples/menu_example/default_arg/%menu_example_arg_optional' the third argument
|
|
* is required, and the menu system cannot make a menu link using this path
|
|
* since it contains a placeholder. However, when the to_arg() function is
|
|
* provided, the menu system will create a menu link pointing to the path
|
|
* which would be created with the to_arg() function filling in the
|
|
* %menu_example_arg_optional.
|
|
*
|
|
* @param string $arg
|
|
* The arg (URL fragment) to be tested.
|
|
*/
|
|
function menu_example_arg_optional_to_arg($arg) {
|
|
// If our argument is not provided, give a default of 99.
|
|
return (empty($arg) || $arg == '%') ? 99 : $arg;
|
|
}
|
|
/**
|
|
* @} End of "defgroup menu_example".
|
|
*/
|