• Reset your password
Home
OO PHP, Drupal, Symfony Developer and Architect
Tim Rabbetts

Main navigation

  • Home
  • Blog
  • Log in

Drupal 8: add custom field to menu and template

Breadcrumb

  • Home
  • blog
  • drupal 8 add custom field to menu and template
  • Drupal 8: add custom field to menu and template
Tim
Rabbetts
By zarexogre | Thu, 02/04/2020
programmer, programming, code
drupal

Had need to add custom image field to menu items.  First thing is to attach the field using this code in custom module.

function iop_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
  if ($entity_type->id() === 'menu_link_content') {
    $fields['menu_link_image'] = BaseFieldDefinition::create('image')
      ->setLabel(t('Menu link image'))
      ->setDescription(t('Upload the image related to this menu item'))
      ->setDisplayOptions('form', array('type' => 'string', 'weight' => 0));
    return $fields;
  }
}

This will add the field, but we need to update the db now or when you save menu item it will complain about missing columns.

drush updatedb --entity-updates

Not the new field will show and save.  But when you create a template for the menu, you will notice that this data isnt available, so you need to preprocess menu and add it.

function MYMODULE_theme_preprocess_menu(&$variables, $hook) {

  // Add the custom image field so can theme in template.
  if ($variables['theme_hook_original'] == 'menu__microsites_menu') {
    foreach ($variables['items'] as $key => &$item) {
      $entity = \Drupal::entityTypeManager()->getStorage('menu_link_content')->loadByProperties(array('uuid' => $item['original_link']->getDerivativeId()));
      if (!empty($entity)) {
        $entity = array_shift($entity);
        $image = $entity->get('menu_link_image')->entity;
        if (!empty($image)) {
          $item['image'] = $image->getFileUri();
        }
      }
    }
  }

}

Then in the menu template, e.g menu--my-menu.html.twig put this:

{% import _self as menus %}
{{ menus.menu_links(items, attributes, 0) }}

{% macro menu_links(items, attributes, menu_level) %}
  {% import _self as menus %}
  {% if items %}
    {% if menu_level == 0 %}
<ul{{ attributes.addClass('menu') }}>
  {% else %}
  <ul class="menu">
    {% endif %}
    {% for item in items %}
      {%
        set classes = [
        'menu-item',
        item.is_expanded ? 'menu-item--expanded',
        item.is_collapsed ? 'menu-item--collapsed',
        item.in_active_trail ? 'menu-item--active-trail',
      ]
      %}
      <li{{ item.attributes.addClass(classes) }}>
          {% if item.image is empty %}
            {{ link(item.title, item.url) }}
          {% else %}
            <a href="{{ item.url }}">
              <img src="{{ item.image | image_style('microsites_logo') }}"/>
            </a>
          {% endif %}

          {% if item.below %}
            {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
          {% endif %}
      </li>
    {% endfor %}
  </ul>
  {% endif %}
  {% endmacro %}

All done should now theme image in menu.