You are here

og_menu_single.module in OG Menu Single 7

Creates a single menu per organic group on a site.

File

og_menu_single.module
View source
<?php

/**
 * @file
 * Creates a single menu per organic group on a site.
 */

// Name of the menu the links are stored in.
define('OG_MENU_SINGLE_MENU_NAME', 'og-menu-single');

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function og_menu_single_form_node_type_form_alter(&$form, $form_state) {
  $type = $form['#node_type']->type;
  $form['menu']['og_menu_single'] = array(
    '#type' => 'fieldset',
    '#title' => t('Og Menu Single'),
    '#collapsible' => TRUE,
    '#collapsed' => !og_menu_single_is_enabled_group_content('node', $type) && !og_menu_single_is_enabled_group('node', $type),
  );
  $form['menu']['og_menu_single']['og_menu_single_group_content__node_'] = array(
    '#type' => 'checkbox',
    '#title' => t('Content of this type may be placed in a group menu. Must also be a group content type'),
    '#default_value' => og_menu_single_is_enabled_group_content('node', $type),
  );
  $form['menu']['og_menu_single']['og_menu_single_group__node_'] = array(
    '#type' => 'checkbox',
    '#title' => t('Groups of this type may have a group menu. Must also be a group type'),
    '#default_value' => og_menu_single_is_enabled_group('node', $type),
  );
}

/**
 * Implements hook_node_prepare().
 */
function og_menu_single_node_prepare($node) {
  if (og_menu_single_is_enabled_group_content('node', $node->type)) {

    // Set PLID for form use later.
    $node->group_plid = og_menu_single_get_active_plid();
    if ($node->group_plid && !empty($node->nid)) {
      if ($mlid = og_menu_single_get_link_mlid('node', $node->nid)) {
        $link = menu_link_load($mlid);
        $node->menu = $node->menu ? $link + $node->menu : $link;
      }
    }
  }
}

/**
 * Implements hook_form_FORMID_alter().
 */
function og_menu_single_form_menu_edit_item_alter(&$form, $form_state) {
  $item = menu_get_item();

  // @TODO
  // Don't want to define new form for menu edit so any contrib editing main one
  // edits this also, but no way other than using 'menu_override_parent_selector
  // but there's no way to know where else outside of core menu_parent_options
  // has been used. Bah!!
  if ($item['path'] == 'group/%/%/admin/menu/item/%/edit' || $item['path'] == 'group/%/%/admin/menu/add') {
    $plid = og_menu_single_get_link_mlid_or_create($item['map'][1], $item['map'][2]);
    $link = $form['original_item']['#value'];
    $options[OG_MENU_SINGLE_MENU_NAME . ':' . $plid] = '<' . t('None') . '>';
    if ($plid && ($tree = og_menu_single_children_items($plid))) {
      _menu_parents_recurse($tree, OG_MENU_SINGLE_MENU_NAME, '--', $options, $link['mlid'] ? $link['mlid'] : 0, 8);
    }
    $form['parent']['#options'] = $options;
    $form['enabled']['#access'] = FALSE;
    $form['expanded']['#access'] = FALSE;
    $menu_path = 'group/' . $item['map'][1] . '/' . $item['map'][2] . '/admin/menu';
    if ($link['mlid']) {
      $breadcrumb = drupal_get_breadcrumb();
      array_pop($breadcrumb);
      $breadcrumb[] = l('Group Menu', 'group/' . $item['map'][1] . '/' . $item['map'][2] . '/admin/menu');
      drupal_set_breadcrumb($breadcrumb);
    }
    $form['#submit'][] = 'og_menu_single_menu_form_new_redirect';
    $form['#og_menu_redirect'] = $menu_path;
  }
}

/**
 * Implements hook_form_FORMID_alter().
 */
function og_menu_single_form_menu_item_delete_form_alter(&$form, $form_state) {
  $item = menu_get_item();
  if ($item['path'] == 'group/%/%/admin/menu/item/%/delete') {
    $menu_path = 'group/' . $item['map'][1] . '/' . $item['map'][2] . '/admin/menu';
    $form['#submit'][] = 'og_menu_single_menu_form_new_redirect';
    $form['#og_menu_redirect'] = $menu_path;
    $form['actions']['cancel']['#href'] = str_replace('admin/structure/menu/manage/' . OG_MENU_SINGLE_MENU_NAME, $menu_path, $form['actions']['cancel']['#href']);
  }
}
function og_menu_single_menu_form_new_redirect($form, &$form_state) {
  $form_state['redirect'] = $form['#og_menu_redirect'];
}

