You are here

menu_fields.module in Menu Item Fields 7

Main file contain hooks/functions.

File

menu_fields.module
View source
<?php

/**
 * @file
 * Main file contain hooks/functions.
 */

/**
 * Implements hook_permission().
 */
function menu_fields_permission() {
  return array(
    'administer menu fields' => array(
      'title' => t('Administer menu fields configuration'),
    ),
  );
}

/**
 * Implements hook_theme().
 */
function menu_fields_theme($existing, $type, $theme, $path) {
  return array(
    'entity__menu_fields' => array(
      'base hook' => 'entity',
      'render element' => 'elements',
      'template' => 'entity--menu-fields',
      'path' => $path . '/templates',
      'pattern' => 'entity__menu_fields__',
    ),
    'menu_fields_menu_link' => array(
      'render element' => 'elements',
    ),
    'menu_fields_menu_tree' => array(
      'render element' => 'tree',
    ),
  );
}

/**
 * Implements hook_entity_view().
 */
function menu_fields_entity_view($entity, $type, $view_mode, $langcode) {
  if ($type != 'menu_fields') {
    return;
  }
  list(, , $bundle) = entity_extract_ids('menu_fields', $entity);
  $link = menu_link_load($entity->mlid);
  if (!$link) {
    return;
  }

  // Get our extra field display values.
  $extra_fields = field_info_extra_fields('menu_fields', $bundle, 'display');

  // Taken directly from menu.inc function menu_tree_page_data().
  $active_trail = array(
    0 => 0,
  );
  $active_path = menu_tree_get_path($link['menu_name']);
  $active_link = menu_link_get_preferred($active_path, $link['menu_name']);

  // Use all the coordinates, except the last one because there
  // can be no child beyond the last column.
  for ($i = 1; $i < MENU_MAX_DEPTH; $i++) {
    if ($link['p' . $i]) {
      $active_trail[$active_link['p' . $i]] = $active_link['p' . $i];
    }
  }
  $active_trail = array_filter($active_trail);
  if (!in_array($link['plid'], $active_trail)) {
    $active_trail[] = $link['plid'];
  }

  // This is the main link, just as it would be printed without this module,
  // only a little more wrappers around.
  if ($extra_fields['menu_fields_link']['display'][$view_mode]['visible']) {

    // We need to get all links from the same parent, otherwise the classes
    // (first, last) will not be correct.
    $parameters = array(
      'active_trail' => $active_trail,
      'only_active_trail' => FALSE,
      'min_depth' => $link['depth'],
      'max_depth' => $link['depth'],
      'conditions' => array(
        'plid' => $link['plid'],
      ),
    );

    // Probably bad for performance, but necessary,
    // see https://www.drupal.org/node/1697570
    drupal_static_reset('_menu_build_tree');
    $tree = menu_build_tree($link['menu_name'], $parameters);

    // Now find the item in the tree that represents the current link and get
    // it's key.
    $link_key = NULL;
    foreach ($tree as $key => $element) {
      if ($element['link']['mlid'] == $entity->mlid) {
        $link_key = $key;
      }
    }

    // Mark it, so that we won't run into a loop.
    $tree[$link_key]['link']['render_menu_fields'] = FALSE;

    // Prepare the output.
    $tree_data = menu_tree_output($tree);
    foreach (element_children($tree_data) as $key) {
      if ($key != $entity->mlid) {
        unset($tree_data[$key]);
      }
    }
    menu_fields_assure_localized_options_classes($tree_data);

    // And put everything into the entities content storage.
    $entity->content['menu_fields_link'] = $tree_data;
    $entity->content['menu_fields_link']['#weight'] = $extra_fields['menu_fields_link']['display'][$view_mode]['weight'];
    $entity->content['menu_fields_link']['#theme_wrappers'][] = 'menu_fields_menu_tree__' . strtr($link['menu_name'], '-', '_');
  }

  // These are the men links children.
  if ($extra_fields['menu_fields_link_children']['display'][$view_mode]['visible'] && $link['has_children']) {
    $parameters = array(
      'active_trail' => array(
        $link['plid'],
      ),
      'only_active_trail' => FALSE,
      'min_depth' => $link['depth'] + 1,
      'max_depth' => $link['depth'] + 1,
      'conditions' => array(
        'plid' => $link['mlid'],
      ),
    );
    $tree = menu_build_tree($link['menu_name'], $parameters);
    $entity->content['menu_fields_link_children'] = menu_tree_output($tree);
    $entity->content['menu_fields_link_children']['#weight'] = $extra_fields['menu_fields_link_children']['display'][$view_mode]['weight'];
  }

  // The path that the link targets.
  if ($extra_fields['menu_fields_link_path']['display'][$view_mode]['visible']) {
    $entity->content['menu_fields_link_path'] = array(
      '#type' => 'item',
      '#markup' => url($link['href']),
      '#weight' => $extra_fields['menu_fields_link_path']['display'][$view_mode]['weight'],
    );
  }

  // And the title of the link.
  if ($extra_fields['menu_fields_link_title']['display'][$view_mode]['visible']) {
    $entity->content['menu_fields_link_title'] = array(
      '#type' => 'item',
      '#markup' => $link['link_title'],
      '#weight' => $extra_fields['menu_fields_link_title']['display'][$view_mode]['weight'],
    );
  }

  // Finally, after everything has been assembled,
  // we need to add another wrapper around this item,
  // so that it appears in an <li> element with the appropriate attributes.
  $tree_data = array(
    $link,
  );
  $tree_data = menu_tree_data($tree_data, $active_trail);

  // If the access to the menu item is denied,
  // menu_tree_output will return an empty array.
  // This can happen for views preview.
  $build = menu_tree_output($tree_data);
  if (!empty($build)) {
    menu_fields_assure_localized_options_classes($build);
    $entity->content['#prefix'] = '<li' . drupal_attributes($entity->content['menu_fields_link'][$link['mlid']]['#attributes']) . '>';
    $entity->content['#suffix'] = '</li>';
  }
}

