-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathmenu_example.module
549 lines (501 loc) · 22.4 KB
/
menu_example.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
<?php
/**
* @file
* Hook implementations for the Menu Example module.
*/
/**
* @defgroup menu_example Example: Menu
* @ingroup examples
* @{
* This example demonstrates how to use the menu API.
*
* The Page Example module is another module that show how to use 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' => 'user-menu',
'page callback' => '_menu_example_menu_page',
'page arguments' => array(t('This will be in the Primary Links 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'),
);
// 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,
);
// Backdrop 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,
);
foreach ($items as $path => $item) {
if (!isset($item['menu_name'])) {
$items[$path]['menu_name'] = 'menu-example-menu';
}
}
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. To view the full range of example menu links created by Menu Example, place the Menu example menu block into a layout region. There are a number of examples there, 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' => user_format_name($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".
*/