/**
 * Implements hook_form_FORMID_alter().
 */
function og_menu_single_form_node_form_alter(&$form, $form_state) {
  if (!og_menu_single_is_enabled_group_content('node', $form['#node']->type) || empty($form['#node']->group_plid)) {
    return;
  }
  $link = $form['#node']->menu;
  $type = $form['#node']->type;
  $options = array();
  $options[OG_MENU_SINGLE_MENU_NAME . ':' . $form['#node']->group_plid] = '<' . t('Group Menu') . '>';
  if ($tree = og_menu_single_children_items($form['#node']->group_plid)) {
    _menu_parents_recurse($tree, OG_MENU_SINGLE_MENU_NAME, '--', $options, $link['mlid'] ? $link['mlid'] : 0, 8);
  }
  if (!empty($form['menu'])) {
    $form['menu']['link']['parent']['#options'] += $options;

    // Restore default if wasn't in menu parents before our alterations..
    if (!empty($link['mlid'])) {
      $default = $link['menu_name'] . ':' . $link['plid'];
      if (isset($form['menu']['link']['parent']['#options'][$default])) {
        $form['menu']['link']['parent']['#default_value'] = $default;
      }
    }
  }
  else {

    // @see menu_form_node_form_alter().
    $context = og_context();
    $form['menu'] = array(
      '#type' => 'fieldset',
      '#title' => t('Menu settings'),
      '#access' => user_access('administer menu') || $context && og_user_access($context['group_type'], $context['gid'], 'manage menu'),
      '#collapsible' => TRUE,
      '#collapsed' => !$link['link_title'],
      '#group' => 'additional_settings',
      '#attached' => array(
        'js' => array(
          drupal_get_path('module', 'menu') . '/menu.js',
        ),
      ),
      '#tree' => TRUE,
      '#weight' => -2,
      '#attributes' => array(
        'class' => array(
          'menu-link-form',
        ),
      ),
    );
    $form['menu']['enabled'] = array(
      '#type' => 'checkbox',
      '#title' => t('Provide a menu link'),
      '#default_value' => (int) (bool) $link['mlid'],
    );
    $form['menu']['link'] = array(
      '#type' => 'container',
      '#parents' => array(
        'menu',
      ),
      '#states' => array(
        'invisible' => array(
          'input[name="menu[enabled]"]' => array(
            'checked' => FALSE,
          ),
        ),
      ),
    );

    // Populate the element with the link data.
    foreach (array(
      'mlid',
      'module',
      'hidden',
      'has_children',
      'customized',
      'options',
      'expanded',
      'hidden',
      'parent_depth_limit',
    ) as $key) {
      $form['menu']['link'][$key] = array(
        '#type' => 'value',
        '#value' => $link[$key],
      );
    }
    $form['menu']['link']['link_title'] = array(
      '#type' => 'textfield',
      '#title' => t('Menu link title'),
      '#default_value' => $link['link_title'],
    );
    $form['menu']['link']['description'] = array(
      '#type' => 'textarea',
      '#title' => t('Description'),
      '#default_value' => isset($link['options']['attributes']['title']) ? $link['options']['attributes']['title'] : '',
      '#rows' => 1,
      '#description' => t('Shown when hovering over the menu link.'),
    );
    $default = $link['mlid'] ? $link['menu_name'] . ':' . $link['plid'] : variable_get('menu_parent_' . $type, 'main-menu:0');

    // If the current parent menu item is not present in options, use the first
    // available option as default value.
    // @todo User should not be allowed to access menu link settings in such a
    // case.
    if (!isset($options[$default])) {
      $array = array_keys($options);
      $default = reset($array);
    }
    $form['menu']['link']['parent'] = array(
      '#type' => 'select',
      '#title' => t('Parent item'),
      '#default_value' => $default,
      '#options' => $options,
      '#attributes' => array(
        'class' => array(
          'menu-parent-select',
        ),
      ),
    );
    $form['menu']['link']['weight'] = array(
      '#type' => 'weight',
      '#title' => t('Weight'),
      '#delta' => 50,
      '#default_value' => $link['weight'],
      '#description' => t('Menu links with smaller weights are displayed before links with larger weights.'),
    );
  }
}