/**
 * Assure that localized options are set.
 *
 * @param array $tree_data
 *   The location where the options are set.
 */
function menu_fields_assure_localized_options_classes(array &$tree_data) {
  foreach (element_children($tree_data) as $key) {
    if (isset($tree_data[$key]['#localized_options']['attributes']['class'])) {
      continue;
    }
    $tree_data[$key]['#localized_options']['attributes']['class'] = $tree_data[$key]['#attributes']['class'];
  }
}

/**
 * Implements hook_preprocess_entity().
 */
function menu_fields_preprocess_entity(&$vars) {
  if ($vars['entity_type'] == 'menu_fields') {

    // Pass the menu link to the template.
    if (!empty($vars['menu_fields']->link)) {

      // If this is from rendering the menu link, the entity will have the
      // 'link' property already set via menu_fields_preprocess_menu_link().
      $vars['link'] = $vars['menu_fields']->link;
    }
    else {

      // This comes directly from entity_view, no menu link has been rendered
      // yet, which means that menu_fields_preprocess_menu_link() has not been
      // triggered neither.
      $vars['link'] = menu_link_load($vars['menu_fields']->mlid);
    }

    // Suggest our own template which doesn't print the title/url to the entity.
    $vars['theme_hook_suggestions'][] = 'entity__menu_fields';
    $vars['theme_hook_suggestions'][] = 'entity__menu_fields';
    $vars['theme_hook_suggestions'][] = 'entity__menu_fields__' . $vars['elements']['#bundle'];
    $vars['theme_hook_suggestions'][] = 'entity__menu_fields__' . $vars['elements']['#bundle'] . '__' . $vars['elements']['#view_mode'];
  }
}

/**
 * Theme a menu link.
 *
 * @param array $variables
 *   Array where the variables are located.
 *
 * @return string
 *   The attributes list.
 */
