You are here

mmenu.module in Mobile sliding menu 8

Same filename and directory in other branches
  1. 7.3 mmenu.module
  2. 7 mmenu.module
  3. 7.2 mmenu.module

Primarily Drupal hooks and global API functions to manipulate mmenus.

File

mmenu.module
View source
<?php

/**
 * @file
 * Primarily Drupal hooks and global API functions to manipulate mmenus.
 */
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\block\Entity\Block;
use Drupal\Component\Utility\Html;
use Drupal\Core\StringTranslation\TranslatableMarkup;

/**
 * Implements hook_mmenu().
 */
function mmenu_mmenu() {
  return [
    'mmenu_left' => [
      'enabled' => TRUE,
      'name' => 'mmenu_left',
      'title' => t('Left menu'),
      'blocks' => [
        [
          'title' => t('Main menu'),
          'plugin_id' => 'mmenu:primary_navigation',
          //'plugin_id' => 'system_menu_block:main',
          'collapsed' => FALSE,
          'wrap' => FALSE,
        ],
        [
          'title' => t('Admin menu'),
          'plugin_id' => 'system_menu_block:admin',
          'collapsed' => FALSE,
          'wrap' => FALSE,
        ],
      ],
      'options' => [
        'extensions' => [
          'position-left',
          'theme-black',
          'border-full',
          'fx-menu-fade',
          'fx-panels-none',
          'fx-listitems-slide',
        ],
        'drag' => [
          'menu' => [
            'open' => TRUE,
            'node' => 'body',
          ],
        ],
        'clickOpen' => [
          'open' => TRUE,
          'selector' => '#logo',
        ],
        'navbars' => [
          [
            'position' => 'top',
            'content' => [
              'breadcrumbs',
              'close',
            ],
          ],
        ],
        'counters' => TRUE,
        'offCanvas' => TRUE,
      ],
      'configurations' => [
        'drag' => [
          'menu' => [
            'width' => [
              'perc' => 0.8,
              'min' => 140,
              'max' => 440,
            ],
            'height' => [
              'perc' => 0.8,
              'min' => 140,
              'max' => 880,
            ],
          ],
        ],
      ],
    ],
    'mmenu_right' => [
      'enabled' => FALSE,
      'name' => 'mmenu_right',
      'title' => t('Right menu'),
      'blocks' => [
        [
          'title' => t('Search'),
          'plugin_id' => 'mmenu:search',
          'collapsed' => FALSE,
          'wrap' => TRUE,
        ],
        [
          'title' => t('Admin menu'),
          'plugin_id' => 'system_menu_block:admin',
          'collapsed' => FALSE,
          'wrap' => FALSE,
        ],
      ],
      'options' => [
        'extensions' => [
          'position-right',
        ],
        'drag' => [
          'menu' => [
            'open' => TRUE,
            'node' => 'body',
          ],
        ],
        'clickOpen' => [
          'open' => TRUE,
          'selector' => '.header-logo',
        ],
        'counters' => TRUE,
      ],
      'configurations' => [],
    ],
    'mmenu_top' => [
      'enabled' => FALSE,
      'name' => 'mmenu_top',
      'title' => t('Top menu'),
      'blocks' => [
        [
          'title' => t('Log in'),
          'plugin_id' => 'mmenu:search',
          'collapsed' => FALSE,
          'wrap' => TRUE,
        ],
      ],
      'options' => [
        'extensions' => [
          'position-top',
        ],
      ],
      'configurations' => [],
    ],
    'mmenu_bottom' => [
      'enabled' => FALSE,
      'name' => 'mmenu_bottom',
      'title' => t('Bottom menu'),
      'blocks' => [
        [
          'title' => t('Administration'),
          'plugin_id' => 'mmenu:search',
          'collapsed' => FALSE,
          'wrap' => TRUE,
          'menu_parameters' => [
            'min_depth' => 2,
          ],
        ],
      ],
      'options' => [
        'extensions' => [
          'position-bottom',
        ],
      ],
      'configurations' => [],
    ],
  ];
}

/**
 * Implements hook_mmenu_theme().
 */
function mmenu_mmenu_theme() {
  return array(
    'mm-basic' => array(
      'name' => 'mm-basic',
      'title' => t('mm-basic'),
      'library' => array(
        'mmenu/mmenu.basic_theme',
      ),
    ),
    'mm-fresh' => array(
      'name' => 'mm-fresh',
      'title' => t('mm-fresh'),
      'library' => array(
        'mmenu/mmenu.fresh_theme',
      ),
    ),
  );
}