/**
 * Implements hook_node_insert().
 */
function og_menu_single_node_insert($node) {
  if (og_menu_single_is_enabled_group('node', $node->type)) {
    _og_menu_single_save_group_link($node);
  }
}

/**
 * Implements hook_node_update().
 */
function og_menu_single_node_update($node) {
  if (og_menu_single_is_enabled_group('node', $node->type)) {
    _og_menu_single_save_group_link($node, og_menu_single_get_link_mlid('node', $node->nid));
  }
}

/**
 * Implements hook_block_info().
 */
function og_menu_single_block_info() {
  $blocks['menu'] = array(
    'info' => t('OG Menu (active space menu)'),
    'cache' => DRUPAL_CACHE_PER_PAGE,
  );
  return $blocks;
}

/**
 * Implements hook_menu().
 */
function og_menu_single_menu() {
  $items = array();
  $items['group/%/%/admin/menu'] = array(
    'title callback' => 'og_ui_menu_title_callback',
    'title arguments' => array(
      'Menu for group @group',
      1,
      2,
    ),
    'description' => 'Manage group menu for a group.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'og_menu_single_menu_edit_form',
      1,
      2,
    ),
    'access callback' => 'og_ui_user_access_group',
    'access arguments' => array(
      'manage menu',
      1,
      2,
    ),
    'weight' => -8,
    'file' => 'og_menu_single.admin.inc',
  );
  $items['group/%/%/admin/menu/list'] = array(
    'title' => 'List links',
    'weight' => -10,
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
  );
  $items['group/%/%/admin/menu/add'] = array(
    'title' => 'Add link',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'menu_edit_item',
      'add',
      NULL,
      menu_load(OG_MENU_SINGLE_MENU_NAME),
    ),
    'access callback' => 'og_ui_user_access_group',
    'access arguments' => array(
      'manage menu',
      1,
      2,
    ),
    'type' => MENU_LOCAL_ACTION,
    'file' => 'menu.admin.inc',
    'file path' => drupal_get_path('module', 'menu'),
  );
  $items['group/%/%/admin/menu/item/%menu_link/edit'] = array(
    'title' => 'Edit menu link',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'menu_edit_item',
      'edit',
      6,
      NULL,
    ),
    'access callback' => 'og_ui_user_access_group',
    'access arguments' => array(
      'manage menu',
      1,
      2,
    ),
    'file' => 'menu.admin.inc',
    'file path' => drupal_get_path('module', 'menu'),
  );
  $items['group/%/%/admin/menu/item/%menu_link/delete'] = array(
    'title' => 'Delete menu link',
    'page callback' => 'menu_item_delete_page',
    'page arguments' => array(
      6,
    ),
    'access callback' => 'og_ui_user_access_group',
    'access arguments' => array(
      'manage menu',
      1,
      2,
    ),
    'file' => 'menu.admin.inc',
    'file path' => drupal_get_path('module', 'menu'),
  );
  return $items;
}

/**
 * Implement hook_og_permission().
 */
function og_menu_single_og_permission() {
  $items = array();
  $items['manage menu'] = array(
    'title' => t('Manage menu'),
    'description' => t('Manage group menu for this group.'),
    'default role' => array(
      OG_ADMINISTRATOR_ROLE,
    ),
    'restrict access' => TRUE,
  );
  return $items;
}

/**
 * Implements hook_og_ui_get_group_admin()
 */
function og_menu_single_og_ui_get_group_admin($group_type, $gid) {
  $items = array();
  if (og_user_access($group_type, $gid, 'manage menu')) {
    $items['manage_menu'] = array(
      'title' => t('Menu'),
      'description' => t('Manage group menu'),
      'href' => 'admin/menu',
    );
  }
  return $items;
}

/**
 * Implements hook_block_configure().
 */
