menu_example.module

  1. examples
    1. 6 menu_example/menu_example.module
    2. 7 menu_example/menu_example.module
    3. 8 menu_example/menu_example.module

Module file for menu_example.

Functions & methods

NameDescription
menu_example_arg_optional_loadLoads an item based on its $id.
menu_example_arg_optional_to_argA 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…
menu_example_id_loadThe special _load function to load menu_example.
menu_example_menuImplements hook_menu().
menu_example_menu_alterImplements hook_menu_alter().
menu_example_menu_link_alterImplements hook_menu_link_alter().
menu_example_permissionImplements hook_permission() to provide a demonstration access string.
menu_example_user_page_titleTitle callback to rename the title dynamically, based on user_page_title().
_menu_example_basic_instructionsPage callback for the simplest introduction menu entry.
_menu_example_mappingsUtility 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.
_menu_example_menu_pagePage callback for use with most of the menu entries. The arguments it receives determine what it outputs.
_menu_example_simple_title_callbackTitle callback to rewrite the '/user' menu link.

File

menu_example/menu_example.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * Module file for menu_example.
  5. */
  6. /**
  7. * @defgroup menu_example Example: Menu
  8. * @ingroup examples
  9. * @{
  10. * Demonstrates uses of the Menu APIs in Drupal.
  11. *
  12. * The Page Example module also talks about the menu system, as well
  13. * as how to use menu arguments to generate pages.
  14. *
  15. * @see hook_menu()
  16. * @see hook_menu_alter()
  17. * @see hook_menu_link_alter()
  18. * @see page_example
  19. * @see page_example_menu()
  20. */
  21. /**
  22. * Implements hook_menu().
  23. */
  24. function menu_example_menu() {
  25. // A simple example which defines a page callback and a menu entry.
  26. // Menu items are defined by placing them in an $items array. The array key
  27. // (in this case 'menu_example') is the path that defines the menu router
  28. // entry, so the page will be accessible from the URL
  29. // example.com/menu_example.
  30. $items['menu_example'] = array(
  31. // We are using the default menu type, so this can be omitted.
  32. // 'type' => MENU_NORMAL_ITEM,
  33. // The menu title. Do NOT use t() which is called by default. You can
  34. // override the use of t() by defining a 'title callback'. This is explained
  35. // in the 'menu_example/title_callbacks' example below.
  36. 'title' => 'Menu Example',
  37. // Description (hover flyover for menu link). Does NOT use t(), which is
  38. // called automatically.
  39. 'description' => 'Simplest possible menu type, and the parent menu entry for others',
  40. // Function to be called when this path is accessed.
  41. 'page callback' => '_menu_example_basic_instructions',
  42. // Arguments to the page callback. Here's we'll use them just to provide
  43. // content for our page.
  44. '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('menu_example/path_only')))),
  45. // If the page is meant to be accessible to all users, you can set 'access
  46. // callback' to TRUE. This bypasses all access checks. For an explanation on
  47. // how to use the permissions system to restrict access for certain users,
  48. // see the example 'menu_example/permissioned/controlled' below.
  49. 'access callback' => TRUE,
  50. // If the page callback is located in another file, specify it here and
  51. // that file will be automatically loaded when needed.
  52. // 'file' => 'menu_example.module',
  53. // We can choose which menu gets the link. The default is 'navigation'.
  54. // 'menu_name' => 'navigation',
  55. // Show the menu link as expanded.
  56. 'expanded' => TRUE,
  57. );
  58. // Show a menu link in a menu other than the default "Navigation" menu.
  59. // The menu must already exist.
  60. $items['menu_example_alternate_menu'] = array(
  61. 'title' => 'Menu Example: Menu in alternate menu',
  62. // Machine name of the menu in which the link should appear.
  63. 'menu_name' => 'primary-links',
  64. 'page callback' => '_menu_example_menu_page',
  65. 'page arguments' => array(t('This will be in the Primary Links menu instead of the default Navigation menu')),
  66. 'access callback' => TRUE,
  67. );
  68. // A menu entry with simple permissions using user_access().
  69. // First, provide a courtesy menu item that mentions the existence of the
  70. // permissioned item.
  71. $items['menu_example/permissioned'] = array(
  72. 'title' => 'Permissioned Example',
  73. 'page callback' => '_menu_example_menu_page',
  74. 'page arguments' => array(t('A menu item that requires the "access protected menu example" permission is at <a href="!link">menu_example/permissioned/controlled</a>', array('!link' => url('menu_example/permissioned/controlled')))),
  75. 'access callback' => TRUE,
  76. 'expanded' => TRUE,
  77. );
  78. // Now provide the actual permissioned menu item.
  79. $items['menu_example/permissioned/controlled'] = array(
  80. // The title - do NOT use t() as t() is called automatically.
  81. 'title' => 'Permissioned Menu Item',
  82. 'description' => 'This menu entry will not show and the page will not be accessible without the "access protected menu example" permission.',
  83. 'page callback' => '_menu_example_menu_page',
  84. 'page arguments' => array(t('This menu entry will not show and the page will not be accessible without the "access protected menu example" permission.')),
  85. // For a permissioned menu entry, we provide an access callback which
  86. // determines whether the current user should have access. The default is
  87. // user_access(), which we'll use in this case. Since it's the default,
  88. // we don't even have to enter it.
  89. // 'access callback' => 'user_access',
  90. // The 'access arguments' are passed to the 'access callback' to help it
  91. // do its job. In the case of user_access(), we need to pass a permission
  92. // as the first argument.
  93. 'access arguments' => array('access protected menu example'),
  94. // The optional weight element tells how to order the submenu items.
  95. // Higher weights are "heavier", dropping to the bottom of the menu.
  96. 'weight' => 10,
  97. );
  98. // A menu router entry with no menu link. This could be used any time we
  99. // don't want the user to see a link in the menu. Otherwise, it's the same
  100. // as the "simplest" entry above. MENU_CALLBACK is used for all menu items
  101. // which don't need a visible menu link, including services and other pages
  102. // that may be linked to but are not intended to be accessed directly.
  103. // First, provide a courtesy link in the menu so people can find this.
  104. $items['menu_example/path_only'] = array(
  105. 'title' => 'MENU_CALLBACK example',
  106. 'page callback' => '_menu_example_menu_page',
  107. 'page arguments' => array(t('A menu entry with no menu link (MENU_CALLBACK) is at <a href="!link">!link</a>', array('!link' => url('menu_example/path_only/callback')))),
  108. 'access callback' => TRUE,
  109. 'weight' => 20,
  110. );
  111. $items['menu_example/path_only/callback'] = array(
  112. // A type of MENU_CALLBACK means leave the path completely out of the menu
  113. // links.
  114. 'type' => MENU_CALLBACK,
  115. // The title is still used for the page title, even though it's not used
  116. // for the menu link text, since there's no menu link.
  117. 'title' => 'Callback Only',
  118. 'page callback' => '_menu_example_menu_page',
  119. '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.')),
  120. 'access callback' => TRUE,
  121. );
  122. // A menu entry with tabs.
  123. // For tabs we need at least 3 things:
  124. // 1. A parent MENU_NORMAL_ITEM menu item (menu_example/tabs in this
  125. // example.)
  126. // 2. A primary tab (the one that is active when we land on the base menu).
  127. // This tab is of type MENU_DEFAULT_LOCAL_TASK.
  128. // 3. Some other menu entries for the other tabs, of type MENU_LOCAL_TASK.
  129. $items['menu_example/tabs'] = array(
  130. // 'type' => MENU_NORMAL_ITEM, // Not necessary since this is the default.
  131. 'title' => 'Tabs',
  132. 'description' => 'Shows how to create primary and secondary tabs',
  133. 'page callback' => '_menu_example_menu_page',
  134. 'page arguments' => array(t('This is the "tabs" menu entry.')),
  135. 'access callback' => TRUE,
  136. 'weight' => 30,
  137. );
  138. // For the default local task, we need very little configuration, as the
  139. // callback and other conditions are handled by the parent callback.
  140. $items['menu_example/tabs/default'] = array(
  141. 'type' => MENU_DEFAULT_LOCAL_TASK,
  142. 'title' => 'Default primary tab',
  143. 'weight' => 1,
  144. );
  145. // Now add the rest of the tab entries.
  146. foreach (array(t('second') => 2, t('third') => 3, t('fourth') => 4) as $tabname => $weight) {
  147. $items["menu_example/tabs/$tabname"] = array(
  148. 'type' => MENU_LOCAL_TASK,
  149. 'title' => $tabname,
  150. 'page callback' => '_menu_example_menu_page',
  151. 'page arguments' => array(t('This is the tab "@tabname" in the "basic tabs" example', array('@tabname' => $tabname))),
  152. 'access callback' => TRUE,
  153. // The weight property overrides the default alphabetic ordering of menu
  154. // entries, allowing us to get our tabs in the order we want.
  155. 'weight' => $weight,
  156. );
  157. }
  158. // Finally, we'll add secondary tabs to the default tab of the tabs entry.
  159. // The default local task needs very little information.
  160. $items['menu_example/tabs/default/first'] = array(
  161. 'type' => MENU_DEFAULT_LOCAL_TASK,
  162. 'title' => 'Default secondary tab',
  163. // The additional page callback and related items are handled by the
  164. // parent menu item.
  165. );
  166. foreach (array(t('second'), t('third')) as $tabname) {
  167. $items["menu_example/tabs/default/$tabname"] = array(
  168. 'type' => MENU_LOCAL_TASK,
  169. 'title' => $tabname,
  170. 'page callback' => '_menu_example_menu_page',
  171. 'page arguments' => array(t('This is the secondary tab "@tabname" in the "basic tabs" example "default" tab', array('@tabname' => $tabname))),
  172. 'access callback' => TRUE,
  173. );
  174. }
  175. // All the portions of the URL after the base menu are passed to the page
  176. // callback as separate arguments, and can be captured by the page callback
  177. // in its argument list. Our _menu_example_menu_page() function captures
  178. // arguments in its function signature and can output them.
  179. $items['menu_example/use_url_arguments'] = array(
  180. 'title' => 'Extra Arguments',
  181. 'description' => 'The page callback can use the arguments provided after the path used as key',
  182. 'page callback' => '_menu_example_menu_page',
  183. '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('menu_example/use_url_arguments/one/two'), '!link2' => url('menu_example/use_url_arguments/firstarg/secondarg')))),
  184. 'access callback' => TRUE,
  185. 'weight' => 40,
  186. );
  187. // The menu title can be dynamically created by using the 'title callback'
  188. // which by default is t(). Here we provide a title callback which adjusts
  189. // the menu title based on the current user's username.
  190. $items['menu_example/title_callbacks'] = array(
  191. 'title callback' => '_menu_example_simple_title_callback',
  192. 'title arguments' => array(t('Dynamic title: username=')),
  193. 'description' => 'The title of this menu item is dynamically generated',
  194. 'page callback' => '_menu_example_menu_page',
  195. 'page arguments' => array(t('The menu title is dynamically changed by the title callback')),
  196. 'access callback' => TRUE,
  197. 'weight' => 50,
  198. );
  199. // Sometimes we need to capture a specific argument within the menu path,
  200. // as with the menu entry 'menu_example/placeholder_argument/3333/display',
  201. // where we need to capture the "3333". In that case, we use a placeholder in
  202. // the path provided in the menu entry. The (odd) way this is done is by using
  203. // array(numeric_position_value) as the value for 'page arguments'. The
  204. // numeric_position_value is the zero-based index of the portion of the URL
  205. // which should be passed to the 'page callback'.
  206. // First we provide a courtesy link with information on how to access
  207. // an item with a placeholder.
  208. $items['menu_example/placeholder_argument'] = array(
  209. 'title' => 'Placeholder Arguments',
  210. 'page callback' => '_menu_example_menu_page',
  211. 'page arguments' => array(t('Demonstrate placeholders by visiting <a href="!link">menu_example/placeholder_argument/3343/display</a>', array('!link' => url('menu_example/placeholder_argument/3343/display')))),
  212. 'access callback' => TRUE,
  213. 'weight' => 60,
  214. );
  215. // Now the actual entry.
  216. $items['menu_example/placeholder_argument/%/display'] = array(
  217. 'title' => 'Placeholder Arguments',
  218. 'page callback' => '_menu_example_menu_page',
  219. // Pass the value of '%', which is zero-based argument 2, to the
  220. // 'page callback'. So if the URL is
  221. // 'menu_example/placeholder_argument/333/display' then the value 333
  222. // will be passed into the 'page callback'.
  223. 'page arguments' => array(2),
  224. 'access callback' => TRUE,
  225. );
  226. // Drupal provides magic placeholder processing as well, so if the placeholder
  227. // is '%menu_example_arg_optional', the function
  228. // menu_example_arg_optional_load($arg) will be called to translate the path
  229. // argument to a more substantial object. $arg will be the value of the
  230. // placeholder. Then the return value of menu_example_id_load($arg) will be
  231. // passed to the 'page callback'.
  232. // In addition, if (in this case) menu_example_arg_optional_to_arg() exists,
  233. // then a menu link can be created using the results of that function as a
  234. // default for %menu_example_arg_optional.
  235. $items['menu_example/default_arg/%menu_example_arg_optional'] = array(
  236. 'title' => 'Processed Placeholder Arguments',
  237. 'page callback' => '_menu_example_menu_page',
  238. 'page arguments' => array(2), // arg 2 (3rd arg) is the one we want.
  239. 'access callback' => TRUE,
  240. 'weight' => 70,
  241. );
  242. $items['menu_example/menu_original_path'] = array(
  243. 'title' => 'Menu path that will be altered by hook_menu_alter()',
  244. 'page callback' => '_menu_example_menu_page',
  245. '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 menu_example/menu_original_path. The hook_menu_alter() changes it to menu_example/menu_altered_path. You can try navigating to both paths and see what happens!')),
  246. 'access callback' => TRUE,
  247. 'weight' => 80,
  248. );
  249. return $items;
  250. }
  251. /**
  252. * Page callback for the simplest introduction menu entry.
  253. *
  254. * @param $content
  255. * Some content passed in.
  256. */
  257. function _menu_example_basic_instructions($content = NULL) {
  258. $base_content = t(
  259. 'This is the base page of the Menu Example. There are a number of examples
  260. here, from the most basic (like this one) to extravagant mappings of loaded
  261. placeholder arguments. Enjoy!');
  262. return '<div>' . $base_content . '</div><br /><div>' . $content . '</div>';
  263. }
  264. /**
  265. * Page callback for use with most of the menu entries. The arguments it
  266. * receives determine what it outputs.
  267. *
  268. * @param $content
  269. * The base content to output.
  270. * @param $arg1
  271. * First additional argument from the path used to access the menu
  272. * @param $arg2
  273. * Second additional argument.
  274. */
  275. function _menu_example_menu_page($content = NULL, $arg1 = NULL, $arg2 = NULL) {
  276. $output = '<div>' . $content . '</div>';
  277. if (!empty($arg1)) {
  278. $output .= '<div>' . t('Argument 1=%arg', array('%arg' => $arg1)) . '</div>';
  279. }
  280. if (!empty($arg2)) {
  281. $output .= '<div>' . t('Argument 2=%arg', array('%arg' => $arg2)) . '</div>';
  282. }
  283. return $output;
  284. }
  285. /**
  286. * Implements hook_permission() to provide a demonstration access string.
  287. */
  288. function menu_example_permission() {
  289. return array(
  290. 'access protected menu example' => array(
  291. 'title' => t('Access the protected menu example'),
  292. ),
  293. );
  294. }
  295. /**
  296. * Utility function to provide mappings from integers to some strings.
  297. * This would normally be some database lookup to get an object or array from
  298. * a key.
  299. *
  300. * @param $id
  301. *
  302. * @return
  303. * The string to which the integer key mapped, or NULL if it did not map.
  304. */
  305. function _menu_example_mappings($id) {
  306. $mapped_value = NULL;
  307. static $mappings = array(
  308. 1 => 'one',
  309. 2 => 'two',
  310. 3 => 'three',
  311. 99 => 'jackpot! default',
  312. );
  313. if (isset($mappings[$id])) {
  314. $mapped_value = $mappings[$id];
  315. }
  316. return $mapped_value;
  317. }
  318. /**
  319. * The special _load function to load menu_example.
  320. *
  321. * Given an integer $id, load the string that should be associated with it.
  322. * Normally this load function would return an array or object with more
  323. * information.
  324. *
  325. * @param $id
  326. * The integer to load.
  327. *
  328. * @return
  329. * A string loaded from the integer.
  330. */
  331. function menu_example_id_load($id) {
  332. // Just map a magic value here. Normally this would load some more complex
  333. // object from the database or other context.
  334. $mapped_value = _menu_example_mappings($id);
  335. if (!empty($mapped_value)) {
  336. return t('Loaded value was %loaded', array('%loaded' => $mapped_value));
  337. }
  338. else {
  339. return t('Sorry, the id %id was not found to be loaded', array('%id' => $id));
  340. }
  341. }
  342. /**
  343. * Implements hook_menu_alter().
  344. *
  345. * Changes the path 'menu_example/menu_original_path' to 'menu_example/menu_altered_path'.
  346. * Changes the title callback of the 'user/UID' menu item.
  347. *
  348. * Remember that hook_menu_alter() only runs at menu_rebuild() time, not every
  349. * time the page is built, so this typically happens only at cache clear time.
  350. *
  351. * @param $items
  352. * The complete list of menu router items ready to be written to the
  353. * menu_router table.
  354. */
  355. function menu_example_menu_alter(&$items) {
  356. // Change the path 'menu_example/menu_original_path' to 'menu_example/menu_altered_path'. This change will
  357. // prevent the page from appearing at the original path (since the item is being unset).
  358. // You will need to go to menu_example/menu_altered_path manually to see the page.
  359. if (!empty($items['menu_example/menu_original_path'])) {
  360. $items['menu_example/menu_altered_path'] = $items['menu_example/menu_original_path'];
  361. $items['menu_example/menu_altered_path']['title'] = 'Menu item altered by hook_menu_alter()';
  362. unset($items['menu_example/menu_original_path']);
  363. }
  364. // Here we will change the title callback to our own function, changing the
  365. // 'user' link from the traditional to always being "username's account".
  366. if (!empty($items['user/%user'])) {
  367. $items['user/%user']['title callback'] = 'menu_example_user_page_title';
  368. }
  369. }
  370. /**
  371. * Title callback to rewrite the '/user' menu link.
  372. *
  373. * @param $base_string
  374. * string to be prepended to current user's name.
  375. */
  376. function _menu_example_simple_title_callback($base_string) {
  377. global $user;
  378. $username = !empty($user->name) ? $user->name : t('anonymous');
  379. return $base_string . ' ' . $username;
  380. }
  381. /**
  382. * Title callback to rename the title dynamically, based on user_page_title().
  383. *
  384. * @param $account
  385. * User account related to the visited page.
  386. */
  387. function menu_example_user_page_title($account) {
  388. return is_object($account) ? t("@name's account", array('@name' => format_username($account))) : '';
  389. }
  390. /**
  391. * Implements hook_menu_link_alter().
  392. *
  393. * This code will get the chance to alter a menu link when it is being saved
  394. * in the menu interface at admin/build/menu. Whatever we do here overrides
  395. * anything the user/administrator might have been trying to do.
  396. *
  397. * @param $item
  398. * The menu item being saved.
  399. * @param $menu
  400. * The entire menu router table.
  401. */
  402. function menu_example_menu_link_alter(&$item, $menu) {
  403. // Force the link title to remain 'Clear Cache' no matter what the admin
  404. // does with the web interface.
  405. if ($item['link_path'] == 'devel/cache/clear') {
  406. $item['link_title'] = 'Clear Cache';
  407. };
  408. }
  409. /**
  410. * Loads an item based on its $id.
  411. *
  412. * In this case we're just creating a more extensive string. In a real example
  413. * we would load or create some type of object.
  414. *
  415. * @param $id
  416. */
  417. function menu_example_arg_optional_load($id) {
  418. $mapped_value = _menu_example_mappings($id);
  419. if (!empty($mapped_value)) {
  420. return t('Loaded value was %loaded', array('%loaded' => $mapped_value));
  421. }
  422. else {
  423. return t('Sorry, the id %id was not found to be loaded', array('%id' => $id));
  424. }
  425. }
  426. /**
  427. * A to_arg() function is used to provide a default for the arg in the
  428. * wildcard. The purpose is to provide a menu link that will function if no
  429. * argument is given. For example, in the case of the menu item
  430. * 'menu_example/default_arg/%menu_example_arg_optional' the third argument
  431. * is required, and the menu system cannot make a menu link using this path
  432. * since it contains a placeholder. However, when the to_arg() function is
  433. * provided, the menu system will create a menu link pointing to the path
  434. * which would be created with the to_arg() function filling in the
  435. * %menu_example_arg_optional.
  436. *
  437. * @param $arg
  438. * The arg (URL fragment) to be tested.
  439. */
  440. function menu_example_arg_optional_to_arg($arg) {
  441. // If our argument is not provided, give a default of 99.
  442. return (empty($arg) || $arg == '%') ? 99 : $arg;
  443. }
  444. /**
  445. * @} End of "defgroup menu_example".
  446. */
Login or register to post comments