/**
 * Implements hook_mmenu_effect().
 */
function mmenu_mmenu_effect() {
  return array(
    'mm-fullscreen' => array(
      'name' => 'mm-fullscreen',
      'title' => t('Makes the menu will fill up 100% of the available width'),
      'css' => array(),
    ),
    'mm-slide' => array(
      'name' => 'mm-slide',
      'title' => t('Makes the menu slide in from the side.'),
      'css' => array(),
    ),
    'mm-zoom-menu' => array(
      'name' => 'mm-zoom-menu',
      'title' => t('Makes the menu zoom in.'),
      'css' => array(),
    ),
    'mm-zoom-panels' => array(
      'name' => 'mm-zoom-panels',
      'title' => t('Makes the panels zoom out while opening a submenu.'),
      'css' => array(),
    ),
  );
}

/**
 * Implements hook_mmenu_icon().
 */
function mmenu_mmenu_icon() {
  $icons = array(
    'path' => array(
      '<nolink>' => 'icon-plus',
      '<firstchild>' => 'icon-plus',
      '<front>' => 'icon-home',
      'home' => 'icon-home',
      'about' => 'icon-office',
      'contact' => 'icon-envelope',
      'user' => 'icon-profile',
      'user/login' => 'icon-lock',
      'user/logout' => 'icon-unlocked',
      'user/register' => 'icon-signup',
      'cart' => 'icon-cart',
      'cart/checkout' => 'icon-money-bag',
      'admin/dashboard' => 'icon-dashboard',
      'admin/store' => 'icon-cart',
      'admin/content' => 'icon-file3',
      'admin/structure' => 'icon-tree',
      'admin/appearance' => 'icon-paint-format',
      'admin/people' => 'icon-users2',
      'admin/modules' => 'icon-library',
      'admin/config' => 'icon-settings',
      'admin/reports' => 'icon-stats',
      'admin/help' => 'icon-question',
    ),
    'block' => array(
      array(
        'module' => 'system',
        'delta' => 'main-menu',
        'icon_class' => 'icon-enter',
      ),
      array(
        'module' => 'system',
        'delta' => 'user-menu',
        'icon_class' => 'icon-enter',
      ),
      array(
        'module' => 'system',
        'delta' => 'devel',
        'icon_class' => 'icon-enter',
      ),
      array(
        'module' => 'system',
        'delta' => 'navigation',
        'icon_class' => 'icon-enter',
      ),
      array(
        'module' => 'system',
        'delta' => 'management',
        'icon_class' => 'icon-enter',
      ),
      array(
        'module' => 'search',
        'delta' => 'search_form_block',
        'icon_class' => 'icon-search',
      ),
      array(
        'module' => 'mmenu',
        'delta' => 'mmenu_search',
        'icon_class' => 'icon-search',
      ),
    ),
  );
  return $icons;
}

/**
 * Implements hook_theme().
 */
function mmenu_theme() {
  $module_path = drupal_get_path('module', 'mmenu');
  return array(
    'mmenu' => array(
      'render element' => 'elements',
      'template' => 'mmenu',
      'path' => $module_path . '/tpl',
    ),
    'mmenu_tree' => array(
      'variables' => array(
        'tree' => NULL,
        'reset' => FALSE,
        'depth' => 1,
      ),
      'function' => 'theme_mmenu_tree',
    ),
    'mmenu_primary_navigation' => [
      'render element' => 'children',
    ],
  );
}

/**
 * Implements hook_libraries_info().
 */
function mmenu_libraries_info() {
  $libraries['mmenu.main'] = array(
    'name' => 'Mmenu libraries',
    'vendor url' => 'http://mmenu.frebsite.nl',
    'download url' => 'http://mmenu.frebsite.nl/download.php',
    'version arguments' => array(
      'file' => 'main/src/js/jquery.mmenu.min.js',
      'pattern' => '/jQuery mmenu v(\\d+\\.+\\d+.+\\d+)/',
      'lines' => 2,
    ),
    'files' => array(
      'js' => array(
        'src/js/jquery.mmenu.min.all.js',
      ),
      'css' => array(
        'src/css/jquery.mmenu.all.css',
      ),
    ),
    'path' => 'main',
    'library path' => libraries_get_path('mmenu'),
  );
  $libraries['mmenu.hammer'] = array(
    'name' => 'Hammer libraries',
    'vendor url' => 'http://eightmedia.github.io/hammer.js',
    'download url' => 'https://github.com/EightMedia/hammer.js',
    'version arguments' => array(
      'file' => 'hammer/hammer.js',
      'pattern' => '/Hammer.JS - v(\\d+\\.+\\d+.+\\d+) -/',
      'lines' => 1,
    ),
    'files' => array(
      'js' => array(
        'hammer.js',
      ),
    ),
    'path' => 'hammer',
    'library path' => libraries_get_path('mmenu'),
  );
  $libraries['mmenu.jquery.hammer'] = array(
    'name' => 'jQuery plugin for Hammer.js',
    'vendor url' => 'https://github.com/hammerjs/jquery.hammer.js',
    'download url' => 'https://github.com/hammerjs/jquery.hammer.js',
    'version arguments' => array(
      'file' => 'jquery.hammer/package.json',
      'pattern' => '/"version": "(\\d+\\.+\\d+.+\\d+)"/',
      'lines' => 3,
    ),
    'files' => array(
      'js' => array(
        'jquery.hammer.js',
      ),
    ),
    'path' => 'jquery.hammer',
    'library path' => libraries_get_path('mmenu'),
  );
  $libraries['mmenu.icomoon'] = array(
    'name' => 'Custom Build and Crisp Icon Fonts',
    'vendor url' => 'https://icomoon.io',
    'download url' => 'https://icomoon.io/app/#/select',
    'version' => 'icomoon',
    'files' => array(
      'css' => array(
        'icomoon.css',
      ),
    ),
    'path' => 'icomoon',
    'library path' => libraries_get_path('mmenu'),
  );
  return $libraries;
}

/**
 * Gets a list of available mmenus.
 *
 * @param string $mmenu_name
 *   A mmenu name if you just want to get a particular mmenu.
 *   Leaves empty if you want to get all available mmenus.
 *
 * @return array
 *   Particular mmenu if the 'mmenu_name' is given.
 *   All available mmenus otherwise.
 */
function mmenu_list($mmenu_name = '') {
  $cid = 'mmenus:cache';

  // Gets mmenus from cache if available.
  if ($cached = \Drupal::cache()
    ->get($cid)) {
    $mmenus = $cached->data;

    // Invoke hook_mmenu_alter().
    // To allow all modules to alter the mmenus.
    // Don't save the altered values into cache.
    \Drupal::moduleHandler()
      ->alter('mmenu', $mmenus);
    if (empty($mmenu_name)) {
      return $mmenus;
    }
    elseif (isset($mmenus[$mmenu_name])) {
      return $mmenus[$mmenu_name];
    }
    else {
      return array();
    }
  }

  // Gets mmenus from hook defined.
  $mmenus = \Drupal::moduleHandler()
    ->invokeAll('mmenu');

  // Gets the default options and configurations.
  $default_options = mmenu_get_default_options();
  $default_configurations = mmenu_get_default_configurations();
  $default_mmenu = array(
    'enabled' => FALSE,
    'name' => '',
    'blocks' => array(),
    'options' => '',
    'configurations' => '',
    'custom' => array(),
  );
  foreach ($mmenus as $mmenu_key => $mmenu) {
    $mmenu += $default_mmenu;

    // Merges with the default values.
    $mmenu['options'] += $default_options;

    // Merges with the default values.
    $mmenu['configurations'] += $default_configurations;

    // Takes mmenu settings from user self defined if available.
    $configurable_mmenu = \Drupal::config('mmenu.settings')
      ->get('mmenu_item_' . $mmenu['name']);
    if (!empty($configurable_mmenu)) {
      if (!isset($configurable_mmenu['options'])) {
        $configurable_mmenu['options'] = array();
      }
      if (!isset($configurable_mmenu['configurations'])) {
        $configurable_mmenu['configurations'] = array();
      }
      if (!isset($configurable_mmenu['custom'])) {
        $configurable_mmenu['custom'] = array();
      }
      $mmenu = $configurable_mmenu + $mmenu;
      $mmenu['options'] = $configurable_mmenu['options'] + $mmenu['options'];
      $mmenu['configurations'] = $configurable_mmenu['configurations'] + $mmenu['configurations'];
      $mmenu['custom'] = $configurable_mmenu['custom'] + $mmenu['custom'];
    }
    $mmenus[$mmenu_key] = $mmenu;

    // Resets blocks values.
    foreach ($mmenu['blocks'] as $block_key => $block) {
      $mmenus[$mmenu_key]['blocks'][$block_key]['collapsed'] = isset($block['collapsed']) ? $block['collapsed'] : TRUE;
      $mmenus[$mmenu_key]['blocks'][$block_key]['wrap'] = isset($block['wrap']) ? $block['wrap'] : FALSE;
    }
  }

  // Caches the mmenus.
  // @TODO: remove comment.
  // \Drupal::cache()->set($cid, $mmenus);
  // Invoke hook_mmenu_alter().
  // To allow all modules to alter the mmenus.
  // Don't save the altered values into cache.
  \Drupal::moduleHandler()
    ->alter('mmenu', $mmenus);
  if (!empty($mmenu_name)) {
    if (isset($mmenus[$mmenu_name])) {
      return $mmenus[$mmenu_name];
    }
    else {
      return array();
    }
  }
  return $mmenus;
}

