menu_token.module in Menu Token 8
Same filename and directory in other branches
Contains menu_token.module.
File
menu_token.moduleView source
<?php
/**
* @file
* Contains menu_token.module.
*/
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Utility\Token;
use Drupal\Core\PhpStorage\PhpStorageFactory;
/**
* Implements hook_help().
*/
function menu_token_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the menu_token module.
case 'help.page.menu_token':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Menu Token module provides tokens, that can be used in title or in path of menu items (links). For example, if you create a menu item with path: "user/[current-user:uid]", the url will be changed on the fly to: "user/1" (assuming you are user 1).') . '</p>';
return $output;
default:
break;
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function menu_token_form_menu_link_content_form_alter(&$form, FormStateInterface $form_state, $form_id) {
$form_state
->setCached(FALSE);
$rebuild_with_custom_element = $form_state
->get('rebuild_with_custom_element');
// Get the entity from the form state.
$form_entity = $form_state
->getFormObject()
->getEntity();
$link_id_from_entity = $form_entity
->get('link')->uri;
$uuid = $form_entity
->get('uuid')->value;
$available_entities_configuration = \Drupal::config('menu_token.availableentitiesconfiguration');
$data = $available_entities_configuration
->getRawData();
$config_array = [];
if (!empty($link_id_from_entity)) {
$config_menu = \Drupal::entityTypeManager()
->getStorage('link_configuration_storage')
->load($uuid);
if (!empty($config_menu)) {
$config_array = unserialize($config_menu
->get('configurationSerialized'));
}
else {
$config_array = [
"menu_token_enabled" => 0,
"remove_if_replacement_is_not_present" => 0,
];
}
}
if (!empty($form['link']['weight'])) {
$link_weight = $form['link']['weight'];
}
else {
$link_weight = -2;
}
if (empty($config_array['menu_token_enabled'])) {
$config_array['menu_token_enabled'] = 0;
}
if (empty($config_array['remove_if_replacement_is_not_present'])) {
$config_array['remove_if_replacement_is_not_present'] = 0;
}
$form['menu_token_enabled'] = [
'#type' => 'checkbox',
'#title' => t('<strong>Use tokens</strong> in title and in path.'),
'#description' => t('Activate this option in order to use Menu token.'),
'#default_value' => $config_array['menu_token_enabled'],
'#weight' => $link_weight,
];
$form['menu_token_options'] = [
'#type' => 'fieldset',
'#title' => t('Menu Token options'),
'#collapsible' => TRUE,
'#weight' => $link_weight,
'#states' => [
'visible' => [
':input[name="menu_token_enabled"]' => [
'checked' => TRUE,
],
],
],
];
$form['menu_token_options']['menu_token_modal_link'] = [
'#title' => t('Browse available tokens.'),
'#type' => 'link',
'#url' => Url::fromRoute('menu_token.page.show.available.tokens'),
'#attributes' => [
'class' => [
'use-ajax',
],
'data-dialog-type' => 'modal',
'data-dialog-options' => Json::encode([
'width' => 600,
'height' => 600,
'resizable' => TRUE,
]),
],
'#states' => [
'visible' => [
':input[name="menu_token_enabled"]' => [
'checked' => TRUE,
],
],
],
];
// If entities exist and item is enabled.
if (!empty($data['available_entities'])) {
foreach ($data['available_entities'] as $config_key => $config_item) {
if ($config_item !== 0) {
$default_value_array = [
"none",
];
if (!empty($config_array[$config_item])) {
$default_value_array = [
$config_array[$config_item],
];
}
$default_selection = $default_value_array[0][0];
$form['menu_token_options'][$config_item]['menu_token_type_' . $config_item] = [
'#type' => 'select',
'#title' => t("Method for %var", [
'%var' => ucfirst($config_item),
]),
'#options' => [
'none' => t("Disabled", [
'%var' => 'none',
]),
'context' => t("Context from %var", [
'%var' => ucfirst($config_item),
]),
'random' => t("Random %var", [
'%var' => ucfirst($config_item),
]),
'user_defined' => t("User defined %var", [
'%var' => ucfirst($config_item),
]),
],
'#default_value' => $default_selection,
'#executes_submit_callback' => TRUE,
'#submit' => [
'menu_token_custom_entity_submit',
],
'#ajax' => [
'callback' => 'menu_token_custom_entity_callback',
'wrapper' => $config_item . '_custom_entity_container',
],
];
// Define the container.
$form['menu_token_options'][$config_item]['custom_entity_wrapper'] = [
'#type' => 'container',
'#attributes' => [
'id' => $config_item . '_custom_entity_container',
],
];
/* If it is rebuild from ajax */
if (!empty($rebuild_with_custom_element)) {
// Made new form element insert.
if ($rebuild_with_custom_element == 'user_defined') {
$form['menu_token_options'][$config_item]['custom_entity_wrapper'][$config_item . 'custom_entity'] = [
'#title' => t('Entity ID'),
'#description' => t('The id of the entity that this token handler should load.'),
'#type' => 'textfield',
'#default_value' => 1,
];
}
}
else {
// Build only if you have in config variable.
if ($default_selection == 'user_defined') {
$form['menu_token_options'][$config_item]['custom_entity_wrapper'][$config_item . 'custom_entity'] = [
'#title' => t('Entity ID'),
'#description' => t('The id of the entity that this token handler should load.'),
'#type' => 'textfield',
'#default_value' => $default_value_array[0][1],
];
}
}
}
}
}
$form['menu_token_options']['remove_if_replacement_is_not_present'] = [
'#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' => $config_array['remove_if_replacement_is_not_present'],
];
// Submit handler.
$form['actions']['submit']['#submit'][] = 'menu_token_form_submit';
}
/**
* Custom form submit handler.
*/
function menu_token_custom_entity_submit($form, &$form_state) {
$triggering_element = $form_state
->getTriggeringElement();
$form_state
->set('rebuild_with_custom_element', $triggering_element['#value']);
$form_state
->setRebuild();
}
/**
* Ajax callback for the method select dropdown.
*/
function menu_token_custom_entity_callback($form, &$form_state) {
$triggering_element = $form_state
->getTriggeringElement();
if ($triggering_element['#value'] == 'user_defined') {
$element = $triggering_element['#array_parents'][1];
}
else {
// Return just the wrapper. Form was rebuild in the background.
$element = $triggering_element['#array_parents'][1];
}
return $form['menu_token_options'][$element]['custom_entity_wrapper'];
}
/**
* Custom form submit handler.
*/
function menu_token_form_submit($form, &$form_state) {
$values = $form_state
->getValues();
$config_array = [
"menu_token_enabled" => $values['menu_token_enabled'],
"remove_if_replacement_is_not_present" => $values['remove_if_replacement_is_not_present'],
];
$available_entities_configuration = \Drupal::config('menu_token.availableentitiesconfiguration');
$data = $available_entities_configuration
->getRawData();
foreach ($data['available_entities'] as $config_key => $config_item) {
if ($config_item !== 0) {
if (isset($values['menu_token_type_' . $config_item])) {
if ($values['menu_token_type_' . $config_item] == 'user_defined') {
if (empty($values[$config_item . 'custom_entity'])) {
$values[$config_item . 'custom_entity'] = $_POST[$config_item . 'custom_entity'];
}
$config_array[$config_key] = [
$values['menu_token_type_' . $config_item],
$values[$config_item . 'custom_entity'],
];
}
else {
$config_array[$config_key] = [
$values['menu_token_type_' . $config_item],
0,
];
}
}
}
}
$form_entity = $form_state
->getFormObject()
->getEntity();
$uuid = $form_entity
->get('uuid')->value;
// Load the configuration if it exists.
$config_menu = \Drupal::entityTypeManager()
->getStorage('link_configuration_storage')
->load($uuid);
if ($values['menu_token_enabled'] == 0) {
if (!empty($config_menu)) {
$config_menu
->delete();
}
}
else {
$token_service = \Drupal::token();
// Have to find out which type to use by tokens.
// Available in link data and not in configuration entity.
$title_tokens = $token_service
->scan($values['title'][0]['value']);
$uri_tokens = $token_service
->scan($values['link'][0]['uri']);
$merged = array_merge($title_tokens, $uri_tokens);
$all_tokens = array_unique($merged, SORT_REGULAR);
$all_token_types = [];
foreach ($all_tokens as $k => $t) {
$all_token_types[] = $k;
}
if (!empty($config_menu)) {
$config_menu
->set("linkid", (string) $values['link'][0]['uri']);
$config_menu
->set("configurationSerialized", serialize($config_array));
}
else {
$config_menu = \Drupal::entityTypeManager()
->getStorage('link_configuration_storage')
->create([
'id' => $uuid,
'label' => 'Menu token link configuration',
'linkid' => (string) $values['link'][0]['uri'],
'configurationSerialized' => serialize($config_array),
]);
}
$config_menu
->save();
$menu_token_menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$menu_token_menu_link_manager
->rebuild();
// Reset all static caches.
drupal_static_reset();
\Drupal::cache()
->deleteAll();
// Flush asset file caches.
\Drupal::service('asset.css.collection_optimizer')
->deleteAll();
\Drupal::service('asset.js.collection_optimizer')
->deleteAll();
_drupal_flush_css_js();
// Wipe the Twig PHP Storage cache.
PhpStorageFactory::get('twig')
->deleteAll();
// Reset all static caches.
drupal_static_reset();
}
}
/**
* Implements hook_tokens().
*/
function menu_token_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
if (!empty($options['configuration'])) {
$configuration = $options['configuration'];
// Flag to know what to do with tokens where replacement is not found.
$remove_if_not_present = !empty($configuration['remove_if_replacement_is_not_present']) && $configuration['remove_if_replacement_is_not_present'] == 1;
$replacements = [];
foreach ($tokens as $key => $token) {
$entity_type = \Drupal::service('token.entity_mapper')
->getEntityTypeForTokenType($type);
$token_replacer = \Drupal::service('menu_token.token_replacer');
if (!empty($configuration[$entity_type][0])) {
// Make type agnostic so it can handle any type.
switch ($configuration[$entity_type][0]) {
case "none":
$r = $token_replacer
->replaceNone($token, $key, $bubbleable_metadata);
$replacements = array_merge($replacements, $r);
break;
case "context":
$r = $token_replacer
->replaceContext($token, $key, $bubbleable_metadata);
if (empty($r)) {
$r = $token_replacer
->replaceExoticToken($token, $key, $bubbleable_metadata);
if (empty($r)) {
$r = [
array_pop($tokens) => '',
];
}
}
$replacements = array_merge($replacements, $r);
break;
case "random":
$r = $token_replacer
->replaceRandom($token, $key, $bubbleable_metadata);
if (empty($r) && $remove_if_not_present) {
$r = [
array_pop($tokens) => '',
];
}
$replacements = array_merge($replacements, $r);
break;
case "user_defined":
$admin_defined_variable = $configuration[$type][1];
$r = $token_replacer
->replaceUserDefined($token, $key, $admin_defined_variable, $bubbleable_metadata);
if (empty($r) && $remove_if_not_present) {
$r = [
array_pop($tokens) => '',
];
}
$replacements = array_merge($replacements, $r);
break;
default:
break;
}
}
else {
$r = $token_replacer
->replaceExoticToken($token, $key, $bubbleable_metadata);
$replacements = array_merge($replacements, $r);
}
}
return $replacements;
}
}
/**
* Helper function for replacing links with token.
*/
function replace_links_with_tokens(Token $token_service, $replace_with, $relevant_link, &$links, BubbleableMetadata $bubbleableMetadata) {
$uuId_from_link = substr($relevant_link['id'], strpos($relevant_link['id'], ":") + 1, strlen($relevant_link['id']));
$config_menu = \Drupal::entityTypeManager()
->getStorage('link_configuration_storage')
->load($uuId_from_link);
// Replace nothing to mess here all action is in hook.
if (!empty($config_menu)) {
$configuration = unserialize($config_menu->configurationSerialized);
$links[$relevant_link['id']][$replace_with] = $token_service
->replace($links[$relevant_link['id']][$replace_with], [], [
"configuration" => $configuration,
], $bubbleableMetadata);
if (is_null($links[$relevant_link['id']][$replace_with])) {
$links[$relevant_link['id']][$replace_with] = $token_service
->replace($config_menu->linkid, [], [
"configuration" => $configuration,
], $bubbleableMetadata);
}
$links[$relevant_link['id']]["options"]["bubleble_metadata"] = $bubbleableMetadata;
}
}
/**
* @param $links
*/
function menu_token_prepare_context_replacement(&$links) {
$token_service = \Drupal::token();
$bubbleable_metadata = new BubbleableMetadata();
foreach ($links as $key => $linkData) {
try {
$links[$key]["link"]["url"] = $token_service
->replace($linkData["link"]["url"], [], [
"configuration" => $linkData["config"],
], $bubbleable_metadata);
$links[$key]["link"]["title"] = $token_service
->replace($linkData["link"]["title"], [], [
"configuration" => $linkData["config"],
], $bubbleable_metadata);
$links[$key]["link"]["options"]["bubleble_metadata"] = $bubbleable_metadata;
} catch (Exception $exception) {
}
$links[$key] = $links[$key]["link"];
}
}
/**
* Replace links with tokens.
*/
function menu_token_menu_links_discovered_alter(&$links) {
$context_manager = \Drupal::service('menu_token.context_manager');
$context_manager
->clear();
$undiscoveredDef = $context_manager
->getUndiscoveredMenuDefinitions();
$links = array_merge($links, $undiscoveredDef);
// Load configuration from entity.
$relevant_links = array_filter($links, function ($k) {
if (!isset($k['id'])) {
$k['id'] = 0;
}
return strpos($k['id'], 'menu_link_content:') === 0;
});
$token_service = \Drupal::token();
$bubbleable_metadata = new BubbleableMetadata();
if (!empty($relevant_links) && is_array($relevant_links)) {
foreach ($relevant_links as $relevant_link) {
$uuId_from_link = substr($relevant_link['id'], strpos($relevant_link['id'], ":") + 1, strlen($relevant_link['id']));
$configMenu = \Drupal::entityTypeManager()
->getStorage('link_configuration_storage')
->load($uuId_from_link);
if (!empty($configMenu)) {
$config = unserialize($configMenu->configurationSerialized);
$context_manager
->prepareContextualLinks($relevant_link, $config);
replace_links_with_tokens($token_service, "url", $relevant_link, $links, $bubbleable_metadata);
replace_links_with_tokens($token_service, "title", $relevant_link, $links, $bubbleable_metadata);
}
}
}
}
Functions
Name | Description |
---|---|
menu_token_custom_entity_callback | Ajax callback for the method select dropdown. |
menu_token_custom_entity_submit | Custom form submit handler. |
menu_token_form_menu_link_content_form_alter | Implements hook_form_FORM_ID_alter(). |
menu_token_form_submit | Custom form submit handler. |
menu_token_help | Implements hook_help(). |
menu_token_menu_links_discovered_alter | Replace links with tokens. |
menu_token_prepare_context_replacement | |
menu_token_tokens | Implements hook_tokens(). |
replace_links_with_tokens | Helper function for replacing links with token. |