function theme_menu_fields_menu_link(array $variables) {
  $element = $variables['element'];
  $sub_menu = '';
  $link = $element['#original_link'];
  $render_fields = !isset($link['render_menu_fields']) || $link['render_menu_fields'] !== FALSE;

  // Yes, we replace the menu link entirely. What else should we do?
  if (isset($element['#menu_fields']) && $element['#menu_fields'] && $render_fields) {

    // This is the rendering of the entity, with all attached fields,
    // following the display configuration.
    $output = drupal_render($element['#menu_fields']);
    return $output . "\n";
  }

  // This is the rendering of a normal link, either from a non menu_fields
  // enabled menu, or from within a menu_field entity.
  $output = l($element['#title'], $element['#href'], $element['#localized_options']);
  if (menu_fields_is_enabled_menu($element['#original_link']['menu_name']) && isset($link['render_menu_fields'])) {

    // In the latter case, we don't want the <li> but only the plain link.
    return $output;
  }

  // The rest is drupal default, we don't mangle with that here.
  if ($element['#below']) {
    $sub_menu = drupal_render($element['#below']);
  }
  return '<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
}

/**
 * Theme a menu tree.
 *
 * @param array $variables
 *   Array where the variables are located.
 *
 * @return string
 *   The children attributes list.
 */
function theme_menu_fields_menu_tree(array $variables) {

  // We check here, if this is the rendering of a single link element as part
  // of a menu fields entity. In that case, the markup has no <li> element and
  // doesn't need the wrapping <ul> neither.
  // The criteria is that their is only a single item in the menu, the menu
  // itself is menu_fields enabled and it's not the rendering of the entity
  // itself (render_menu_fields == FALSE) which could be the case for single
  // link menus.
  $first_item = reset($variables['tree']);
  $link = $first_item['#original_link'];
  $render_plain = !isset($link['render_menu_fields']) || $link['render_menu_fields'] === FALSE;
  $menu_fields_enabled = menu_fields_is_enabled_menu($link['menu_name']);
  $single_item = count(element_children($variables['tree'])) == 1;
  if ($render_plain && $menu_fields_enabled && $single_item) {
    return $first_item['#children'];
  }
  return '<ul class="menu">' . $variables['tree']['#children'] . '</ul>';
}

/**
 * Menu fields link function.
 */
function menu_fields_preprocess_menu_link(&$vars) {
  $element =& $vars['element'];
  $menu_name = $element['#original_link']['menu_name'];
  if (!menu_fields_is_enabled_menu($menu_name)) {

    // This menu isn't enabled for fields,
    // so don't change the way the link is rendered.
    return;
  }
  $vars['theme_hook_suggestions'][] = 'menu_fields_menu_link';
  $render_fields = !isset($element['#original_link']['render_menu_fields']) || $element['#original_link']['render_menu_fields'];
  if (!$render_fields) {
    return;
  }
  $mlid = $element['#original_link']['mlid'];
  $entity = menu_fields_load_by_mlid($mlid);
  if (!$entity && empty($element['#below'])) {

    // No entity is found and this menu link doesn't have any children,
    // so don't change the way the link is rendered.
    return;
  }

  // If there is no existing entity, then we create a fake entity object so that
  // menu links with children use the same render pipeline.
  // @todo Remove this if/when issue #2420525 is fixed!
  if (!$entity) {
    $entity = entity_create('menu_fields', array(
      'menu_name' => menu_fields_create_machine_name($menu_name),
      'mlid' => $mlid,
    ));
  }

  // Stash the link on the entity object so we can pass it to the template.
  $entity->link = $element['#original_link'];
  $view = entity_view('menu_fields', array(
    $entity,
  ), isset($vars['#view_mode']) ? $vars['#view_mode'] : 'default');
  $element['#menu_fields'] = $view;
  $element['#attributes']['class'][] = 'menu-fields-menu-link';
  if (!empty($element['#localized_options']['attributes']['class'])) {
    $element['#localized_options']['attributes']['class'] = array_merge($element['#localized_options']['attributes']['class'], $element['#attributes']['class']);
  }
  else {
    $element['#localized_options']['attributes']['class'] = $element['#attributes']['class'];
  }
}

/**
 * Implements hook_field_extra_fields().
 */