/**
 * Gets a list of available mmenu themes.
 *
 * @param string $theme_name
 *   A class name if you just want to get a particular mmenu theme.
 *   Leaves empty if you want to get all available mmenu themes.
 *
 * @return array
 *   Particular mmenu theme if the 'theme_name' is given.
 *   All available mmenu themes otherwise.
 */
function mmenu_theme_list($theme_name = '') {

  // Get mmenu themes from hook.
  $themes = Drupal::moduleHandler()
    ->invokeAll('mmenu_theme');

  // Invoke hook_mmenu_theme_alter().
  // To allow all modules to alter the mmenu themes.
  Drupal::moduleHandler()
    ->alter('mmenu_theme', $themes);
  if (!empty($theme_name)) {
    if (isset($themes[$theme_name])) {
      return $themes[$theme_name];
    }
    else {
      return array();
    }
  }
  return $themes;
}

/**
 * Gets a list of available mmenu effects.
 *
 * @param string $effect_name
 *   A effect name if you just want to get a particular mmenu effect.
 *   Leaves empty if you want to get all available mmenu effects.
 *
 * @return array
 *   Particular mmenu effect if the 'effect_name' is given.
 *   All available mmenu effects otherwise.
 */
function mmenu_effect_list($effect_name = '') {

  // Get mmenu effects from hook.
  $effects = Drupal::moduleHandler()
    ->invokeAll('mmenu_effect');

  // Invoke hook_mmenu_effect_alter().
  // To allow all modules to alter the mmenu effect.
  Drupal::moduleHandler()
    ->alter('mmenu_effect', $effects);
  if (!empty($effect_name)) {
    if (isset($effects[$effect_name])) {
      return $effects[$effect_name];
    }
    else {
      return array();
    }
  }
  return $effects;
}

/**
 * Gets a list of available mmenu icons.
 *
 * @return array
 *   All available mmenu icons.
 */
function mmenu_icon_list() {

  // Get mmenu icons from hook.
  $icons = Drupal::moduleHandler()
    ->invokeAll('mmenu_icon');

  // Invoke hook_mmenu_icon_alter().
  // To allow all modules to alter the mmenu icon.
  Drupal::moduleHandler()
    ->alter('mmenu_icon', $icons);
  return $icons;
}

/**
 * Gets default options of the mmenu.
 *
 * @return array
 *   Default mmenu options.
 */
function mmenu_get_default_options() {
  return [];
}

/**
 * Gets default configurations of the mmenu.
 *
 * @return array
 *   Default mmenu configurations.
 */
function mmenu_get_default_configurations() {
  return [];
}

/**
 * Generates the mmenu css list and adds to Drupal.
 *
 * @param array $variables
 *   Render array from parent method.
 */
function mmenu_add_libraries(&$variables) {
  $mmenu = $variables['mmenu'];

  // Uses custom js handler if it is set.
  if (isset($mmenu['custom']['library'])) {
    foreach ($mmenu['custom']['library'] as $lib) {
      $variables['#attached']['library'][] = $lib;
    }
  }
  else {
    $variables['#attached']['library'][] = 'mmenu/mmenu.default';
  }

  // Adds mmenu theme styles.
  if (isset($mmenu['options']['classes'])) {
    $themes = explode(' ', $mmenu['options']['classes']);
    foreach ($themes as $theme) {
      $mmenu_theme = mmenu_theme_list($theme);
      if (isset($mmenu_theme['library'])) {
        foreach ($mmenu_theme['library'] as $lib) {
          $variables['#attached']['library'][] = $lib;
        }
      }
    }
  }

  // Adds mmenu effect styles.
  if (isset($mmenu['options']['effects'])) {
    foreach ($mmenu['options']['effects'] as $k => $v) {
      $mmenu_effect = mmenu_effect_list($k);
      if (isset($mmenu_effect['library'])) {
        foreach ($mmenu_effect['library'] as $lib) {
          $variables['#attached']['library'][] = $lib;
        }
      }
    }
  }
}

