選單的建立則須實作 hook_menu() , 說明如下 (當選單內容異動後, 須 清除系統快取 一次)
常用類型為
► 權限管控參數 access callback
►動態/多語系選單名稱 (選單參數 titles 或 descriptions 不要使用 t() )
要達成動態或多語系的選單名稱, 正確的方式是使用 'title callback' 參數, 藉由呼叫 function 來進行. 而 description 系統本就會自動進行t()的轉換程序.
► 萬用字元 % 的運用
選單 % 的解析, URL的path 符合越完整則系統會觸發該項選單
注意 : 當有使用萬用字元, 而指定的 callback 有需要傳入path內參數時最好使用 'page arguments' => array() 來指定要帶入哪些參數, 否則會會因$items['KEY-Path'] 中 KEY-Path 的內容不同, 傳入的第一個參數位置也有所不同, 如
$items['menufun/%/%'] 若無指定 page arguments 時,
當 example.com/menufun/p1/p2/p3/p4 請求時傳入的第一個參數為 p3 而不是 p1,
也就是說無指定 page arguments 時, 傳入的第一個參數為扣除 KEY-Path 內容後的第一個位置為第一個參數.
而使用 'page arguments' => array(1, 2) array內指定的index順序不會因為KEY內容而有所變化, 1則為 p1, 2則為p2.
► 名稱式萬用字元 %NAME 的運用
若選單 KEY-Path 設定如 $items['menufun/%name/%'] 的方式, 除 % 外還後接英文字母, 則雖 %name 仍是為一個萬用字元%同樣效用外, 系統會自動呼叫 %NAME_to_arg($arg, $map, $index) 與 %NAME_load($arg, $map, $index) 這兩個函式.
注意 : 使用名稱式萬用字元至少必須存在 _to_arg() 或 _load() 其中一個函式, 否則該選單永遠不會有效
►變更其他模組的選單參數
►變更選單連結資料
► 頁面內選單
常用類型為
MENU_CALLBACK: 建立 URL 的請求路徑模式, 通常不會自動出現在系統選單內.
MENU_NORMAL_ITEM: 該模式選單會自動呈現在 系統的導覽 選單區塊內.
MENU_NORMAL_ITEM: 該模式選單會自動呈現在 系統的導覽 選單區塊內.
// Implementation of hook_menu() function menufun_menu() { $items['menufun'] = array( // example.com/menufun, Key 則為URL的請求路徑 'title' => 'Greeting', 'page callback' => 'menufun_hello', //呼叫 function menufun_hello //'page arguments' => array('參數1', 3), //$para1 = '參數1', $para2 = path第三位置的內容 //'page arguments' => array(1), //若指定的參數個數沒有填滿function 參數的數目, 當path還有參數可取得時系統會在自動傳入 'access callback' => TRUE, //選單權限管控 Defaults to user_access() 'type' => MENU_CALLBACK, //'file' => 'menufun_greeting.inc', //告訴系統 function 所在的檔案 ); $items['menufun1'] = array( 'title' => 'Navigation-Menu', //選單顯示標題 'page callback' => 'menufun_hello', 'access callback' => TRUE, 'type' => MENU_NORMAL_ITEM, //直接出現在導覽選單內 ); $items['menufun1/child'] = array( // 子選單模式, parentKey/childKey 'title' => 'Menu-child', 'page callback' => 'menufun_hello', 'access callback' => TRUE, 'type' => MENU_NORMAL_ITEM, ); return $items; } /** Page callback. * example.com/menufun => $para1 = '', $para2 = '' * example.com/menufun/p1 => $para1 = 'p1', $para2 = '' * example.com/menufun/p1/p2 => $para1 = 'p1', $para2 = 'p2' * example.com/menufun/p1/p2/p3 => $para1 = 'p1', $para2 = 'p2' p3 無用 * 設定 'page arguments' => array('固定', 1) => example.com/menufun/p1/p2 => $para1 = '固定', $para2 = 'p1' */ function menufun_hello($para1 = '', $para2 = '') { return t('Hello @para1 @para2', array('@para1' => $para1, '@para2' => $para2)); }
► 權限管控參數 access callback
function menufun_menu() { ... $items['menufun1/child'] = array(// 子選單模式, parentKey/childKey 'title' => 'Menu-child', 'page callback' => 'menufun_hello', //'access callback' => 'user_access', //告訴系統透過 function user_access() 來進行權限檢驗, 此為預設 'access arguments' => array('receive greeting'), //許可權限項目 'type' => MENU_NORMAL_ITEM, ); return $items; } /** * Implementation of hook_permission() * 權限的檢查機制一般透過 user_access() 進行, 傳回 TRUE 則表示具有權限 */ function menufun_permission() { return array( 'receive greeting' => array( // 定義權限項目 'title' => t('Receive a greeting'), 'description' => t('Allow users receive a greeting message'), ), ); }
►動態/多語系選單名稱 (選單參數 titles 或 descriptions 不要使用 t() )
要達成動態或多語系的選單名稱, 正確的方式是使用 'title callback' 參數, 藉由呼叫 function 來進行. 而 description 系統本就會自動進行t()的轉換程序.
function menufun_menu() { ... $items['menufun1/child'] = array( 'title' => 'Menu-child', 'title callback' => 'menufun_title', //call function 來產生選單標題 'page callback' => 'menufun_hello', 'type' => MENU_NORMAL_ITEM, ); return $items; } // Title callback function menufun_title() { drupal_set_title(t('The page title'));//指定標題內容, 一般頁面標題內容通常為選單 title 內容 $now = format_date(time()); return t('It is now @time', array('@time' => $now)); }
► 萬用字元 % 的運用
選單 % 的解析, URL的path 符合越完整則系統會觸發該項選單
$items['menufun'] << example.com/menufun 無%
$items['menufun/%'] << example.com/menufun/p1 表示至少須有一個參數, 符合則觸發此選單的 callback
$items['menufun/%/bb/%'] << example.com/menufun/p1/bb/p3 至少須有三個參數, 但第二個須為 bb
URL 的參數 index, 如 example.com/menufun/p1/p2/p3/p4, 則參數0:menufun, 參數1:p1, 參數2:p2, 參數3:p3, 參數4:p4, 這順序規則是固定不變, 所以選單中使用 'page arguments' => array(1, 3), 則callback時指定傳入的第一個參數是p1, 第二個參數是p3.$items['menufun/%'] << example.com/menufun/p1 表示至少須有一個參數, 符合則觸發此選單的 callback
$items['menufun/%/bb/%'] << example.com/menufun/p1/bb/p3 至少須有三個參數, 但第二個須為 bb
注意 : 當有使用萬用字元, 而指定的 callback 有需要傳入path內參數時最好使用 'page arguments' => array() 來指定要帶入哪些參數, 否則會會因$items['KEY-Path'] 中 KEY-Path 的內容不同, 傳入的第一個參數位置也有所不同, 如
$items['menufun/%/%'] 若無指定 page arguments 時,
當 example.com/menufun/p1/p2/p3/p4 請求時傳入的第一個參數為 p3 而不是 p1,
也就是說無指定 page arguments 時, 傳入的第一個參數為扣除 KEY-Path 內容後的第一個位置為第一個參數.
而使用 'page arguments' => array(1, 2) array內指定的index順序不會因為KEY內容而有所變化, 1則為 p1, 2則為p2.
► 名稱式萬用字元 %NAME 的運用
若選單 KEY-Path 設定如 $items['menufun/%name/%'] 的方式, 除 % 外還後接英文字母, 則雖 %name 仍是為一個萬用字元%同樣效用外, 系統會自動呼叫 %NAME_to_arg($arg, $map, $index) 與 %NAME_load($arg, $map, $index) 這兩個函式.
呼叫順序 _load() ► _to_arg() ► _load() , _load() 被呼叫兩次為何如此??? 尚須再研究function menufun_menu() { ... $items['menufun/aa/%para_name'] = array(//使用 %name 萬用字元, 須配合 _to_arg()或 _load() 此選單才會有效 'title' => 'Greeting3', 'load arguments' => array(2), // call function %PARA-NAME_load 時額外要傳入的參數 'page callback' => 'menufun_hello', //呼叫 function menufun_hello 'page arguments' => array(1),// example.com/menufun/a/b/c 則傳入參數為 a, c兩個, a為array(1)指定, c 為系統傳入 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); return $items; } //$arg : URL path %para_name 位置的參數內容, 系統固定自動傳入. //$index : 指出 $arg 內容位於 URL path 參數的位置, 也等同 $map 參數陣列位置, 此例 %index=2 //$map : 將 URL path 參數項目以陣列形式傳入.(e.g. array('node','123','edit') for 'node/123/edit') //需使用 $map, $index 參數內容, 將函式宣告成 para_name_to_arg($arg, $map, $index) 形式,系統自動傳入 function para_name_to_arg($arg) { //主要發生在系統要產生選單連結時會呼叫 //return empty($arg) || $arg == '%' ? $GLOBALS['user']->uid : $arg; return 'arg'; //提供 %para_name 內容,除讓系統可以自動產生導覽選單項目外,亦可動態變換內容 } //僅$arg系統會傳入內容同 _to_arg(), 需額外傳入參數則由 load arguments 設定 //特殊指定參數 'load arguments' => array('%map', '%index'), // function para_name_load($arg, $map, $index), 則 $map, $index 內容同 _to_arg() function para_name_load($arg) { //選單被調用時系統會呼叫並可將路徑參數傳入 //資料處理 }
注意 : 使用名稱式萬用字元至少必須存在 _to_arg() 或 _load() 其中一個函式, 否則該選單永遠不會有效
►變更其他模組的選單參數
變更前 logout 選單資料內容/** * Implementation of hook_menu_alter(). 變更其他模組選單參數資料 * @param array $items * Menu items keyed by path. */ function menufun_menu_alter(&$items) { // 變更 'user_logout' callback 到自己的 callback. $items['logout']['page callback'] = 'menufun_user_logout'; // 原始 callback 的 function 是指向 user.pages.inc 內搜索 unset($items['logout']['file']); } function menufun_user_logout() { global $user; watchdog('menufun', 'Session closed for %name.', array('%name' => $user->name)); }
array(
'file' => 'user.pages.inc',
'module' => 'user',
'page callback' => 'user_logout',
...
變更後 logout 選單資料內容
'file' => 'user.pages.inc',
'module' => 'user',
'page callback' => 'user_logout',
...
array(
'module' => 'user',
'page callback' => 'menufun_user_logout',
...
'module' => 'user',
'page callback' => 'menufun_user_logout',
...
/** * Implements hook_menu_link_alter(). 選單連結資料儲存前可藉此更動 * @param $item Associative array defining a menu link as passed into menu_link_save() */ function menufun_menu_link_alter(&$item) { if ($item['link_path'] == 'user/logout') { $item['link_title'] = 'Sign off'; } }
問題 : 當有多個模組都去更動同一個選單時(hook_menu_alter, hook_menu_link_alter), 那優先順序是如何決定?
► 頁面內選單
使用注意function milkshake_menu() { $items['milkshake'] = array( //ROOT menu 'title' => 'Milkshake flavors', 'type' => MENU_NORMAL_ITEM, //MENU_CALLBACK, 'page callback' => 'milkshake_overview', ); $items['milkshake/list'] = array( 'title' => 'List DEFAULT TASK', 'type' => MENU_DEFAULT_LOCAL_TASK,//此型態 page callback 參數是無效的 //'page callback' => 'milkshake_overview', //無效的等同 parent menu 'weight' => 0, ); $items['milkshake/list/fruity'] = array( 'title' => 'Fruity TASK', 'type' => MENU_LOCAL_TASK, 'page callback' => 'milkshake_list', 'page arguments' => array(2), ); $items['milkshake/list/Candy'] = array( 'title' => 'Candy TASK', 'type' => MENU_LOCAL_TASK, 'page callback' => 'milkshake_list', 'page arguments' => array(2), ); $items['milkshake/list/Candy/Candy1'] = array( 'title' => 'Candy1 ACTION', 'type' => MENU_LOCAL_ACTION, 'page callback' => 'milkshake_list', 'page arguments' => array(3), ); $items['milkshake/list/Candy/Candy2'] = array( 'title' => 'Candy2 ACTION', 'type' => MENU_LOCAL_ACTION, 'page callback' => 'milkshake_list', 'page arguments' => array(3), ); $items['milkshake/add'] = array( 'title' => 'Add TASK', 'type' => MENU_LOCAL_TASK, 'page callback' => 'milkshake_add', 'weight' => 1, ); $items['milkshake/add/a1'] = array( 'title' => 'a1 TASK', 'type' => MENU_LOCAL_ACTION, 'page callback' => 'milkshake_add', ); $items['milkshake/add/a2'] = array( 'title' => 'a2 TASK', 'type' => MENU_LOCAL_ACTION, 'page callback' => 'milkshake_add', ); return $items; } function milkshake_overview() { return = t('The following flavors are available...'); } function milkshake_add() { return t('A handy form to add flavors might go here...'); } function milkshake_list($type) { return t('List @type flavors', array('@type' => $type)); }
- Root Menu 必須為 MENU_NORMAL_ITEM, 或 MENU_CALLBACK
- 同一層級僅有一個 _TASK item 時不會顯示, 單一item 採用 MENU_LOCAL_ACTION
- _TASK item 最多僅顯示到第二層級, 以後均不會顯示
- _ACTION 為單層次, 均會在頁面顯示下一層, 深度無限制
- _ACTION 若在第二層以後, 當點選時若 root 層為 _TASK, 其tab選單將不在繼續顯示
- _ACTION 若在第一層, 當點選時若 root 層為 _TASK, 其tab選單仍會繼續顯示