function menu_fields_field_extra_fields() {
  $info = array();
  foreach (menu_fields_enabled_menus() as $menu) {
    $menu = menu_fields_create_machine_name($menu);
    if (!isset($info['menu_fields'][$menu]['display']['menu_fields_link'])) {
      $info['menu_fields'][$menu]['display']['menu_fields_link'] = array(
        'label' => t('Menu link'),
        'description' => t('A fully rendered menu link (default style).'),
        'weight' => 10,
      );
    }
    if (!isset($info['menu_fields'][$menu]['display']['menu_fields_link_children'])) {
      $info['menu_fields'][$menu]['display']['menu_fields_link_children'] = array(
        'label' => t('Child links'),
        'description' => t('Children links of the menu item.'),
        'weight' => 20,
      );
    }
    if (!isset($info['menu_fields'][$menu]['display']['menu_fields_link_path'])) {
      $info['menu_fields'][$menu]['display']['menu_fields_link_path'] = array(
        'label' => t('Link path'),
        'description' => t('The link path of the menu item.'),
        'weight' => 30,
      );
    }
    if (!isset($info['menu_fields'][$menu]['display']['menu_fields_link_title'])) {
      $info['menu_fields'][$menu]['display']['menu_fields_link_title'] = array(
        'label' => t('Link title'),
        'description' => t('The link title of the menu item.'),
        'weight' => 40,
      );
    }
  }
  return $info;
}

/**
 * Implements hook_menu().
 */
function menu_fields_menu() {
  $items['admin/structure/menu/menu-fields'] = array(
    'title' => 'Menu fields',
    'type' => MENU_LOCAL_TASK,
    'description' => 'Configure menu fields.',
    'access arguments' => array(
      'administer menu fields',
    ),
    'page arguments' => array(
      'menu_fields_field_configuration_form',
    ),
    'page callback' => 'drupal_get_form',
    'file' => 'menu_fields.admin.inc',
    'weight' => 10,
  );
  return $items;
}

/**
 * Implements hook_menu_alter().
 *
 * Add support for drupal style "manage fields" and "manage display" tabs.
 */
function menu_fields_menu_alter(&$items) {
  foreach ($items as $path => $item) {
    $map = explode('/', $path);
    $map_count = count($map);
    if (strpos($path, 'admin/structure/menu/manage/%/fields') !== FALSE && $map_count == 6) {
      $items[$path]['page arguments'][0] = 'menu_fields_field_ui_field_overview_form';
      $items[$path]['type'] = MENU_LOCAL_TASK;
    }
    if (strpos($path, 'admin/structure/menu/manage/%/display') !== FALSE && $map_count == 6) {
      $items[$path]['page arguments'][0] = 'menu_fields_field_ui_display_overview_form';
      $items[$path]['type'] = MENU_LOCAL_TASK;
    }
    if (strpos($path, 'admin/structure/menu/manage/%/display') !== FALSE && $map_count == 7) {
      $items[$path]['page arguments'][0] = 'menu_fields_field_ui_display_overview_form';
      $items[$path]['access callback'] = 'menu_fields_field_ui_view_mode_menu_access';
    }
    if (strpos($path, 'admin/structure/menu') !== FALSE && strpos($path, '%field_ui_menu') !== FALSE) {
      $path_new = str_replace('%field_ui_menu', '%menu_fields_field_ui_menu', $path);
      $items[$path_new] = $items[$path];
      unset($items[$path]);
    }
  }
  $items['admin/structure/menu']['page callback'] = 'menu_fields_menu_overview_page';
  $items['admin/structure/menu']['file'] = 'menu_fields.admin.inc';
  $items['admin/structure/menu']['file path'] = drupal_get_path('module', 'menu_fields');
}

/**
 * Menu loader; Load a field instance based on field and bundle name.
 *
 * @param string $field_name
 *   The name of the field, as contained in the path.
 * @param string $entity_type
 *   The name of the entity.
 * @param string $bundle_name
 *   The name of the bundle, as contained in the path.
 * @param int $bundle_pos
 *   The position of $bundle_name in $map.
 * @param object $map
 *   The translated menu router path argument map.
 *
 * @return array
 *   The field instance array.
 *
 * @ingroup field
 */
function menu_fields_field_ui_menu_load($field_name, $entity_type, $bundle_name, $bundle_pos, $map) {
  $bundle_name = str_replace('-', '_', $bundle_name);
  $map[$bundle_pos] = str_replace('-', '_', $map[$bundle_pos]);
  return field_ui_menu_load($field_name, $entity_type, $bundle_name, $bundle_pos, $map);
}

