Commit 9eaf4e4f by Manzar Hussain

menu block

parent fd0c7209
ABOUT MENU BLOCK
----------------
Like Drupal core, the Menu Block module allows you to create blocks of menu
items. However, Menu Block's blocks are much more configurable than Drupal
core's.
ADDING MENU BLOCKS
------------------
To add new menu blocks:
1. Install module.
2. Go to /admin/structure/block.
3. Click the "Place block" button in the desired region.
4. Choose a block from the "Menus" category.
5. In the form that appears, configure the options desired and then click the
"Save block" button.
CONFIGURING MENU BLOCKS
-----------------------
When adding or configuring a menu block, several configuration options are
available:
Basic Options:
Title
The default block title will be the menu name.
Display title
Checkbox to have the block title visible or not. If unchecked, the block
title will remain accessible, but hidden visually.
Menu levels:
Initial menu level
The menu will only be visible if the menu item for the current page is at or
below the selected starting level. Select level 1 to always keep this menu
visible.
Maximum number of menu levels to display
The maximum number of menu levels to show, starting from the initial menu
level. For example: with an initial level 2 and a maximum number of 3, menu
levels 2, 3 and 4 can be displayed.
Advanced options:
Expand all menu links
All menu links that have children will "Show as expanded".
Fixed parent item
Alter the options in “Menu levels” to be relative to the fixed parent item.
The block will only contain children of the selected menu link.
HTML and style options:
Theme hook suggestion
A theme hook suggestion can be used to override the default HTML and CSS
classes for menus found in menu.html.twig.
block.settings.menu_block:*:
type: block_settings
label: 'Menu block'
mapping:
follow:
type: boolean
label: 'The initial visibility level follows the active menu item'
follow_parent:
type: string
label: 'Set initial visibility level to the active menu item, or its children'
level:
type: integer
label: 'Starting level'
depth:
type: integer
label: 'Maximum number of levels'
expand:
type: boolean
label: 'Expand all menu links'
parent:
type: string
label: 'Parent menu link'
suggestion:
type: string
label: 'Theme suggestion'
name: Menu Block
description: Provides configurable blocks of menu links.
core: 8.x
core_version_requirement: ^8 || ^9
type: module
dependencies:
- drupal:menu_ui
# Information added by Drupal.org packaging script on 2020-04-24
version: '8.x-1.6'
project: 'menu_block'
datestamp: 1587721602
<?php
/**
* @file
* Install, update and uninstall functions for the Menu Block module.
*/
/**
* Issue #2932048: Config schema mismatch for expand(ed).
*/
function menu_block_update_8101() {
$config_factory = \Drupal::configFactory();
$config_factory->rename('expanded', 'expand');
}
<?php
/**
* @file
* Provides configurable blocks of menu links.
*/
/**
* Implements hook_theme_suggestions_HOOK() for "block".
*/
function menu_block_theme_suggestions_block(array $variables) {
$suggestions = [];
// Check if this is a menu_block block.
if (isset($variables['elements']['#base_plugin_id']) && $variables['elements']['#base_plugin_id'] == 'menu_block') {
$menu_name = strtr($variables['elements']['#derivative_plugin_id'], '-', '_');
$config = isset($variables['elements']['#configuration']) ? $variables['elements']['#configuration'] : [];
// Context module (and perhaps others?) adds 'region' into the config.
if (!empty($config['region'])) {
$suggestions[] = 'block__menu_block__region_' . $config['region'];
$suggestions[] = 'block__menu_block__' . $menu_name . '__region_' . $config['region'];
}
// Add our custom theme suggestion.
if (!empty($config['suggestion']) && $config['suggestion'] !== $menu_name) {
$suggestions[] = 'block__menu_block__' . $config['suggestion'];
}
// Context module adds block 'uuid' into the config.
if (!empty($config['uuid'])) {
$suggestions[] = 'block__menu_block__' . strtr($config['uuid'], '-', '_');
}
}
return $suggestions;
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*
* Adds block__system_menu_block so menu blocks work the same as core's menu
* blocks.
*/
function menu_block_theme_suggestions_block_alter(array &$suggestions, array $variables) {
if ($suggestions[0] == 'block__menu_block') {
if ($suggestions[1] == 'block__menu_block') {
// Since this first suggestion is a dupe, replace it with the system
// suggestion.
$suggestions[0] = 'block__system_menu_block';
}
// If some other module has removed the duplicates, use array_unshift().
else {
array_unshift($suggestions, 'block__system_menu_block');
}
// The suggestions added with menu_block_theme_suggestions_block() are added
// after the machine name-based suggestion, but are less specific and should
// come before it.
if (!empty($variables['elements']['#id'])) {
$machine_name_suggestion = 'block__' . $variables['elements']['#id'];
$suggestions = array_diff($suggestions, [$machine_name_suggestion]);
$suggestions[] = $machine_name_suggestion;
}
}
}
/**
* Implements hook_theme_registry_alter().
*/
function menu_block_theme_registry_alter(&$theme_registry) {
// Add $menu_block_configuration as a variable to the 'menu' theme hook. Set
// its default value to be an empty array.
$theme_registry['menu']['variables']['menu_block_configuration'] = [];
}
/**
* Implements hook_theme_suggestions_HOOK() for "menu".
*/
function menu_block_theme_suggestions_menu(array $variables) {
$suggestions = [];
// The MenuBlock plugin's build() method populates this variable.
if (!empty($variables['menu_block_configuration'])) {
$config = $variables['menu_block_configuration'];
$menu_name = strtr($variables['menu_name'], '-', '_');
$suggestions[] = 'menu__' . $menu_name;
// Context module (and perhaps others?) adds 'region' into the config.
if (!empty($config['region'])) {
$suggestions[] = 'menu__region_' . $config['region'];
$suggestions[] = 'menu__' . $menu_name . '__region_' . $config['region'];
}
// Add our custom theme suggestion.
if (!empty($config['suggestion']) && $config['suggestion'] !== $menu_name) {
$suggestions[] = 'menu__' . $config['suggestion'];
}
// Context module adds block 'uuid' into the config.
if (!empty($config['uuid'])) {
$suggestions[] = 'menu__' . $menu_name . '__' . $config['uuid'];
}
}
return $suggestions;
}
<?php
/**
* @file
* Post update functions for Menu block.
*/
use Drupal\block\BlockInterface;
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
/**
* Implement config schema for the menu_block settings follow.
*/
function menu_block_post_update_implement_schema_for_follow_and_follow_parent(&$sandbox = NULL) {
if (!\Drupal::moduleHandler()->moduleExists('block')) {
return;
}
\Drupal::classResolver(ConfigEntityUpdater::class)
->update($sandbox, 'block', function (BlockInterface $block) {
if (strpos($block->getPluginId(), 'menu_block:') === 0) {
$block_settings = $block->get('settings');
$block_settings['follow'] = (bool) $block_settings['follow'];
$block->set('settings', $block_settings);
return TRUE;
}
return FALSE;
});
}
services:
menu_block.kernel_view_subscriber:
class: Drupal\menu_block\EventSubscriber\MenuBlockKernelViewSubscriber
arguments: ['@current_route_match']
tags:
- { name: event_subscriber }
<?php
namespace Drupal\menu_block\EventSubscriber;
use Drupal\Core\Routing\RouteMatchInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Alters the block library modal.
*
* We can't use hook_ajax_render_alter() because the #markup is rendered before
* it is passed to that hook.
*/
class MenuBlockKernelViewSubscriber implements EventSubscriberInterface {
/**
* The current route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $currentRouteMatch;
/**
* Constructs a new MenuBlockKernelViewSubscriber.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $current_route_match
* The current route match.
*/
public function __construct(RouteMatchInterface $current_route_match) {
$this->currentRouteMatch = $current_route_match;
}
/**
* Alters the block library modal.
*
* @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The event to process.
*/
public function onView(GetResponseEvent $event) {
switch ($this->currentRouteMatch->getRouteName()) {
case 'block.admin_library':
case 'context.reaction.blocks.library':
// Grab the render array result before it is rendered by the
// main_content_view_subscriber.
$result = $event->getControllerResult();
foreach ($result['blocks']['#rows'] as $key => $row) {
// Remove rows for any block provided by the system_menu_block plugin.
$routeParameters = $row['operations']['data']['#links']['add']['url']->getRouteParameters();
$plugin_id = !empty($routeParameters['plugin_id']) ? $routeParameters['plugin_id'] : $routeParameters['block_id'];
if (strpos($plugin_id, 'system_menu_block:') === 0) {
unset($result['blocks']['#rows'][$key]);
}
}
// Override the original render array.
$event->setControllerResult($result);
break;
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
// Run before main_content_view_subscriber.
$events[KernelEvents::VIEW][] = ['onView', 1];
return $events;
}
}
<?php
namespace Drupal\menu_block\Plugin\Derivative;
use Drupal\system\Plugin\Derivative\SystemMenuBlock;
/**
* Provides block plugin definitions for custom menus.
*
* @see \Drupal\system\Plugin\Block\SystemMenuBlock
*/
class MenuBlock extends SystemMenuBlock {
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition) {
foreach ($this->menuStorage->loadMultiple() as $menu => $entity) {
$this->derivatives[$menu] = $base_plugin_definition;
$this->derivatives[$menu]['admin_label'] = $entity->label();
$this->derivatives[$menu]['config_dependencies']['config'] = [$entity->getConfigDependencyName()];
}
return $this->derivatives;
}
}
name: 'Menu block test module'
type: module
description: 'Support module for menu_block testing.'
package: Testing
core: 8.x
# Information added by Drupal.org packaging script on 2020-04-24
version: '8.x-1.6'
project: 'menu_block'
datestamp: 1587721602
menu_test.hierarchy.parent:
path: '/menu-block-test/hierarchy/parent'
defaults:
_title: 'parent page'
_controller: '\Drupal\menu_block_test\Controller\MenuBlockTestController::menuBlockTestCallback'
requirements:
_access: 'TRUE'
menu_test.hierarchy.parent.child_1:
path: '/menu-block-test/hierarchy/parent/child-1'
defaults:
_title: 'child-1 page'
_controller: '\Drupal\menu_block_test\Controller\MenuBlockTestController::menuBlockTestCallback'
requirements:
_access: 'TRUE'
menu_test.hierarchy.parent.child_1.child_1_1:
path: '/menu-block-test/hierarchy/parent/child-1/child-1-1'
defaults:
_title: 'child-1-1 page'
_controller: '\Drupal\menu_block_test\Controller\MenuBlockTestController::menuBlockTestCallback'
requirements:
_access: 'TRUE'
menu_test.hierarchy.parent.child_1.child_1_2:
path: '/menu-block-test/hierarchy/parent/child-1/child-1-2'
defaults:
_title: 'child-1-2 page'
_controller: '\Drupal\menu_block_test\Controller\MenuBlockTestController::menuBlockTestCallback'
requirements:
_access: 'TRUE'
menu_test.hierarchy.parent.child_2:
path: '/menu-block-test/hierarchy/parent/child-2'
defaults:
_title: 'child-2 page'
_controller: '\Drupal\menu_block_test\Controller\MenuBlockTestController::menuBlockTestCallback'
requirements:
_access: 'TRUE'
<?php
namespace Drupal\menu_block_test\Controller;
use Drupal\Core\Controller\ControllerBase;
/**
* Controller routines for menu_block_test routes.
*/
class MenuBlockTestController extends ControllerBase {
/**
* Returns placeholder page content which can be used for testing.
*
* @return string
* A string that can be used for comparison.
*/
public function menuBlockTestCallback() {
return ['#markup' => 'This is the menuBlockTestCallback() content.'];
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment