View source
<?php
namespace Drupal\footermap\Plugin\Block;
use Drupal\Core\Access\AccessResultNeutral;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Menu\MenuLinkManagerInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Core\Menu\InaccessibleMenuLink;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class FootermapBlock extends BlockBase implements ContainerFactoryPluginInterface, FootermapInterface {
protected $mapref;
protected $menuTree;
protected $entityManager;
protected $entityRepository;
protected $menuLinkManager;
protected $logger;
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_manager, EntityRepositoryInterface $entityRepository, MenuLinkTreeInterface $menu_tree, MenuLinkManagerInterface $menu_link_manager, LoggerChannelFactoryInterface $logger_factory) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityManager = $entity_manager;
$this->entityRepository = $entityRepository;
$this->menuTree = $menu_tree;
$this->menuLinkManager = $menu_link_manager;
$this->logger = $logger_factory
->get('footermap');
}
public function access(AccountInterface $account, $return_as_object = FALSE) {
if ($return_as_object) {
return AccessResultNeutral::allowed();
}
return TRUE;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('entity_type.manager'), $container
->get('entity.repository'), $container
->get('menu.link_tree'), $container
->get('plugin.manager.menu.link'), $container
->get('logger.factory'));
}
public function defaultConfiguration() {
$settings = parent::defaultConfiguration();
$settings['footermap_recurse_limit'] = 0;
$settings['footermap_display_heading'] = 1;
$settings['footermap_avail_menus'] = [];
$settings['footermap_top_menu'] = '';
return $settings;
}
public function getCacheContexts() {
return [
'languages',
];
}
public function blockForm($form, FormStateInterface $form_state) {
$form['footermap_recurse_limit'] = [
'#type' => 'number',
'#title' => $this
->t('Recurse Limit'),
'#description' => $this
->t('Limit the depth of menu items to display. The default is 0, unlimited. This is useful if you have a deep hierarchy of child menu items that you do not want to display in the footermap.'),
'#size' => 3,
'#max_length' => 3,
'#min' => 0,
'#default_value' => $this->configuration['footermap_recurse_limit'],
];
$form['footermap_display_heading'] = [
'#type' => 'radios',
'#title' => $this
->t('Enable Menu Heading'),
'#description' => $this
->t('This will enable the menu-name label (e.g. Navigation, Footer) to be displayed as the heading above each menu column. This is nice if you have your menus setup in distinct blocks or controlled via the recurse-limit property above.'),
'#options' => [
$this
->t('No'),
$this
->t('Yes'),
],
'#default_value' => $this->configuration['footermap_display_heading'],
];
$form['footermap_top_menu'] = [
'#type' => 'textfield',
'#title' => $this
->t('Top-level Menu'),
'#description' => $this
->t('Set the plugin ID to use for the top-level menu. This may be useful if you want a footer map of menu links deep within a menu instead of pulling from each menu. The default is to use from avail-menus below.'),
'#default_value' => $this->configuration['footermap_top_menu'],
];
$form['footermap_avail_menus'] = [
'#type' => 'checkboxes',
'#title' => $this
->t('Available menus'),
'#description' => $this
->t('Select which top-level menus to include in this footer site map.'),
'#options' => $this
->getMenus(),
'#default_value' => $this->configuration['footermap_avail_menus'],
];
return $form;
}
public function blockSubmit($form, FormStateInterface $form_state) {
$this->configuration = $form_state
->getValues();
}
public function build() {
$build = [
'#theme' => 'footermap',
'#title' => $this->configuration['label_display'] ? $this->configuration['label'] : '',
'#block' => $this,
'#attributes' => [
'class' => [
'footermap',
'footermap--' . $this
->getPluginId(),
],
],
'#attached' => [
'library' => [
'footermap/footermap',
],
],
];
try {
$build['#footermap'] = $this
->buildMap();
} catch (\Exception $e) {
$this->logger
->error($e
->getMessage());
}
return $build;
}
public function buildMap() {
$this->mapref = [];
$col_index = 1;
$depth = $this->configuration['footermap_recurse_limit'] == 0 ? NULL : $this->configuration['footermap_recurse_limit'];
$top_menu_plugin_id = $this->configuration['footermap_top_menu'] == '' ? FALSE : $this->configuration['footermap_top_menu'];
$menus = $this
->getMenus($top_menu_plugin_id);
$parameters = new MenuTreeParameters();
if ($this->configuration['footermap_recurse_limit']) {
$parameters
->setMaxDepth($depth);
}
$parameters
->onlyEnabledLinks();
$parameters
->excludeRoot();
if ($top_menu_plugin_id && !empty($menus)) {
$parameters
->setRoot($top_menu_plugin_id);
}
$manipulators = [
[
'callable' => 'footermap.anonymous_tree_manipulator:checkAccess',
],
];
foreach ($menus as $menu_name => $menu) {
if (isset($this->configuration['footermap_avail_menus'][$menu_name]) && $this->configuration['footermap_avail_menus'][$menu_name] === $menu_name) {
$menu_name_class = str_replace('_', '-', $menu_name);
$tree = $this->menuTree
->load($menu_name, $parameters);
$tree = $this->menuTree
->transform($tree, $manipulators);
if (!empty($tree)) {
$this->mapref[$menu_name] = [
'#theme' => 'footermap_header',
'#title' => $menu,
'#title_display' => $this->configuration['footermap_display_heading'] ? 'visible' : 'hidden',
'#menu_name' => $menu_name,
'#attributes' => [
'class' => [
'footermap-header',
'footermap-header--' . $menu_name_class,
],
],
];
$this
->buildMenu($tree, $this->mapref[$menu_name]);
}
$col_index++;
}
}
return $this->mapref;
}
public function buildMenu(array &$tree, array &$mapref) {
foreach ($tree as $key => $item) {
$link = $item->link;
$link_title = $link
->getTitle();
if ($link
->isEnabled() && !empty($link_title) && !$link instanceof InaccessibleMenuLink) {
if (isset($mapref['#theme']) && $mapref['#theme'] == 'footermap_header') {
$child =& $mapref['#items'];
}
else {
$child =& $mapref;
}
if (strpos($link
->getPluginId(), 'menu_link_content') === 0) {
list(, $uuid) = explode(':', $link
->getPluginId(), 2);
$entity = $this->entityRepository
->loadEntityByUuid('menu_link_content', $uuid);
}
$child['menu-' . $key] = [
'#theme' => 'footermap_item',
'#title' => $link
->getTitle(),
'#url' => $link
->getUrlObject(),
'#attributes' => [
'class' => [
'footermap-item',
'footermap-item--depth-' . $item->depth,
],
],
'#level' => $item->depth,
'#weight' => $link
->getWeight(),
];
}
if ($item->hasChildren) {
$child['menu-' . $key]['#children'] = [];
$child['menu-' . $key]['#attributes']['class'][] = 'footermap-item--haschildren';
$this
->buildMenu($item->subtree, $child['menu-' . $key]['#children']);
}
}
}
protected function getMenus($plugin_id = NULL) {
$options = [];
if (isset($plugin_id) && $plugin_id) {
$item = $this->menuLinkManager
->getDefinition($plugin_id, FALSE);
if (!$item) {
return $options;
}
return [
$item['menu_name'] => $item['title'],
];
}
$controller = $this->entityManager
->getStorage('menu');
if ($menus = $controller
->loadMultiple()) {
foreach ($menus as $menu_name => $menu) {
$options[$menu_name] = $menu
->label();
}
asort($options);
}
return $options;
}
}