/**
 * Wrapper around field_ui_field_overview_form().
 */
function menu_fields_field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle) {
  $bundle = menu_fields_create_machine_name($bundle);
  $form = field_ui_field_overview_form($form, $form_state, $entity_type, $bundle);
  return $form;
}

/**
 * Wrapper around field_ui_field_overview_form_submit().
 */
function menu_fields_field_ui_field_overview_form_submit($form, &$form_state) {
  field_ui_field_overview_form_submit($form, $form_state);
}

/**
 * Wrapper around field_ui_display_overview_form().
 */
function menu_fields_field_ui_display_overview_form($form, &$form_state, $entity_type, $bundle, $view_mode) {
  $bundle = menu_fields_create_machine_name($bundle);
  $form = field_ui_display_overview_form($form, $form_state, $entity_type, $bundle, $view_mode);
  return $form;
}

/**
 * Wrapper around field_ui_field_overview_form_submit().
 */
function menu_fields_field_ui_display_overview_form_submit($form, &$form_state) {
  field_ui_display_overview_form_submit($form, $form_state);
}

/**
 * Gets an array of enabled menu names.
 *
 * @param mixed $default
 *   What should be returned if nothing is set.
 *
 * @return array
 *   Returns array of enabled menu names.
 */
function menu_fields_enabled_menus($default = array()) {
  return variable_get('menu_fields_menus', $default);
}

/**
 * Convenience function for quick menu fields check.
 *
 * @param string $menu_name
 *   The menu name.
 *
 * @return bool
 *   The verification if the menu field is enabled or not.
 */
function menu_fields_is_enabled_menu($menu_name) {
  return in_array($menu_name, menu_fields_enabled_menus());
}

/**
 * Saves enabled Menu Fields menus.
 *
 * @param array $menus
 *   Array of menu names.
 */
function menu_fields_save_enabled_menus(array $menus) {
  variable_set('menu_fields_menus', $menus);

  // Hide the 'Primary link' extra field by default.
  foreach ($menus as $menu) {
    $menu_fields_bundle = menu_fields_create_machine_name($menu);
    $field_bundle_settings = variable_get('field_bundle_settings_menu_fields__' . $menu_fields_bundle, FALSE);
    if ($field_bundle_settings === FALSE) {
      $field_bundle_settings = array(
        'view_modes' => array(),
        'extra_fields' => array(
          'form' => array(),
          'display' => array(
            'menu_fields_links_primary' => array(
              'default' => array(
                'weight' => 10,
                'visible' => FALSE,
              ),
            ),
          ),
        ),
      );
      variable_set('field_bundle_settings_menu_fields__' . $menu_fields_bundle, $field_bundle_settings);
    }
  }

  // Clear the caches that the manage fields link is added.
  field_info_cache_clear();
  entity_info_cache_clear();
  menu_rebuild();
}

/**
 * Implements hook_form_ID_alter().
 *
 * We are going to alter the form for editing a menu item
 * and are going to add some additional fields.
 */
function menu_fields_form_menu_edit_item_alter(&$form, &$form_state) {
  $mlid = $form['mlid']['#value'];

  // Is it a new menu link, get the menu name from the arguments.
  if ($mlid) {
    $menu_link = menu_link_load($mlid);
    $menu_name = $menu_link['menu_name'];
  }
  else {

    // A new menu link is created.
    $menu_name = $form['original_item']['#value']['menu_name'];

    // Set mlid to NULL in case 0 is used for the menu overview entity.
    $mlid = NULL;
  }

  // Add menu field entity fields.
  menu_fields_add_fields_entity_fields($menu_name, $mlid, $form, $form_state);
}

/**
 * Implements hook_menu_link_update().
 */
function menu_fields_menu_link_update($link) {

  // Update menu_name if menu_link moved to another menu.
  $id = menu_fields_entity_id_by_mlid($link['mlid']);
  if ($id) {
    $menu_fields = entity_load_single('menu_fields', $id);
    $menu_name = str_replace('-', '_', $link['menu_name']);
    if (!empty($menu_fields) && $menu_fields->menu_name != $menu_name) {
      $menu_fields->menu_name = $menu_name;
      entity_save('menu_fields', $menu_fields);
    }
  }
}