function og_menu_single_block_configure($delta = '') {

  // This example comes from node.module.
  $form = array();
  if ($delta == 'menu') {
    $form['settings']['og_menu_single_block_menu_depth'] = array(
      '#title' => t('Depth'),
      '#type' => 'select',
      '#options' => array(
        0 => t('All'),
        1 => 1,
        2 => 2,
        3 => 3,
        4 => 4,
        5 => 5,
        6 => 6,
        7 => 7,
      ),
      '#default_value' => variable_get('og_menu_single_block_menu_depth', 0),
      '#description' => t('Select how deep/how many levels of the menu to display.'),
    );
  }
  return $form;
}

/**
 * Implements hook_block_save().
 */
function og_menu_single_block_save($delta = '', $edit = array()) {
  if ($delta == 'menu') {
    variable_set('og_menu_single_block_menu_depth', $edit['og_menu_single_block_menu_depth']);
  }
}

/**
 * Implements hook_block_view().
 */
function og_menu_single_block_view($delta = '') {
  $block = array();
  if ($plid = og_menu_single_get_active_plid()) {
    $tree = og_menu_single_children_items($plid, variable_get('og_menu_single_block_menu_depth', MENU_MAX_DEPTH));
    if ($tree && ($output = menu_tree_output($tree))) {
      $block['content'] = $output;
    }
  }
  return $block;
}

/**
 * Returns whether the group type is a considered group content.
 */
function og_menu_single_is_enabled_group_content($entity_type = 'node', $bundle) {
  $is_group_content_type = og_is_group_content_type($entity_type, $bundle);
  return $is_group_content_type && variable_get('og_menu_single_group_content__' . $entity_type . '__' . $bundle, $is_group_content_type && !og_is_group_type($entity_type, $bundle));
}

/**
 * Returns whether the group type is a considered a group.
 */
function og_menu_single_is_enabled_group($entity_type = 'node', $bundle) {
  $is_group_type = og_is_group_type($entity_type, $bundle);
  return $is_group_type && variable_get('og_menu_single_group__' . $entity_type . '__' . $bundle, $is_group_type);
}

/**
 * Fetches the link for given item in menu.
 *
 * @param $type
 *   What type of group it is -- currently only node is supported.
 * @param $id
 *   ID of group.
 * @param $reset
 *   Reset the internal cache for this $type/id.
 *
 * @return
 *   A menu link in og menu single menu for given entity if exists.
 */
function og_menu_single_get_link_mlid($type, $id, $reset = FALSE) {
  $mlids =& drupal_static(__FUNCTION__, array());
  $cid = $type . '_' . $id;
  if ($reset || !isset($mlids[$cid])) {
    $mlids[$cid] = db_select('menu_links', 'ml')
      ->fields('ml', array(
      'mlid',
    ))
      ->orderBy('mlid', 'ASC')
      ->condition('ml.link_path', 'node/' . $id)
      ->condition('ml.module', 'menu')
      ->condition('ml.menu_name', OG_MENU_SINGLE_MENU_NAME)
      ->range(0, 1)
      ->execute()
      ->fetchField();
  }
  return $mlids[$cid];
}

/**
 * Fetched the space mlid of the current space in the menu.
 *
 * @return
 *   The active menu link ID for current group.
 */
function og_menu_single_get_active_plid() {
  $context = og_context();

  // TODO
  if (!$context || $context['group_type'] != 'node' || !$context['gid']) {
    return NULL;
  }

  // Set PLID for form use later.
  return og_menu_single_get_link_mlid_or_create($context['group_type'], $context['gid']);
}

/**
 * Fetched or crate space mlid of an entity.
 *
 * @return
 *   The active menu link ID for current group.
 */
function og_menu_single_get_link_mlid_or_create($entity_type, $entity_id) {
  $mlid = og_menu_single_get_link_mlid($entity_type, $entity_id);
  if (!$mlid && ($entities = entity_load($entity_type, array(
    $entity_id,
  )))) {
    _og_menu_single_save_group_link(reset($entities));
    $mlid = og_menu_single_get_link_mlid($entity_type, $entity_id, TRUE);
  }
  return $mlid;
}

/**
 * Fetches all children of a given parent link.
 *
 * @param $mlid
 *   Parent link ID to build a tree of menu links below.
 * @param $max_depth
 *   The maxium depth of the tree to fetch, defaults to menu's max depth.
 *
 * @return
 *   An array of menu links and their children (as determined by depth).
 */
