menu_node.module in Menu Node API 6
Same filename and directory in other branches
Menu Node API Manages relationships between the {node} and {menu_links} table.
File
menu_node.moduleView source
<?php
/**
* @file
* Menu Node API
* Manages relationships between the {node} and {menu_links} table.
*/
/**
* Implements hook_nodeapi().
*/
function menu_node_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
$watch = array(
'insert',
'update',
'delete',
'load',
);
// Do we care about this node?
if (!in_array($op, $watch)) {
return;
}
// On delete operations, the menu item may be deleted before this
// runs, so ensure we have the data.
if ($op == 'load') {
// Ensure the menu object is loaded.
$node->menu_node_items = menu_node_get_links($node->nid);
}
$mlid = isset($node->menu['mlid']) ? $node->menu['mlid'] : NULL;
// If the node is being deleted, remove all records.
if ($op == 'delete') {
menu_node_delete($node);
}
else {
// If we have a record to insert, then do so now.
if (empty($node->menu['delete']) && !empty($mlid)) {
menu_node_save($node->nid, $mlid);
}
else {
if (!empty($mlid)) {
menu_node_delete($node->nid, $mlid);
}
}
}
}
/**
* Get the relevant node object for a menu item.
*
* @param $mlid
* The menu link id.
* @param $load
* Boolean value that indicates whether to return the node id or a full $node.
* @return
* A node id, a complete node object or FALSE on failure.
*/
function menu_node_get_node($mlid, $load = TRUE) {
$nid = db_result(db_query("SELECT n.nid FROM {node} n INNER JOIN {menu_node} mn ON n.nid = mn.nid WHERE mn.mlid = %d", $mlid));
if (empty($nid)) {
return FALSE;
}
if ($load) {
return node_load($nid);
}
return $nid;
}
/**
* Get the relevant menu links for a node.
* @param $nid
* The node id.
* @param $router
* Boolean flag indicating whether to attach the menu router item to the $item object.
* If set to TRUE, the router will be set as $item->menu_router.
* @return
* An array of complete menu_link objects or an empy array on failure.
*/
function menu_node_get_links($nid, $router = FALSE) {
$result = db_query("SELECT * FROM {menu_links} WHERE link_path = '%s'", 'node/' . $nid);
$items = array();
while ($data = db_fetch_object($result)) {
if ($router) {
$data->menu_router = menu_get_item('node/' . $nid);
}
$items[$data->mlid] = $data;
}
return $items;
}
/**
* Get all menu links assigned to a specific menu.
*
* @param $menu_name
* The machine name of the menu, e.g. 'navigation'.
* @return
* A simple array of menu link ids.
*/
function menu_node_get_links_by_menu($menu_name) {
$links = array();
$result = db_query("SELECT mlid FROM {menu_links} WHERE menu_name = '%s'", $menu_name);
while ($data = db_fetch_object($result)) {
$links[] = $data->mlid;
}
return $links;
}
/**
* Get all nodes assigned to a specific menu.
*
* @param $menu_name
* The machine name of the menu, e.g. 'navigation'.
* @param $load
* Boolean flag that indicates whether to load the node object or not.
* NOTE: This can be resource intensive!
* @return
* A simple array of node ids.
*/
function menu_node_get_nodes_by_menu($menu_name, $load = FALSE) {
$links = array();
$result = db_query("SELECT mn.nid FROM {menu_node} mn INNER JOIN {menu_links} ml ON mn.mlid = ml.mlid WHERE ml.menu_name = '%s'", $menu_name);
while ($data = db_fetch_object($result)) {
if ($load) {
$nodes[$data->nid] = node_load($data->nid);
}
else {
$nodes[] = $data->nid;
}
}
return $nodes;
}
/**
* Public function for generating a tree representation of nodes in a menu.
*
* This function is useful for showing the relationship between nodes within
* a given menu tree. It can be used to build options lists for forms and other
* user interface elements.
*
* @param $tree
* The parent menu tree, generated by menu_tree_all_data().
* @param $menu
* The name of the menu for which to return data.
* @param $filter
* An array of menu links ids that indicate the only children to return.
* That is, if this array is populated, only its members and their children will
* be returned by this function.
* @param $options
* An array of processing options. The valid options are 'marker' and 'spacer'.
* -- 'marker' indicates a text mark to indicate menu depth for a menu link.
* -- 'spacer' indicates the text string to insert betwen a marker and its link title.
* @return
* A nested array of menu data.
*/
function menu_node_tree($tree, $menu = NULL, $filter = array(), $options = array()) {
$options += array(
'marker' => '-',
'spacer' => ' ',
);
$data = array();
if (!empty($menu)) {
_menu_node_tree($data, $menu, $value, $filter, $options['marker'], $options['spacer']);
return $data[$menu];
}
else {
foreach ($tree as $key => $value) {
_menu_node_tree($data, $key, $value, $filter, $options['marker'], $options['spacer']);
}
}
return $data;
}
/**
* A private recursive sort function.
*
* Given a menu tree, return its child node items.
*
* @param $tree
* The recursive tree data.
* @param $menu
* The menu that this data belongs to.
* @param $data
* The tree data for this menu element.
* @param $parents
* An array of menu link ids indicating the tree elements to return.
* @param $marker
* A string (or NULL) to prepend to the menu link title, indicating relative depth.
* @param $spacer
* A string (or NULL) to place between the marker and the title.
* @return
* No return. Modify $tree by reference.
*/
function _menu_node_tree(&$tree, $menu, $data, $parents, $marker = NULL, $spacer = NULL) {
if (empty($tree)) {
$tree = array();
}
if (empty($parents)) {
$parents = array();
}
if (in_array($data['link']['mlid'], $parents)) {
$parent = menu_node_get_parent($data['link']);
$tree[$parent][$data['link']['mlid']] = str_repeat($marker, $data['link']['depth']) . $spacer . $data['link']['title'] . ' ';
}
if (!empty($data['below'])) {
// Recursive processing joy!
foreach ($data['below'] as $value) {
_menu_node_tree($tree, $menu, $value, $parents, $marker, $spacer);
}
}
}
/**
* Return the parent item of a menu element.
*
* @param $item
* The menu item.
* @param $return
* Indicates the value to return, options are:
* -- 'title' returns the name of the parent menu item.
* -- 'item' returns the entire parent, as loaded by menu_get_item().
* @return
* A string, representing the parent name or a menu object.
*/
function menu_node_get_parent($item, $return = 'title') {
if ($return == 'title') {
return db_result(db_query("SELECT link_title FROM {menu_links} WHERE mlid = %d", $item['p1']));
}
$path = db_result(db_query("SELECT link_path FROM {menu_links} WHERE mlid = %d", $item['p1']));
return menu_get_item($path);
}
/**
* Implements hook_form_alter().
*
* React to the editing of custom menu items.
*/
function menu_node_form_menu_edit_item_alter(&$form, $form_state) {
$form['#submit'][] = 'menu_node_edit_form_submit';
}
/**
* Implements hook_form_alter().
*
* React to the deletion of custom menu items.
*/
function menu_node_form_menu_item_delete_form_alter(&$form, $form_state) {
$form['mlid'] = array(
'#type' => 'value',
'#value' => $form['#item']['mlid'],
);
$form['#submit'][] = 'menu_node_delete_form_submit';
// Our submit _must_ be run first.
$form['#submit'] = array_reverse($form['#submit']);
}
/**
* Implements hook_form_alter().
*
* React to the deletion of entire menus.
*/
function menu_node_form_menu_delete_menu_confirm_alter(&$form, $form_state) {
$form['menu_name'] = array(
'#type' => 'value',
'#value' => $form['#menu']['menu_name'],
);
$form['#submit'][] = 'menu_node_delete_menu_form_submit';
// Our submit _must_ be run first.
$form['#submit'] = array_reverse($form['#submit']);
}
/**
* Custom form handler to react to menu changes.
*/
function menu_node_edit_form_submit($form, &$form_state) {
$menu = $form_state['values']['menu'];
// Is this a node item?
if (count($menu['parts']) == 2 && ($menu['parts'][0] = 'node' && is_numeric($menu['parts'][1]))) {
menu_node_save($menu['parts'][1], $menu['mlid']);
}
}
/**
* Save records to the {menu_node} table.
*
* After saving, we fire the appropriate menu_node hook,
* either 'insert' or 'update'.
*
* @param $nid
* The node id.
* @param $mlid
* The menu link id.
*/
function menu_node_save($nid, $mlid, $hook = 'update') {
$new = menu_node_exists($mlid);
$record = array(
'nid' => $nid,
'mlid' => $mlid,
);
// Save if the record does not exist, otherwise update the existing link
if (empty($new)) {
drupal_write_record('menu_node', $record);
$hook = 'insert';
}
else {
drupal_write_record('menu_node', $record, 'mlid');
}
_menu_node_invoke($nid, $mlid, $hook);
}
/**
* Wrapper function for module hooks.
*
* @param $nid
* The node id.
* @param $mlid
* The menu link id.
* @param $hook
* The hook to invoke ('insert', 'update', or 'delete').
*/
function _menu_node_invoke($nid, $mlid, $hook) {
// Use our internal lookup fuinctions.
$node = menu_node_get_node($mlid);
$items = menu_node_get_links($nid);
module_invoke_all('menu_node_' . $hook, $items[$mlid], $node);
}
/**
* Check to see if a specific mlid exists.
*
* @param $mlid
* The menu link id.
* @return
* The count of matches (which should be 1 or 0).
*/
function menu_node_exists($mlid) {
return db_result(db_query("SELECT COUNT(mlid) FROM {menu_node} WHERE mlid = %d", $mlid));
}
/**
* Custom form handler to react to menu item changes.
*/
function menu_node_delete_form_submit($form, &$form_state) {
$mlid = $form_state['values']['mlid'];
$node = menu_node_get_node($mlid, TRUE);
// Is this a node item?
if (!empty($node)) {
menu_node_delete($node);
}
}
/**
* Custom form handler to react to custom menu changes.
*/
function menu_node_delete_menu_form_submit($form, &$form_state) {
$menu_name = $form_state['values']['menu_name'];
$items = menu_node_get_links_by_menu($menu_name);
// We pass these individually in case any hook implementations care.
foreach ($items as $mlid) {
$node = menu_node_get_node($mlid, TRUE);
menu_node_delete($node);
}
}
/**
* Delete a record from {menu_node} and run hook_menu_node_delete().
*
* We deliberately run the hook before the delete, in case any module
* wishes to run a JOIN on the {menu_node} table.
*
* @param $node
* The node being deleted.
* @return
* No return. hook_menu_node_delete() is invoked.
*/
function menu_node_delete($node) {
if (!empty($node->menu_node_items)) {
foreach ($node->menu_node_items as $item) {
module_invoke_all('menu_node_delete', $item, $node);
}
}
db_query("DELETE FROM {menu_node} WHERE nid = %d", $node->nid);
}
Functions
Name | Description |
---|---|
menu_node_delete | Delete a record from {menu_node} and run hook_menu_node_delete(). |
menu_node_delete_form_submit | Custom form handler to react to menu item changes. |
menu_node_delete_menu_form_submit | Custom form handler to react to custom menu changes. |
menu_node_edit_form_submit | Custom form handler to react to menu changes. |
menu_node_exists | Check to see if a specific mlid exists. |
menu_node_form_menu_delete_menu_confirm_alter | Implements hook_form_alter(). |
menu_node_form_menu_edit_item_alter | Implements hook_form_alter(). |
menu_node_form_menu_item_delete_form_alter | Implements hook_form_alter(). |
menu_node_get_links | Get the relevant menu links for a node. |
menu_node_get_links_by_menu | Get all menu links assigned to a specific menu. |
menu_node_get_node | Get the relevant node object for a menu item. |
menu_node_get_nodes_by_menu | Get all nodes assigned to a specific menu. |
menu_node_get_parent | Return the parent item of a menu element. |
menu_node_nodeapi | Implements hook_nodeapi(). |
menu_node_save | Save records to the {menu_node} table. |
menu_node_tree | Public function for generating a tree representation of nodes in a menu. |
_menu_node_invoke | Wrapper function for module hooks. |
_menu_node_tree | A private recursive sort function. |