/**
 * Implements hook_menu_link_delete().
 */
function menu_fields_menu_link_delete($link) {

  // Cleanup menu_fields fields for deleted menu_links.
  $id = menu_fields_entity_id_by_mlid($link['mlid']);
  if ($id) {
    entity_delete('menu_fields', $id);
  }
}

/**
 * Implements hook_menu_delete().
 */
function menu_fields_menu_delete($menu) {

  // Cleanup menu_fields fields for deleted menus.
  $id = menu_fields_entity_id_by_menu($menu['menu_name']);
  if ($id) {
    entity_delete('menu_fields', $id);
  }
}

/**
 * Add the menu fields entity to the given form.
 */
function menu_fields_add_fields_entity_fields($menu_name, $mlid, &$form, &$form_state) {

  // Create bundle name for the given menu name.
  $bundle_name = menu_fields_create_machine_name($menu_name);

  // Check is this field selected for menu fields.
  $selected_menus = menu_fields_enabled_menus();

  // Check is this menu selected for fieldable.
  if (in_array($menu_name, $selected_menus)) {
    $form['#submit'][] = 'menu_fields_form_menu_edit_fields_submit';

    // Load entity id for this menu link.
    $query = new EntityFieldQuery();
    $query
      ->entityCondition('entity_type', 'menu_fields')
      ->propertyCondition('mlid', $mlid)
      ->propertyCondition('menu_name', $bundle_name);
    $result = $query
      ->execute();

    // Is no entity found, create a new one.
    if (empty($result)) {
      $entity = entity_create('menu_fields', array(
        'menu_name' => $bundle_name,
        'mlid' => $mlid,
      ));
    }
    else {
      $entity_nid = array_keys($result['menu_fields']);
      $entity = entity_load('menu_fields', $entity_nid);
      $entity = reset($entity);
    }

    // Set the correct parents for the attached field values,
    // because they are added to a fieldset.
    $form['menu_fields'] = array(
      '#type' => 'fieldset',
      '#title' => t('Menu Fields'),
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
      '#tree' => TRUE,
    );

    // Enable/disable fields for the menu item.
    $form['menu_fields']['enabled'] = array(
      '#type' => 'checkbox',
      '#title' => t('Enable fields for this menu link'),
      '#default_value' => !empty($entity->id) ? TRUE : FALSE,
    );

    // Add menu fields.
    $form['menu_fields']['fields'] = array(
      '#type' => 'container',
      '#states' => array(
        'visible' => array(
          ':input[name="menu_fields[enabled]"]' => array(
            'checked' => TRUE,
          ),
        ),
      ),
    );

    // Get the language code.
    $langcode = NULL;
    if (function_exists('entity_language')) {
      $langcode = entity_language('menu_fields', $entity);
    }

    // Add entity fields.
    field_attach_form('menu_fields', $entity, $form['menu_fields']['fields'], $form_state, $langcode);

    // Add entity to form.
    $form['menu_fields']['entity'] = array(
      '#type' => 'value',
      '#value' => $entity,
    );
  }
}

/**
 * Attached menu entity fields submit callback.
 *
 * Callback function when menu or menu link forms submitted.
 */
function menu_fields_form_menu_edit_fields_submit($form, &$form_state) {

  // If no entity added, no field processing necessary.
  if (isset($form_state['values']['menu_fields']['entity'])) {

    // Get and save the entity.
    $entity = $form_state['values']['menu_fields']['entity'];
    if (!empty($form_state['values']['menu_fields']['enabled'])) {

      // Unset the 'menu_name' because this is a value from the core menu field
      // and overwrites in entity_form_submit_build_entity()
      // the menu_fields bundle name also called 'menu_name'.
      unset($form_state['values']['menu_name']);
      entity_form_submit_build_entity('menu_fields', $entity, $form, $form_state);
      $entity
        ->save();
    }
    elseif (!empty($entity->id)) {
      $entity
        ->delete();
    }

    // Clear cache for given path or the default entry.
    if (isset($form_state['values']['link_path'])) {
      cache_clear_all('fields:' . $form_state['values']['link_path'], 'cache_menu_fields');
    }
    elseif ($entity->mlid == 0) {
      cache_clear_all('fields:/', 'cache_menu_fields');
    }

    // Clear cache for the defined menu link.
    if (isset($form_state['values']['mlid'])) {
      cache_clear_all('fields:mlid:' . $form_state['values']['mlid'], 'cache_menu_fields');
    }

    // Clear block cache.
    cache_clear_all('menu_fields:menu_fields_field_display', 'cache_block', TRUE);
  }
}