function og_menu_single_children_items($plid, $max_depth = NULL) {
  if (!isset($max_depth)) {
    $max_depth = MENU_MAX_DEPTH - 1;
  }
  $menu_link = og_menu_single_menu_link_load($plid);
  return _og_menu_single_children_items($plid, $menu_link['depth'] + 1, $max_depth + 1);
}

/**
 * Helper function to populate the menu tree without loading the entire tree.
 */
function _og_menu_single_children_items($plid, $current_depth, $max_depth) {
  $menu_links =& drupal_static(__FUNCTION__, array());
  $tree = array();

  // current depth should always be same for a given plid.
  if (!isset($menu_links[$plid])) {
    $menu_links[$plid] = menu_build_tree(OG_MENU_SINGLE_MENU_NAME, array(
      'expanded' => array(
        $plid,
      ),
      'min_depth' => $current_depth,
    ));
  }
  foreach ($menu_links[$plid] as $key => $item) {
    if (module_exists('i18n_menu')) {
      _i18n_menu_link_localize($item['link']);
    }
    $tree[$key] = $item;
    if ($current_depth < $max_depth) {
      $tree[$key]['below'] = _og_menu_single_children_items($item['link']['mlid'], $current_depth + 1, $max_depth);
    }
  }
  return $tree;
}

/**
 * Cached menu_link_load as may call for same mlid during same page load.
 */
function og_menu_single_menu_link_load($mlid) {
  $menu_links =& drupal_static(__FUNCTION__, array());
  if (!isset($menu_links[$mlid])) {
    $menu_links[$mlid] = menu_link_load($mlid);
  }
  return $menu_links[$mlid];
}

/**
 * Saves menu link to single menu for group.
 *
 * @param $node
 *   A group node object that link will be created/updated for.
 * @param $mlid
 *   Current link ID if exists for that group.
 */
function _og_menu_single_save_group_link($node, $mlid = null) {
  if (og_menu_single_is_enabled_group('node', $node->type)) {
    $link = array(
      'mlid' => $mlid,
      'link_title' => $node->title,
      'link_path' => 'node/' . $node->nid,
      'menu_name' => OG_MENU_SINGLE_MENU_NAME,
      'options' => array(
        'attributes' => array(
          'title' => t('Menu for group') . ' ' . $node->title,
        ),
      ),
    );
    menu_link_save($link);
  }
}

/*
 * Implements hook_ctools_plugin_directory
 */
function og_menu_single_ctools_plugin_directory($owner, $plugin_type) {
  if ($owner == 'ctools' && $plugin_type == 'content_types') {
    return 'plugins/content_types';
  }
}

Functions

Namesort descending Description
og_menu_single_block_configure Implements hook_block_configure().
og_menu_single_block_info Implements hook_block_info().
og_menu_single_block_save Implements hook_block_save().
og_menu_single_block_view Implements hook_block_view().
og_menu_single_children_items Fetches all children of a given parent link.
og_menu_single_ctools_plugin_directory
og_menu_single_form_menu_edit_item_alter Implements hook_form_FORMID_alter().
og_menu_single_form_menu_item_delete_form_alter Implements hook_form_FORMID_alter().
og_menu_single_form_node_form_alter Implements hook_form_FORMID_alter().
og_menu_single_form_node_type_form_alter Implements hook_form_BASE_FORM_ID_alter().
og_menu_single_get_active_plid Fetched the space mlid of the current space in the menu.
og_menu_single_get_link_mlid Fetches the link for given item in menu.
og_menu_single_get_link_mlid_or_create Fetched or crate space mlid of an entity.
og_menu_single_is_enabled_group Returns whether the group type is a considered a group.
og_menu_single_is_enabled_group_content Returns whether the group type is a considered group content.
og_menu_single_menu Implements hook_menu().
og_menu_single_menu_form_new_redirect
og_menu_single_menu_link_load Cached menu_link_load as may call for same mlid during same page load.
og_menu_single_node_insert Implements hook_node_insert().
og_menu_single_node_prepare Implements hook_node_prepare().
og_menu_single_node_update Implements hook_node_update().
og_menu_single_og_permission Implement hook_og_permission().
og_menu_single_og_ui_get_group_admin Implements hook_og_ui_get_group_admin()
_og_menu_single_children_items Helper function to populate the menu tree without loading the entire tree.
_og_menu_single_save_group_link Saves menu link to single menu for group.

Constants