menu_link_attributes.module in Menu Link Attributes 8
Core file of the Menu Link Attributes module.
File
menu_link_attributes.moduleView source
<?php
/**
* @file
* Core file of the Menu Link Attributes module.
*/
use Drupal\Core\Form\FormStateInterface;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Url;
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/
function menu_link_attributes_form_menu_link_content_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
$account = \Drupal::currentUser();
$attributes = \Drupal::config('menu_link_attributes.config')
->get('attributes') ?: [];
$menu_link = $form_state
->getFormObject()
->getEntity();
$menu_link_options = $menu_link->link ? $menu_link->link
->first()->options : [];
if (!$account
->hasPermission('use menu link attributes')) {
$form_state
->set('menu_link_options', $menu_link_options);
$form['actions']['submit']['#submit'][] = 'menu_link_attributes_menu_link_content_form_preserve';
return;
}
$form['options']['attributes'] = [
'#type' => 'details',
'#title' => t('Attributes'),
'#weight' => -3,
'#tree' => TRUE,
];
$form['options']['container_attributes'] = [
'#type' => 'details',
'#title' => t('Container attributes'),
'#description' => t('These attributes are applied to the container element (<code><li></code>) of the menu link.'),
'#weight' => -2,
'#tree' => TRUE,
'#access' => FALSE,
];
$config_path = Url::fromRoute('menu_link_attributes.config')
->toString();
$referrer_path = parse_url(\Drupal::request()->headers
->get('referer'))['path'];
$coming_from_config = $config_path == $referrer_path;
// Open <details> element if coming from config page.
if ($coming_from_config) {
$form['options']['attributes']['#open'] = TRUE;
}
$destination = \Drupal::destination()
->getAsArray();
$config_path = Url::fromRoute('menu_link_attributes.config', [], [
'query' => $destination,
])
->toString();
if ($account
->hasPermission('administer menu link attributes')) {
if (count($attributes)) {
$form['options']['attributes']['#description'] = '<small>' . t('Manage available attributes <a href="@config">here</a>.', [
'@config' => $config_path,
]) . '</small>';
}
else {
$form['options']['attributes']['help'] = [
'#markup' => t('Manage available attributes <a href="@config">here</a>.', [
'@config' => $config_path,
]),
];
}
}
$autofocus = FALSE;
// Iterate all defined attributes and create text field for them.
foreach ($attributes as $attribute => $info) {
$is_container_attribute = menu_link_attributes_is_container_attribute($attribute);
$attribute_formatted = $attribute;
$attributes_key = 'attributes';
if ($is_container_attribute) {
$attributes_key = 'container_attributes';
$attribute_formatted = preg_replace('/^container_/', '', $attribute);
}
// Provide default label / description for attributes.
if (empty($info['label'])) {
$info['label'] = str_replace('-', ' ', Unicode::ucfirst($attribute_formatted));
}
if (empty($info['description'])) {
$info['description'] = t('Enter value for <code>@attribute</code> attribute.', [
'@attribute' => $attribute_formatted,
]);
}
// Determine type based on options field.
if (empty($info['type'])) {
$type = !empty($info['options']) ? 'select' : 'textfield';
}
else {
$type = $info['type'];
}
$form['options']['attributes'][$attribute] = [
'#type' => $type,
'#title' => $info['label'],
'#description' => $info['description'],
'#default_value' => isset($menu_link_options[$attributes_key][$attribute_formatted]) ? $menu_link_options[$attributes_key][$attribute_formatted] : (isset($info['default_value']) ? $info['default_value'] : ''),
];
// Fill options if select list.
if ($type == 'select') {
$form['options']['attributes'][$attribute]['#empty_option'] = t('- Select -');
$form['options']['attributes'][$attribute]['#options'] = $info['options'];
}
// Fill options if type is "managed_file".
if ($type === 'managed_file' && !empty($info['upload_location'])) {
$form['options']['attributes'][$attribute]['#upload_location'] = $info['upload_location'];
}
// Add "autofocus" attribute for first attribute input field
// if coming from config page.
if ($coming_from_config && !$autofocus) {
$form['options']['attributes'][$attribute]['#attributes'] = [
'autofocus' => 'autofocus',
];
$autofocus = TRUE;
}
}
$form['actions']['submit']['#submit'][] = 'menu_link_attributes_menu_link_content_form_submit';
}
/**
* Submit function for menu add / edit form.
*/
function menu_link_attributes_menu_link_content_form_submit($form, FormStateInterface $form_state) {
/** @var \Drupal\menu_link_content\Form\MenuLinkContentForm $form_object */
$form_object = $form_state
->getFormObject();
$menu_link = $form_object
->getEntity();
if (!$menu_link->link || $menu_link->link
->isEmpty()) {
return;
}
$menu_link_options = $menu_link->link
->first()->options ?: [];
$menu_link_attributes = [
'attributes' => $form_state
->getValue('attributes'),
];
foreach ($menu_link_attributes['attributes'] as $attribute_name => &$attribute_value) {
// Make "class" attributes an array.
if (in_array($attribute_name, [
'class',
'container_class',
]) && !is_array($attribute_value)) {
$attribute_value = [
(string) $attribute_value,
];
}
$is_container_attribute = menu_link_attributes_is_container_attribute($attribute_name);
if ($is_container_attribute) {
unset($menu_link_attributes['attributes'][$attribute_name]);
$attribute_name = preg_replace('/^container_/', '', $attribute_name);
$menu_link_attributes['container_attributes'][$attribute_name] = $attribute_value;
}
}
// Remove empty attribute values.
foreach ($menu_link_attributes as $attribute_group => $grouped_attributes) {
foreach ($grouped_attributes as $group_attribute_name => $group_attribute_value) {
if (is_array($group_attribute_value)) {
$menu_link_attributes[$attribute_group][$group_attribute_name] = array_filter($group_attribute_value);
}
elseif (mb_strlen($group_attribute_value) === 0) {
unset($menu_link_attributes[$attribute_group][$group_attribute_name]);
}
}
}
$menu_link_attributes = array_filter($menu_link_attributes);
$menu_link_options = array_merge_recursive($menu_link_options, $menu_link_attributes);
if (count($menu_link_attributes)) {
$menu_link->link
->first()->options = $menu_link_options;
$menu_link
->save();
}
}
/**
* Preserve menu link attributes on form submit.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
function menu_link_attributes_menu_link_content_form_preserve(array $form, FormStateInterface $form_state) {
/** @var \Drupal\menu_link_content\Form\MenuLinkContentForm $form_object */
$form_object = $form_state
->getFormObject();
$menu_link = $form_object
->getEntity();
if (!$menu_link->link || $menu_link->link
->isEmpty()) {
return;
}
$menu_link_options = $form_state
->get('menu_link_options');
if (!empty($menu_link_options)) {
$menu_link->link->options = $menu_link_options;
$menu_link
->save();
}
}
/**
* Helper function to determine if attribute is a container attribute.
*
* @param string $attribute_name
* The name of the attribute.
*
* @return bool
* TRUE if the attribute is a container attribute.
*/
function menu_link_attributes_is_container_attribute($attribute_name) {
$attributes = \Drupal::config('menu_link_attributes.config')
->get('attributes') ?: [];
$info = $attributes[$attribute_name];
$possible_container_attribute = strpos($attribute_name, 'container_') === 0;
$disabled_container = isset($info['container']) && !$info['container'];
$possible_container_attribute = $possible_container_attribute && !$disabled_container;
$container_attribute_enabled = isset($info['container']) && $info['container'];
$is_container_attribute = $possible_container_attribute || $container_attribute_enabled;
return $is_container_attribute;
}
/**
* Implements template_preprocess_menu().
*/
function menu_link_attributes_preprocess_menu(&$variables) {
_menu_link_attributes_preprocess_menu_items($variables['items']);
}
/**
* Helper function to recursively set list item attributes.
*/
function _menu_link_attributes_preprocess_menu_items(&$items) {
foreach ($items as $item) {
/** @var \Drupal\Core\Menu\MenuLinkDefault $menu_link */
$menu_link = isset($item['original_link']) ? $item['original_link'] : NULL;
$options = !empty($menu_link) ? $menu_link
->getOptions() : NULL;
// Apply container attributes on <li> element.
if ($options && isset($options['container_attributes'])) {
foreach ($options['container_attributes'] as $attribute => $value) {
$item['attributes']
->setAttribute($attribute, $value);
}
}
if (!empty($item['below'])) {
_menu_link_attributes_preprocess_menu_items($item['below']);
}
}
}
Functions
Name | Description |
---|---|
menu_link_attributes_form_menu_link_content_form_alter | Implements hook_form_BASE_FORM_ID_alter(). |
menu_link_attributes_is_container_attribute | Helper function to determine if attribute is a container attribute. |
menu_link_attributes_menu_link_content_form_preserve | Preserve menu link attributes on form submit. |
menu_link_attributes_menu_link_content_form_submit | Submit function for menu add / edit form. |
menu_link_attributes_preprocess_menu | Implements template_preprocess_menu(). |
_menu_link_attributes_preprocess_menu_items | Helper function to recursively set list item attributes. |