/**
 * Implements hook_flush_caches().
 */
function menu_fields_flush_caches() {
  return array(
    'cache_menu_fields',
  );
}

/**
 * Implements hook_entity_info().
 */
function menu_fields_entity_info() {

  // Add a bundle for every activated menu in the fields settings.
  $menus = menu_get_menus();
  $enabled_menus = menu_fields_enabled_menus();
  $bundles = array();
  foreach ($menus as $key => $value) {

    // Always use underscores for menu key hyphens,
    // because hyphens are not allowed for bundle names.
    $machine_name = menu_fields_create_machine_name($key);
    $bundles[$machine_name] = array(
      'label' => $value,
    );
    if (in_array($key, $enabled_menus)) {
      $bundles[$machine_name]['admin'] = array(
        'path' => 'admin/structure/menu/manage/%',
        'real path' => 'admin/structure/menu/manage/' . str_replace('_', '-', $machine_name),
        'bundle argument' => 4,
        'access callback' => 'menu_fields_admin_access',
        'access arguments' => array(
          4,
        ),
      );
    }
  }
  $info['menu_fields'] = array(
    'label' => t('Menu Fields'),
    'controller class' => 'EntityAPIController',
    'base table' => 'menu_fields',
    'fieldable' => TRUE,
    'entity keys' => array(
      'id' => 'id',
      'bundle' => 'menu_name',
    ),
    'bundle keys' => array(
      'bundle' => 'menu_name',
    ),
    'bundles' => $bundles,
    'entity class' => 'Entity',
    'module' => 'menu_fields',
    'view modes' => array(
      'full' => array(
        'label' => t('Full'),
        'default' => FALSE,
      ),
      'block' => array(
        'label' => t('Block'),
        'default' => FALSE,
      ),
    ),
  );
  return $info;
}

/**
 * Entity admin access callback.
 *
 * @param string $menu
 *   Menu.
 *
 * @return bool
 *   Verification if certain menus are enabled or not.
 *
 * @see menu_fields_entity_info()
 */
function menu_fields_admin_access($menu) {
  if (is_numeric($menu)) {
    $menu = arg($menu);
  }
  $menu = str_replace('_', '-', $menu);
  $enabled_menus = menu_fields_enabled_menus();
  if (!in_array($menu, $enabled_menus)) {
    return FALSE;
  }
  return user_access('administer menu fields');
}

/**
 * Access callback for the field ui pages.
 *
 * @param string $entity_type
 *   Entity type.
 * @param string $bundle
 *   Bundle value.
 * @param string $view_mode
 *   View mode.
 * @param string $access_callback
 *   Access callback.
 *
 * @return bool
 *   Menu access callback for the 'view mode display settings' pages.
 */
function menu_fields_field_ui_view_mode_menu_access($entity_type, $bundle, $view_mode, $access_callback) {
  return _field_ui_view_mode_menu_access($entity_type, menu_fields_create_machine_name($bundle), $view_mode, $access_callback, 'menu_fields_admin_access', array(
    $bundle,
  ));
}

/**
 * Gets the Menu Fields entity for given Menu Link ID.
 *
 * @param int $mlid
 *   The Menu Link ID to search for the fields entity.
 *
 * @return Entity
 *   The entity or NULL is no entity found.
 */
