book_menus.module in Book Menus 7
Functionality for book_menus.module.
File
book_menus.moduleView source
<?php
/**
* @file
* Functionality for book_menus.module.
*/
/**
* Implements hook_block_info().
*/
function book_menus_block_info() {
// Define the block;
$block = array();
$block['navigation']['info'] = t('Book Menus navigation');
$block['navigation']['cache'] = DRUPAL_CACHE_PER_PAGE | DRUPAL_CACHE_PER_ROLE;
// Return the renderable block.
return $block;
}
/**
* Implements hook_block_view().
*
* Main differences from core book.module
* - No "All Pages" (use core for that).
* - No shifting the tree to remove the first element.
* - Do not pass the book menu item to menu_tree_output (want full tree).
*/
function book_menus_block_view($delta = '') {
// Store the renderable block.
$block = array();
// Start with no bid.
$current_bid = 0;
// Try to get the node.
if ($node = menu_get_object()) {
// Check if this node had a book.
$current_bid = empty($node->book['bid']) ? 0 : $node->book['bid'];
}
// This node has a book.
if ($current_bid) {
// Only display this block when the user is browsing a book.
$select = db_select('node', 'n')
->fields('n', array(
'title',
))
->condition('n.nid', $node->book['bid'])
->addTag('node_access');
// Get the title.
$title = $select
->execute()
->fetchField();
// Only show the block if the user has view access for the top-level node.
if ($title) {
// Build the full menu tree.
$tree = menu_tree_all_data($node->book['menu_name']);
// Set title to the main book node.
$block['subject'] = $title;
// Add the tree.
$block['content'] = menu_tree_output($tree);
}
}
// Return the renderable block.
return $block;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function book_menus_form_book_admin_edit_alter(&$form, &$form_state) {
// Get the menu name.
$menu_name = !empty($form['#node']->book['menu_name']) ? $form['#node']->book['menu_name'] : FALSE;
// Should (will) always be a menu name.
if (!$menu_name) {
return NULL;
}
// See if this is a book_menus book.
if (in_array($menu_name, variable_get('book_menus', array()))) {
// Make sure the user has access.
if (!user_access('administer menu')) {
drupal_set_message(t('This is a Book Menu and you do not have the "administer menu" permission'), 'error');
return array();
}
// Go to the menu page instead.
drupal_goto('admin/structure/menu/manage/' . $menu_name);
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* The book admin settings form.
*/
function book_menus_form_book_admin_settings_alter(&$form, &$form_state) {
// Move actions below new element.
$form['actions']['#weight'] = 10;
// Start with empty message.
$form['book_menus'] = array(
'#prefix' => '<div class="form-item">',
'#suffix' => '</div>',
'#markup' => '<label>' . t('Book Menus') . '</label>' . t('Create some books first.'),
);
// Get all the books.
$books = book_get_books();
// Make sure there's some books.
if (count($books)) {
// Get the original defaults.
$book_menus_defaults = variable_get('book_menus', array());
// Save them for submission processing.
$form_state['storage']['book_menus_original'] = array_flip($book_menus_defaults);
// Change the form item to checkboxes.
$form['book_menus'] = array(
'#type' => 'checkboxes',
'#title' => t('Book Menus'),
'#description' => t('Select the books that should get an entry in the Drupal <a href="@menu_link">menu list</a>.', array(
'@menu_link' => base_path() . 'admin/structure/menu',
)),
'#default_value' => $book_menus_defaults,
'#options' => array(),
);
// Go through each book.
foreach ($books as $book) {
$form['book_menus']['#options'][$book['menu_name']] = $book['link_title'];
}
// Add a submission function.
$form['#submit'][] = 'book_menus_form_book_admin_settings_submit';
}
}
/**
* Submission callback for the book admin settings form.
*/
function book_menus_form_book_admin_settings_submit(&$form, &$form_state) {
// Get the original settings.
$book_menus_original = $form_state['storage']['book_menus_original'];
// Get the new settings.
$book_menus = $form_state['values']['book_menus'];
// Go through each settings.
foreach ($book_menus as $key => $value) {
// Was it checked in the new but not original.
if ($value !== 0 && !array_key_exists($key, $book_menus_original)) {
// Add the item to the custom menu table.
db_insert('menu_custom')
->fields(array(
'menu_name' => $key,
'title' => $form['book_menus']['#options'][$key],
'description' => '',
))
->execute();
// Rebuild the menus.
menu_rebuild();
}
elseif ($value === 0 && array_key_exists($key, $book_menus_original)) {
// Remove the record.
db_delete('menu_custom')
->condition('menu_name', $key)
->execute();
// Rebuild the menus.
menu_rebuild();
}
}
}
/**
* Implements hook_theme_registry_alter().
*
* Make our preprocess function run before book.module's.
*/
function book_menus_theme_registry_alter(&$theme_registry) {
// Make sure that the book navigation theme entry is present.
if (!empty($theme_registry['book_navigation']['preprocess functions'])) {
// Save the template function.
$template_function = 'template_preprocess_book_navigation';
// Get the current function order.
$functions_old = $theme_registry['book_navigation']['preprocess functions'];
// Make sure the one we want is in there.
if (!in_array($template_function, $functions_old)) {
// Functions not there, bail out.
return NULL;
}
// Get the template function index.
$index = array_search($template_function, $functions_old);
// Set the new order.
$theme_registry['book_navigation']['preprocess functions'] = array_merge(array_slice($functions_old, 0, $index), array(
'book_menus_preprocess_book_navigation_before',
), array_slice($functions_old, $index));
}
}
/**
* Custom preprocess called before book.module's.
*
* This needs to run before because we're hijacking the creation of the book
* tree so that "non-links" are not considered by book.module when creating
* the navigation.
*
* @see book_menus_theme_registry_alter
* @see template_preprocess_book_navigation
*/
function book_menus_preprocess_book_navigation_before(&$variables) {
// Get the book link.
$book_link = $variables['book_link'];
// Get the flat menu if there is one.
$flat =& drupal_static('book_get_flat_menu', array());
// Create the flat menu if there isn't one.
if (!isset($flat[$book_link['mlid']])) {
// Get the flat menu.
$flat[$book_link['mlid']] = book_menus_get_flat_menu($book_link);
// Remove any non-linked pages.
foreach ($flat[$book_link['mlid']] as $key => $value) {
if ($value['page_callback'] == 'drupal_not_found') {
unset($flat[$book_link['mlid']][$key]);
}
}
// Make sure the parent was a valid book page.
if (!array_key_exists($book_link['plid'], $flat[$book_link['mlid']])) {
// Setting to TRUE tricks book.module not to display the "up" link.
$variables['book_link']['plid'] = TRUE;
}
}
}
/**
* Gets the book menu tree for a page and returns it as a linear array.
*
* @param $book_link
* A fully loaded menu link that is part of the book hierarchy.
*
* @return
* A linear array of menu links in the order that the links are shown in the
* menu, so the previous and next pages are the elements before and after the
* element corresponding to the current node. The children of the current node
* (if any) will come immediately after it in the array, and links will only
* be fetched as deep as one level deeper than $book_link.
*/
function book_menus_get_flat_menu($book_link) {
$flat =& drupal_static(__FUNCTION__, array());
if (!isset($flat[$book_link['mlid']])) {
// Call menu_tree_all_data() to take advantage of the menu system's caching.
// Override book.module and remove the second parameter so we get the full
// book.
$tree = menu_tree_all_data($book_link['menu_name']);
$flat[$book_link['mlid']] = array();
_book_flatten_menu($tree, $flat[$book_link['mlid']]);
}
return $flat[$book_link['mlid']];
}
/**
* Implements hook_node_presave().
*
* Set the original parent for the book before book.module overwrites it.
*/
function book_menus_node_presave($node) {
// Check if this is a book menu node with a menu entry.
if (!empty($node->book['plid']) && $node->book['plid'] > 0 && !empty($node->book['bid']) && $node->book['bid'] > 0 && !empty($node->book['menu_name']) && in_array($node->book['menu_name'], variable_get('book_menus', array()))) {
// Save the original plid.
$node->original_plid = $node->book['plid'];
}
}
/**
* Implements hook_node_update().
*/
function book_menus_node_update($node) {
// Check if the original plid was set.
if (!empty($node->original_plid)) {
// book.module changes the plid if the plid wasn't a book item.
// Override that and set it to the original parent.
$node->book['plid'] = $node->original_plid;
// Save the menu link.
menu_link_save($node->book);
}
}
Functions
Name![]() |
Description |
---|---|
book_menus_block_info | Implements hook_block_info(). |
book_menus_block_view | Implements hook_block_view(). |
book_menus_form_book_admin_edit_alter | Implements hook_form_FORM_ID_alter(). |
book_menus_form_book_admin_settings_alter | Implements hook_form_FORM_ID_alter(). |
book_menus_form_book_admin_settings_submit | Submission callback for the book admin settings form. |
book_menus_get_flat_menu | Gets the book menu tree for a page and returns it as a linear array. |
book_menus_node_presave | Implements hook_node_presave(). |
book_menus_node_update | Implements hook_node_update(). |
book_menus_preprocess_book_navigation_before | Custom preprocess called before book.module's. |
book_menus_theme_registry_alter | Implements hook_theme_registry_alter(). |