/**
 * Implements hook_page_bottom().
 */
function mmenu_page_bottom(array &$page_bottom) {

  // Gets all mmenus markups and adds them to page.
  $mmenus = mmenu_list();
  $js_settings = array();
  foreach ($mmenus as $mmenu) {
    $name = $mmenu['name'];

    // Checks if the mmenu was allowed to show.
    if (mmenu_display_access($mmenu)) {
      $page_bottom['mmenu'][$name] = array(
        '#theme' => 'mmenu',
        '#mmenu' => $mmenu,
      );
      $js_settings[$name] = $mmenu;
    }
  }

  // Outputs the mmenus settings as JSON, then we can do some custom
  // stuffs in our own JS handlers.
  if (count($js_settings) > 0) {
    $page_bottom['#attached']['drupalSettings']['mmenu'] = $js_settings;
  }
  if (isset($page_bottom['mmenu']) && count($page_bottom['mmenu']) > 0) {

    // Loads libraries.
    $page_bottom['#attached']['library'][] = 'mmenu/mmenu.hammer';
    $page_bottom['#attached']['library'][] = 'mmenu/mmenu.jquery.hammer';
    $page_bottom['#attached']['library'][] = 'mmenu/mmenu.main';
    $page_bottom['#attached']['library'][] = 'mmenu/mmenu.icomoon';
    $page_bottom['#attached']['library'][] = 'mmenu/mmenu.basic_theme';
    $page_bottom['#attached']['library'][] = 'mmenu/mmenu.fresh_theme';
  }
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function mmenu_theme_suggestions_mmenu(array $variables) {
  $suggestions = array();
  if (!empty($variables['elements']['#mmenu']['name'])) {

    // Template suggestions.
    // mmenu--mmenu-right.html.twig.
    $suggestions[] = 'mmenu__' . $variables['elements']['#mmenu']['name'];
  }
  return $suggestions;
}

/**
 * Implements hook_theme_suggestions_HOOK_alter().
 */
function mmenu_theme_suggestions_block_alter(array &$suggestions, array $variables) {
  if (in_array('mmenu_block', $variables['elements']['#cache']['tags'])) {

    // Adds more template suggestions such as
    // block--mmenu-search--mmenu.html.twig or
    // block--mmenu-search--mmenu-mmenu-right.html.twig.
    $suggestions[] = 'block__' . $variables['elements']['#plugin_id'] . '__' . 'mmenu';
    foreach ($variables['elements']['#cache']['tags'] as $tag) {
      if (strpos($tag, 'mmenu_block:') === 0) {
        list(, $mmenu_name) = explode(':', $tag);
        $suggestions[] = 'block__' . $variables['elements']['#plugin_id'] . '__' . 'mmenu_' . $mmenu_name;
      }
    }
  }
}

/**
 * Processes variables for mmenu.tpl.php.
 *
 * Most themes utilize their own copy of mmenu.tpl.php. The default is located
 * inside "modules/mmenu/tpl/mmenu.tpl.php". Look in there for the full list of
 * variables.
 *
 * The $variables array contains the following arguments:
 * - $mmenu
 * - $id
 * - $name
 * - $blocks
 *
 * @see mmenu.tpl.php
 */
function template_preprocess_mmenu(&$variables) {
  $variables['mmenu'] = $variables['elements']['#mmenu'];
  $variables['id'] = $variables['elements']['#mmenu']['name'];
  $variables['name'] = $variables['elements']['#mmenu']['name'];
  $variables['blocks'] = array();
  static $mmenu_tree;

  // Get existing menus list from the site.
  $system_menus = mmenu_menu_get_menus();
  foreach ($variables['mmenu']['blocks'] as $mmenu_block) {
    if (empty($mmenu_block['plugin_id'])) {
      continue;
    }
    list($block_module, $block_delta) = explode(':', $mmenu_block['plugin_id']);

    // When it is a menu block.
    if ($block_module == 'system_menu_block' && isset($system_menus[$block_delta])) {

      // Builds the menu tree for rendering markup.
      $menu_parameters = isset($mmenu_block['menu_parameters']) ? $mmenu_block['menu_parameters'] : array();
      $menu_parameters['conditions']['hidden'] = 0;
      if (!isset($mmenu_tree[$block_delta])) {
        $menu_tree = \Drupal::menuTree();
        $parameters = new MenuTreeParameters();
        $min_depth = isset($menu_parameters['min_depth']) ? $menu_parameters['min_depth'] : 1;
        $parameters
          ->setMinDepth($min_depth);
        $tree = $menu_tree
          ->load($block_delta, $parameters);
        $mmenu_tree[$block_delta] = $tree;
      }
      else {
        $tree = $mmenu_tree[$block_delta];
      }
      $block['content'] = array(
        '#theme' => 'mmenu_tree',
        '#tree' => $tree,
        '#reset' => TRUE,
        '#depth' => 1,
      );
    }
    else {

      // dpm($mmenu_block['plugin_id'], 'plugin_id');
      $block_manager = \Drupal::service('plugin.manager.block');

      // You can hard code configuration or you load from settings.
      $plugin_block = $block_manager
        ->createInstance($mmenu_block['plugin_id'], []);

      // Some blocks might implement access check.
      $access_result = $plugin_block
        ->access(\Drupal::currentUser());

      // Return empty render array if user doesn't have access.
      // $access_result can be boolean or an AccessResult class
      if (is_object($access_result) && $access_result
        ->isForbidden() || is_bool($access_result) && !$access_result) {

        // You might need to add some cache tags/contexts.
        $block['content'] = [
          '#markup' => '',
        ];
      }
      else {
        $content = $plugin_block
          ->build();
        if (!empty($content)) {
          $block['content'] = $content;
        }
      }
    }

    // Uses the mmenu block title if it was defined.
    // Otherwise, uses default block subject.
    $subject = '';
    if ($mmenu_block['title'] == '<none>') {
      $subject = '';
    }
    elseif (!empty($mmenu_block['title'])) {
      $subject = $mmenu_block['title'];
    }
    elseif (isset($block['subject'])) {
      $subject = $block['subject'];
    }
    else {
      $subject = '';
    }
    $new_block['subject'] = $subject;

    // Renders block content.
    $new_block['content'] = render($block['content']);

    // Checks if the block is collapsed or expanded.
    $new_block['collapsed'] = isset($mmenu_block['collapsed']) ? $mmenu_block['collapsed'] : TRUE;

    // Checks if the block needs to wrap by
    // '<ul><li><span>xxxxxx</span></li></ul>'.
    $new_block['wrap'] = isset($mmenu_block['wrap']) ? $mmenu_block['wrap'] : FALSE;

    // Don't render if block content is empty.
    if (!empty($new_block['content'])) {
      $variables['blocks'][] = $new_block;
    }
  }

  // Adds CSS for particular mmenu.
  mmenu_add_libraries($variables);
}

/**
 * Returns HTML for a wrapper for a mmenu tree.
 *
 * @param array $block
 *   An associative array containing:
 *   - tree: An array containing the tree's items.
 *   - reset: An boolean to determine if needs to reset the static variable.
 *
 * @ingroup themeable
 */
function theme_mmenu_tree(array $block = array(
  'tree' => array(),
  'reset' => FALSE,
  'depth' => 1,
)) {
  $tree = $block['tree'];
  $reset = $block['reset'];
  $depth = $block['depth'];

  // Don't render if block content is empty.
  if (count($tree) <= 0) {
    return '';
  }
  static $mmenu_output = '';
  if ($reset) {
    $mmenu_output = '';
  }
  foreach ($tree as $item) {
    $cur_path = \Drupal::service('path.current')
      ->getPath();
    $menu_path = $item->link
      ->getUrlObject()
      ->toString();

    // Adds classes to li in order to do more customization changes.

    //$mlid = $item->link->getMetadata()['entity_id'] ? $item->link->getMetadata()['entity_id'] : '0';
    $li_class = array();

    //$li_class[] = 'mmenu-mm-list-mlid-' . $mlid;
    $my_menu_path = $item->link
      ->getUrlObject()
      ->toString();
    $my_menu_path = trim($my_menu_path, '<');
    $my_menu_path = trim($my_menu_path, '>');
    $my_menu_path = trim($my_menu_path, '/');
    $my_menu_path = str_replace('/', '-', $my_menu_path);
    if (!empty($my_menu_path)) {
      $li_class[] = 'mmenu-mm-list-path-' . Html::escape($my_menu_path);
    }
    if ($cur_path == $menu_path) {
      $li_class[] = 'active-trail';
    }

    // Gets the classes from the menu attributes.
    if (isset($item->link
      ->getOptions()['attributes']['class']) && count($item->link
      ->getOptions()['attributes']['class']) > 0) {
      $li_class = array_merge($li_class, $item->link
        ->getOptions()['attributes']['class']);
    }
    $icon_class = mmenu_get_icon_class('path', $my_menu_path);

    // In order to support the special_menu_items and menu_firstchild modules.
    $subopen_link_class = '';
    if (in_array($my_menu_path, array(
      '<nolink>',
      '<firstchild>',
    ))) {
      $menu_path = 'javascript:void(0);';
      $subopen_link_class = 'mmenu-mm-subopen';
    }
    $mmenu_output .= '<li class="' . implode(' ', $li_class) . '"><a href="' . $menu_path . '" class="mmenu-mm-list ' . $subopen_link_class . '"><i class="' . $icon_class . '"></i><span class="mmenu-block-title">' . $item->link
      ->getTitle() . '</span></a>';
    if (!empty($item->subtree)) {
      $mmenu_output .= '<ul class="mmenu-mm-list-level-' . ($depth + 1) . '">';
      $subtree = array(
        '#theme' => 'mmenu_tree',
        '#tree' => $item->subtree,
        '#reset' => FALSE,
        '#depth' => $depth + 1,
      );
      render($subtree);
      $mmenu_output .= '</ul>';
    }
    $mmenu_output .= '</li>';
  }
  return '<ul class="mmenu-mm-list-level-' . $depth . '">' . $mmenu_output . '</ul>';
}

/**
 * Gets all Drupal blocks for assigning to a mmenu.
 *
 * @return array
 *   An associative array contains all Drupal blocks.
 */
function mmenu_get_blocks() {
  $blockManager = \Drupal::service('plugin.manager.block');
  $contextRepository = \Drupal::service('context.repository');
  $available_plugins = $blockManager
    ->getDefinitionsForContexts($contextRepository
    ->getAvailableContexts());
  $available_plugins = $blockManager
    ->getSortedDefinitions($available_plugins);
  $options = [];
  foreach ($available_plugins as $key => $definition) {
    if ($definition['category'] instanceof TranslatableMarkup) {
      $category = $definition['category']
        ->render();
    }
    else {
      $category = $definition['category'];
    }
    $admin_label = $definition['admin_label'];
    $options[$category][$key] = $category . ' - ' . $admin_label;
  }

  //  dpm($options);
  return $options;

  //  $block_ids = \Drupal::entityQuery('block')
  //    ->execute();
  //
  //  $drupal_blocks = array();
  //  foreach ($block_ids as $block_id) {
  //    $block = Block::load($block_id);
  //    $dependencies = $block->getDependencies();
  //    if (!empty($dependencies['module']) && $module = current($dependencies['module'])) {
  //      if (empty($drupal_blocks[$module])) {
  //        $drupal_blocks[$module] = array();
  //      }
  //      $drupal_blocks[$module][$block_id] = $block;
  //    }
  //  }
  //  return $drupal_blocks;
}

/**
 * Get the icon class for the given path or block title.
 *
 * @param string $type
 *   The type of the icon. Possible values: path or block.
 * @param string $value
 *   The info of the given path or block.
 *
 * @return string
 *   An icon class name.
 */
function mmenu_get_icon_class($type = 'path', $value = '') {
  $language = \Drupal::languageManager()
    ->getCurrentLanguage();
  $icons = mmenu_icon_list();
  $class = '';
  switch ($type) {
    case 'path':
      $value = trim($value, '/');

      // Remove language string.
      $value = ltrim($value, $language
        ->getId());
      if (empty($value)) {
        $value = 'home';
      }
      $class = isset($icons['path'][$value]) ? $icons['path'][$value] : 'icon-list2';
      break;
    case 'block':
      foreach ($icons['block'] as $block) {
        if ($block['module'] == $value['module'] && $block['delta'] == $value['delta']) {
          return $block['icon_class'];
        }
      }
      $class = 'icon-list2';
      break;
  }
  return $class;
}

///**

// * Converts value from PHP to JSON format.
// *
// * @param string $type
// *   The type of the settings such as options or configurations.
// * @param array $values
// *   An associative array that contains the mmenu settings.
// *
// * @return array
// *   A converted mmenu settings array.
// */

//function mmenu_convert_settings($type = 'options', array $values = array()) {

//  foreach ($values as $k => $value) {
//    switch ($k) {
//      case 'offCanvas':
//        if ($type == 'options' && isset($value['enabled']) && $value['enabled'] == 'false') {
//          $value = 'false';
//        }
//        break;
//
//      default:
//        break;
//    }
//
//    if (is_array($value)) {
//      $values[$k] = mmenu_convert_settings($type, $value);
//    }
//    if ($value == 'true') {
//      $values[$k] = TRUE;
//    }
//    elseif ($value == 'false') {
//      $values[$k] = FALSE;
//    }
//    elseif (is_numeric($value)) {
//      $values[$k] = (float) $value;
//    }
//  }
//  return $values;

//}

/**
 * To check if enables the mmenu.
 *
 * First to check the value of enabled variable.
 *
 * Second to check the enabled_callback only if the enabled is set to TRUE.
 *
 * @param array $mmenu
 *   An associative array of the mmenu.
 *
 * @return bool
 *   A boolean to determine to show or hide the mmenu.
 */
function mmenu_display_access(array $mmenu) {
  $flag = FALSE;
  if (isset($mmenu['enabled'])) {

    // The enabled flag will be higher priority then the enabled_callback flag.
    if (!$mmenu['enabled']) {
      return FALSE;
    }
    else {
      if (isset($mmenu['enabled_callback'])) {
        return mmenu_check_enabled_callback($mmenu['enabled_callback']);
      }
      else {
        $flag = TRUE;
      }
    }
  }
  return $flag;
}

/**
 * To check if enables the mmenu by the enabled callback functions.
 *
 * @param array $enabled_callback
 *   An associative array of the enabled callback.
 *
 * @return bool
 *   A boolean to determine to show or hide the mmenu.
 */
function mmenu_check_enabled_callback(array $enabled_callback) {
  $flag = TRUE;
  if (isset($enabled_callback['php']) && count($enabled_callback['php']) > 0) {
    foreach ($enabled_callback['php'] as $callback) {
      if (!(function_exists($callback) && call_user_func($callback))) {
        $flag = FALSE;
        break;
      }
    }
  }
  return $flag;
}

/**
 * Callback function to determine to enable/disable the mmenu.
 *
 * @return bool
 *   A boolean to determine to enable/disable the mmenu.
 */
function mmenu_enabled_callback() {
  return TRUE;
}

/**
 * Helper function for menu_get_menus().
 *
 * @param bool|TRUE $all
 *   Indicate whether to include all menus.
 *
 * @return array
 *   An array list with existing menus on the site.
 */
function mmenu_menu_get_menus($all = TRUE) {
  if ($custom_menus = entity_load_multiple('menu')) {
    if (!$all) {
      $custom_menus = array_diff_key($custom_menus, menu_list_system_menus());
    }
    foreach ($custom_menus as $menu_name => $menu) {
      $custom_menus[$menu_name] = $menu
        ->label();
    }
    asort($custom_menus);
  }
  return $custom_menus;
}

Functions

Namesort descending Description
mmenu_add_libraries Generates the mmenu css list and adds to Drupal.
mmenu_check_enabled_callback To check if enables the mmenu by the enabled callback functions.
mmenu_display_access To check if enables the mmenu.
mmenu_effect_list Gets a list of available mmenu effects.
mmenu_enabled_callback Callback function to determine to enable/disable the mmenu.
mmenu_get_blocks Gets all Drupal blocks for assigning to a mmenu.
mmenu_get_default_configurations Gets default configurations of the mmenu.
mmenu_get_default_options Gets default options of the mmenu.
mmenu_get_icon_class Get the icon class for the given path or block title.
mmenu_icon_list Gets a list of available mmenu icons.
mmenu_libraries_info Implements hook_libraries_info().
mmenu_list Gets a list of available mmenus.
mmenu_menu_get_menus Helper function for menu_get_menus().
mmenu_mmenu Implements hook_mmenu().
mmenu_mmenu_effect Implements hook_mmenu_effect().
mmenu_mmenu_icon Implements hook_mmenu_icon().
mmenu_mmenu_theme Implements hook_mmenu_theme().
mmenu_page_bottom Implements hook_page_bottom().
mmenu_theme Implements hook_theme().
mmenu_theme_list Gets a list of available mmenu themes.
mmenu_theme_suggestions_block_alter Implements hook_theme_suggestions_HOOK_alter().
mmenu_theme_suggestions_mmenu Implements hook_theme_suggestions_HOOK().
template_preprocess_mmenu Processes variables for mmenu.tpl.php.
theme_mmenu_tree Returns HTML for a wrapper for a mmenu tree.