function menu_fields_load_by_mlid($mlid) {
  $cache_key = 'fields:mlid:' . $mlid;
  $entity =& drupal_static($cache_key);

  // Check the cache for this entity.
  if (!$entity) {
    $entity = cache_get($cache_key, 'cache_menu_fields');
    $entity = $entity ? $entity->data : NULL;
  }

  // If the entity is not cached, load it.
  if (!$entity) {

    // Get the menu link from given mlid.
    $id = menu_fields_entity_id_by_mlid($mlid);
    if ($id) {
      $entity = entity_load_single('menu_fields', $id);
      cache_set($cache_key, $entity, 'cache_menu_fields');
    }
  }
  return $entity;
}

/**
 * Returns the menu_fields fields entity id for given menu link id (mlid).
 *
 * @param string $mlid
 *   The menu link id.
 *
 * @return string
 *   The menu_fields field entity id or FALSE is no entity found for this mlid.
 */
function menu_fields_entity_id_by_mlid($mlid) {
  $query = db_select('menu_fields', 'm');
  return $query
    ->fields('m', array(
    'id',
  ))
    ->condition('mlid', $mlid)
    ->execute()
    ->fetchField();
}

/**
 * Returns the menu_fields fields entity id for given menu (menu name).
 *
 * @param string $menu_name
 *   The menu machine name.
 *
 * @return string
 *   The menu_fields field entity id or FALSE otherwise.
 */
function menu_fields_entity_id_by_menu($menu_name) {
  $bundle_name = menu_fields_create_machine_name($menu_name);
  return db_select('menu_fields', 'm')
    ->fields('m', array(
    'id',
  ))
    ->condition('mlid', 0)
    ->condition('menu_name', $bundle_name)
    ->execute()
    ->fetchField();
}

/**
 * Creates a machine name from given string.
 *
 * Currently, replaces all hyphens with underscores.
 *
 * @param string $value
 *   The string to use as machine name.
 *
 * @return string
 *   The machine name.
 */
function menu_fields_create_machine_name($value) {
  return str_replace('-', '_', $value);
}

Functions

Namesort descending Description
menu_fields_add_fields_entity_fields Add the menu fields entity to the given form.
menu_fields_admin_access Entity admin access callback.
menu_fields_assure_localized_options_classes Assure that localized options are set.
menu_fields_create_machine_name Creates a machine name from given string.
menu_fields_enabled_menus Gets an array of enabled menu names.
menu_fields_entity_id_by_menu Returns the menu_fields fields entity id for given menu (menu name).
menu_fields_entity_id_by_mlid Returns the menu_fields fields entity id for given menu link id (mlid).
menu_fields_entity_info Implements hook_entity_info().
menu_fields_entity_view Implements hook_entity_view().
menu_fields_field_extra_fields Implements hook_field_extra_fields().
menu_fields_field_ui_display_overview_form Wrapper around field_ui_display_overview_form().
menu_fields_field_ui_display_overview_form_submit Wrapper around field_ui_field_overview_form_submit().
menu_fields_field_ui_field_overview_form Wrapper around field_ui_field_overview_form().
menu_fields_field_ui_field_overview_form_submit Wrapper around field_ui_field_overview_form_submit().
menu_fields_field_ui_menu_load Menu loader; Load a field instance based on field and bundle name.
menu_fields_field_ui_view_mode_menu_access Access callback for the field ui pages.
menu_fields_flush_caches Implements hook_flush_caches().
menu_fields_form_menu_edit_fields_submit Attached menu entity fields submit callback.
menu_fields_form_menu_edit_item_alter Implements hook_form_ID_alter().
menu_fields_is_enabled_menu Convenience function for quick menu fields check.
menu_fields_load_by_mlid Gets the Menu Fields entity for given Menu Link ID.
menu_fields_menu Implements hook_menu().
menu_fields_menu_alter Implements hook_menu_alter().
menu_fields_menu_delete Implements hook_menu_delete().
menu_fields_menu_link_delete Implements hook_menu_link_delete().
menu_fields_menu_link_update Implements hook_menu_link_update().
menu_fields_permission Implements hook_permission().
menu_fields_preprocess_entity Implements hook_preprocess_entity().
menu_fields_preprocess_menu_link Menu fields link function.
menu_fields_save_enabled_menus Saves enabled Menu Fields menus.
menu_fields_theme Implements hook_theme().
theme_menu_fields_menu_link Theme a menu link.
theme_menu_fields_menu_tree Theme a menu tree.