array(), ); } /** * Appends the "uses tokens" label to links on the admin menu links overview * form. */ function theme_menu_token_uses_tokens() { drupal_add_css(drupal_get_path('module', 'menu_token') . '/menu_token.css'); return ' ' . t('uses tokens') . ''; } /** * Implements hook_ctools_plugin_type(). */ function menu_token_ctools_plugin_type() { return array( 'plugins' => array( 'cache' => TRUE, 'use hooks' => TRUE, 'classes' => array('handler'), ), ); } /** * Implements hook_menu_token_plugins(). */ function menu_token_menu_token_plugins() { $plugins = array(); $entity_info = entity_get_info(); $entities = variable_get('menu_token_entities', drupal_map_assoc(array('node', 'user'))); foreach ($entities as $entity => $enabled) { if ($enabled) { $plugins["{$entity}_context"] = array( 'type' => $entity, 'label' => t('@entity_label from context', array('@entity_label' => $entity_info[$entity]['label'])), 'description' => t('Picks a @entity_label from the current context.', array('@entity_label' => $entity_info[$entity]['label'])), 'handler' => array( 'path' => drupal_get_path('module', 'menu_token') . '/plugins', 'file' => 'menu_token_entity_context.inc', 'class' => 'menu_token_entity_context', ), ); $plugins["{$entity}_random"] = array( 'type' => $entity, 'label' => t('Random @entity_label', array('@entity_label' => $entity_info[$entity]['label'])), 'description' => t('Picks a random @entity_label from the database.', array('@entity_label' => $entity_info[$entity]['label'])), 'handler' => array( 'path' => drupal_get_path('module', 'menu_token') . '/plugins', 'file' => 'menu_token_entity_random.inc', 'class' => 'menu_token_entity_random', ), ); $plugins["{$entity}_user_defined"] = array( 'type' => $entity, 'label' => t('User-defined @entity_label', array('@entity_label' => $entity_info[$entity]['label'])), 'description' => t('Uses a user-defined @entity_label.', array('@entity_label' => $entity_info[$entity]['label'])), 'handler' => array( 'path' => drupal_get_path('module', 'menu_token') . '/plugins', 'file' => 'menu_token_entity_user_defined.inc', 'class' => 'menu_token_entity_user_defined', ), ); } } return $plugins; } /** * Implements hook_translated_menu_link_alter(). */ function menu_token_translated_menu_link_alter(&$item, $map) { global $menu_admin; if (!_menu_token_is_called_from_features()) { return; } // Check whether we should replace the path. if (empty($menu_admin) && isset($item['options']['menu_token_link_path'])) { $info = token_get_info(); $data = array(); // Load data objects used when replacing link. if (isset($item['options']['menu_token_data'])) { foreach ($item['options']['menu_token_data'] as $type => $values) { if (!empty($info['types'][$type]) && $handler = menu_token_get_handler($values['plugin'])) { $values['options']['_type'] = $type; if ($object = $handler->object_load($values['options'])) { $data[$type] = $object; } } } } $options['clear'] = !empty($item['options']['menu_token_options']['clear']) ? TRUE : FALSE; // If item is generated by admin menu module, tokens should not be replaced // and indicator that tokens are used should be shown. $item['title'] = token_replace($item['title'], $data, $options); $url = token_replace($item['options']['menu_token_link_path'], $data, $options); // Make sure aliases are proccessed correctly $url = trim($url, '/'); $url = drupal_get_normal_path($url); // Override active trail if showing front page but translated link is not to // front page. // NOTE: This relies on any parent of a tokenised menu item having "option" // flag "alter" set, which is most easily achieved by setting it to use // token translation but not specifying a token. Otherwise parent does not // get processed through this function and because its untranslated child // has an href of , the menu system thinks it is part of the active // trail to the front page. if (drupal_is_front_page() && $item['href'] != drupal_get_normal_path(variable_get('site_frontpage', 'node'))) { $item['in_active_trail'] = FALSE; } // Check whether path is external. if (url_is_external($url)) { $item['href'] = $item['link_path'] = $url; return; } // Split url into parts and save in proper format. $url_parts = parse_url($url); $url = $url_parts['path']; $item['href'] = $item['link_path'] = $item['router_path'] = $url; if (isset($url_parts['query'])) { $query = drupal_get_query_array($url_parts['query']); $item['localized_options']['query'] = $item['options']['query'] = $query; } if (isset($url_parts['fragment'])) { $item['localized_options']['fragment'] = $item['options']['fragment'] = $url_parts['fragment']; } if ($url == '') { $url = drupal_get_normal_path(variable_get('site_frontpage', 'node')); } // Load menu item and check access. if ($menu_item = menu_get_item($url)) { $item['access'] = $menu_item['access']; return; } $item['access'] = FALSE; } } /** * Implements hook_menu_link_alter(). */ function menu_token_menu_link_alter(&$item) { if (isset($item['options']['menu_token_link_path'])) { // Set 'alter' option to use hook_translated_menu_link_alter() // Only alter if not called from within menu_links_features_export_render $item['options']['alter'] = _menu_token_is_called_from_features(); } } /** * Returns TRUE if 'menu_links_features_export_render' is in the callstack. */ function _menu_token_is_called_from_features() { $called = &drupal_static(__FUNCTION__); if (!isset($called)) { $callstack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); foreach($callstack as $function) { $called = ($function['function'] == 'menu_links_features_export_render'); if ($called) { break; } } } return !$called; } /** * Retrieves the handler of a menu token plugin. * * @param $name * The name of a plugin. * * @return * A menu_token_handler object that represents the handler of the plugin * defined by $name or FALSE if no plugin named $name exists. */ function menu_token_get_handler($name) { $handlers = &drupal_static(__FUNCTION__); if (!isset($handlers[$name])) { if ($plugin = menu_token_get_plugin($name)) { $handlers[$name] = new $plugin['class']($plugin); } } if (isset($handlers[$name])) { return $handlers[$name]; } return FALSE; } /** * Retrieves a menu token plugin. * * @param $name * The name of a plugin. * * @return * An array containing information about the plugin as returned by the ctools * plugin API. */ function menu_token_get_plugin($name) { $plugins = _menu_token_plugin_info()->plugins; if (isset($plugins[$name])) { return $plugins[$name]; } return FALSE; } /** * Retrieves a list of all available menu token plugins. * * @return * An array containing all available plugins. */ function menu_token_get_plugins() { return _menu_token_plugin_info()->plugins; } /** * Retrieves a list of all token types that are covered by the available menu * token plugins. * * @return * An array containing all token types covered by menu token plugins. */ function menu_token_get_plugin_types() { return _menu_token_plugin_info()->types; } /** * Builds and returns information about the menu token plugins and their types. */ function _menu_token_plugin_info() { $cache = &drupal_static(__FUNCTION__); if (!isset($cache)) { ctools_include('plugins'); $cache = (object) array( 'plugins' => array(), 'types' => array(), ); $info = token_get_info(); foreach (ctools_get_plugins('menu_token', 'plugins') as $plugin) { if (isset($info['types'][$plugin['type']]) && $class = ctools_plugin_get_class($plugin, 'handler')) { $cache->plugins[$plugin['name']] = $plugin; $cache->plugins[$plugin['name']]['class'] = $class; $cache->types[$plugin['type']][$plugin['name']] = $plugin['label']; } } } return $cache; } /** * Implementation of hook_form_FORM_ID_alter(). */ function menu_token_form_menu_edit_item_alter(&$form, &$form_state) { if ($form['module']['#value'] == 'menu') { $types = menu_token_get_plugin_types(); $options = $form['options']['#value']; // Replace fake path (/menutoken/ouruid) with user inputed one. if (!empty($options['menu_token_link_path'])) { $form['menu_token_uuid'] = array( '#type' => 'hidden', '#value' => $form['link_path']['#default_value'], ); $form['link_path']['#default_value'] = $options['menu_token_link_path']; } $form['link_title']['#weight'] = -5; $form['link_path']['#weight'] = -4; $form['menu_token_enabled'] = array( '#type' => 'checkbox', '#title' => t('Use tokens in title and in path.'), '#description' => t('Active this option in order to use Menu token.'), '#default_value' => isset($options['menu_token_link_path']), '#weight' => -3, ); $form['menu_token_options'] = array( '#type' => 'fieldset', '#title' => t('Menu Token options'), '#collapsible' => TRUE, '#weight' => -2, '#states' => array( 'visible' => array( ':input[name="menu_token_enabled"]' => array('checked' => TRUE), ), ), ); foreach ($types as $type => $items) { $info = token_get_info($type); $default = NULL; if (isset($form_state['values']['menu_token_type_' . $type])) { $default = $form_state['values']['menu_token_type_' . $type]; } elseif (!empty($options['menu_token_data'][$type])) { $default = $options['menu_token_data'][$type]['plugin']; } $form['menu_token_options'][$type] = array( '#type' => 'container', ); $form['menu_token_options'][$type]['menu_token_type_' . $type] = array( '#type' => 'select', '#title' => t('Method for') . ' ' . $info['name'], '#description' => $info['description'], '#options' => array('_none' => t('Disabled')), '#default_value' => isset($default) && in_array($default, array_keys($items)) ? $default : array('_none'), '#ajax' => array( 'callback' => 'menu_token_method_callback', 'wrapper' => 'menu-token-method-options-' . $type, 'method' => 'replace', 'effect' => 'fade', ), ); foreach ($items as $name => $label) { $form['menu_token_options'][$type]['menu_token_type_' . $type]['#options'][$name] = $label; } $form['menu_token_options'][$type]['menu_token_method_options_wrapper'] = array( '#type' => 'container', '#prefix' => '', ); if (isset($default) && $handler = menu_token_get_handler($default)) { if ($append = $handler->form_options($options['menu_token_data'][$type]['options'])) { $form['menu_token_options'][$type]['menu_token_method_options_wrapper']['menu_token_method_options'] = array( '#type' => 'fieldset', '#title' => t('Method options'), '#collapsible' => TRUE, ) + $append; } } } $form['menu_token_options']['menu_token_clear'] = array( '#type' => 'checkbox', '#title' => t('Remove token if replacement is not present'), '#description' => t('If the replacement token is not available on the page being viewed, the token will be removed if checked.'), '#default_value' => isset($options['menu_token_options']['clear']) ? $options['menu_token_options']['clear'] : '', ); // Create new fieldset. $form['menu_token_replacement_patterns'] = array( '#type' => 'fieldset', '#title' => t('Replacement patterns'), '#collapsible' => FALSE, '#weight' => -1, '#states' => array( 'visible' => array( ':input[name="menu_token_enabled"]' => array('checked' => TRUE), ), ), ); $form['menu_token_replacement_patterns']['patterns'] = array( '#theme' => 'token_tree', '#token_types' => array_keys($types), '#dialog' => TRUE, ); // Add custom validation and submit functions. array_unshift($form['#validate'], 'menu_token_form_menu_edit_item_validate'); array_unshift($form['#submit'], 'menu_token_form_menu_edit_item_submit'); foreach (array_keys(menu_token_get_plugins()) as $plugin) { if ($handler = menu_token_get_handler($plugin)) { $handler->form_alter($form, $form_state); } } } } /** * Custom validation for form menu_edit_item. */ function menu_token_form_menu_edit_item_validate($form, &$form_state) { $values = $form_state['values']; // If token replacing is enabled and this is a custom menu item. if ($values['module'] == 'menu' && !empty($values['menu_token_enabled'])) { // Substitute link_path with our own unique menu path. This will make sure features will export our menu items. form_set_value(array('#parents' => array('options', 'menu_token_link_path')), $values['link_path'], $form_state); form_set_value(array('#parents' => array('link_path')), '', $form_state); if (!empty($values['menu_token_uuid'])) { // If a uuid already exists, dont change it form_set_value(array('#parents' => array('link_path')), $values['menu_token_uuid'], $form_state); } else { form_set_value(array('#parents' => array('link_path')), 'menutoken/' . uniqid(), $form_state); } foreach (array_keys(menu_token_get_plugin_types()) as $type) { if (!empty($values['menu_token_type_' . $type]) && $values['menu_token_type_' . $type] != '_none') { $plugin = $values['menu_token_type_' . $type]; if ($handler = menu_token_get_handler($plugin)) { // Validate the form via the handler. $form_state['_menu_token_entity_type'] = $type; $handler->form_validate($form, $form_state); } } } } } /** * Custom submit for form menu_edit_item. */ function menu_token_form_menu_edit_item_submit($form, &$form_state) { $values = &$form_state['values']; // If token replacing is enabled and this is a custom menu item if ($values['module'] == 'menu' && !empty($values['menu_token_enabled'])) { // Store the actual path in the options array. form_set_value(array('#parents' => array('options', 'menu_token_data')), array(), $form_state); form_set_value(array('#parents' => array('options', 'menu_token_options', 'clear')), $values['menu_token_clear'], $form_state); foreach (array_keys(menu_token_get_plugin_types()) as $type) { if (!empty($values['menu_token_type_' . $type]) && $values['menu_token_type_' . $type] != '_none') { $plugin = $values['menu_token_type_' . $type]; if ($handler = menu_token_get_handler($plugin)) { form_set_value(array('#parents' => array('options', 'menu_token_data', $type)), array('type' => $type, 'plugin' => $plugin, 'options' => array()), $form_state); // Validate the form via the handler. if ($output = $handler->form_submit($form, $form_state)) { $output = $values['options']['menu_token_data'][$type]['options'] + $output; form_set_value(array('#parents' => array('options', 'menu_token_data', $type, 'options')), $output, $form_state); } } } } } else { foreach (array('menu_token_link_path', 'menu_token_data', 'menu_token_options') as $key) { unset($values['options'][$key]); } } } /** * Implementation hook_form_FORM_ID_alter(). */ function menu_token_form_menu_overview_form_alter(&$form, $form_state) { foreach ($form as &$item) { if (isset($item['mlid'], $item['#item']['options']) && isset($item['#item']['options']['menu_token_link_path'])) { $item['title']['#markup'] .= theme('menu_token_uses_tokens'); } } } /** * Ajax callback for the method select dropdown. */ function menu_token_method_callback($form, $form_state) { $parents = $form_state['triggering_element']['#array_parents']; array_pop($parents); array_push($parents, 'menu_token_method_options_wrapper'); return drupal_array_get_nested_value($form, $parents); } /** * The menu token handler interface should be implemented by all menu token * plugins. */ interface menu_token_handler { /** * You can provide options for your menu token handler via this function. * The return value will be appended to the form as soon as the administrator * chooses your plugin. */ function form_options($options); /** * This function allows your plugin to act upon form submission. The return * value will be added to the $options array and thus should be an array * itself. * * Note: Only invoked for selected plugins. */ function form_submit($form, &$form_state); /** * This function allows your plugin to act upon form validation. The return * value will be added to the $options array and thus should be an array * itself. * * Note: Only invoked for selected plugins. */ function form_validate($form, &$form_state); /** * You can alter the menu item administration form with this function. */ function form_alter(&$form, &$form_state); /** * This function is used to load the relevant token replacement object. */ function object_load($options); } /** * Implements hook_permission(). */ function menu_token_permission() { return array( 'administer menu_token' => array( 'title' => t('Administer Menu Token'), ), ); } /** * Implements hook_menu(). */ function menu_token_menu() { $items = array(); $items['menutoken/%'] = array( 'title' => "Dummy Menu Token item", 'access callback' => TRUE, 'page callback' => 'theme_menu_token_uses_tokens', ); $items['admin/config/menu_token'] = array( 'title' => 'Menu Token', 'description' => 'Configure the Menu Token module.', 'page callback' => 'drupal_get_form', 'page arguments' => array('menu_token_settings_form'), 'access arguments' => array('administer menu_token'), 'file' => 'menu_token.admin.inc', ); return $items; }