Commit c59127f7 authored by catch's avatar catch
Browse files

Issue #3443833 by plopesc, m4olivei, gábor hojtsy, matthieuscarset,...

Issue #3443833 by plopesc, m4olivei, gábor hojtsy, matthieuscarset, penyaskito, larowlan, tim.plunkett: Provide a way for other modules to flag block plugin implementations as 'navigation safe'

(cherry picked from commit 4c9cd84e)
parent cc885723
Loading
Loading
Loading
Loading
Loading
+20 −6
Original line number Diff line number Diff line
@@ -131,12 +131,10 @@ public function blockBuildLocalTasksBlockAlter(array &$build, BlockPluginInterfa
  #[Hook('plugin_filter_block__layout_builder_alter')]
  public function pluginFilterBlockLayoutBuilderAlter(array &$definitions, array $extra): void {
    if (($extra['section_storage'] ?? NULL) instanceof NavigationSectionStorage) {
      // Remove all blocks other than the ones we support.
      $navigation_safe = ['navigation_user', 'navigation_shortcuts', 'navigation_menu'];
      $definitions = array_filter($definitions, static function (array $definition, string $plugin_id) use ($navigation_safe) : bool {
          [$base_plugin_id] = explode(PluginBase::DERIVATIVE_SEPARATOR, $plugin_id);
          return in_array($base_plugin_id, $navigation_safe, TRUE);
      }, ARRAY_FILTER_USE_BOTH);
      // Include only blocks explicitly indicated as Navigation allowed.
      $definitions = array_filter($definitions,
        fn (array $definition): bool => ($definition['allow_in_navigation'] ?? FALSE) === TRUE
      );
    }
  }

@@ -156,12 +154,28 @@ public function pluginFilterLayoutLayoutBuilderAlter(array &$definitions, array
   */
  #[Hook('block_alter')]
  public function blockAlter(&$definitions) : void {
    // Hide Navigation specific blocks from the generic UI.
    $hidden = ['navigation_user', 'navigation_shortcuts', 'navigation_menu', 'navigation_link'];
    foreach ($hidden as $block_id) {
      if (isset($definitions[$block_id])) {
        $definitions[$block_id]['_block_ui_hidden'] = TRUE;
      }
    }

    // Add the allow_in_navigation attribute to those blocks valid for Navigation.
    // @todo Refactor to use actual block Attribute once
    //   https://www.drupal.org/project/drupal/issues/3443882 is merged.
    array_walk($definitions, function (&$definition, $block_id) {
      $allow_in_navigation = [
        'navigation_user',
        'navigation_shortcuts',
        'navigation_menu',
      ];
      [$base_plugin_id] = explode(PluginBase::DERIVATIVE_SEPARATOR, $block_id);
      if (in_array($base_plugin_id, $allow_in_navigation, TRUE)) {
        $definition['allow_in_navigation'] = TRUE;
      }
    });
  }

  /**
+37 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\navigation_test\Hook;

use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\State\StateInterface;

/**
 * Hooks implementations for navigation_test module.
 */
class NavigationTestHooks {

  /**
   * NavigationTestHooks constructor.
   *
   * @param \Drupal\Core\State\StateInterface $state
   *   The state service.
   */
  public function __construct(
    protected StateInterface $state,
  ) {
  }

  /**
   * Implements hook_block_alter().
   */
  #[Hook('block_alter')]
  public function blockAlter(&$definitions): void {
    if ($this->state->get('navigation_safe_alter')) {
      $definitions['navigation_link']['allow_in_navigation'] = TRUE;
      $definitions['navigation_shortcuts']['allow_in_navigation'] = FALSE;
    }
  }

}
+76 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Tests\navigation\Functional;

use Drupal\Tests\BrowserTestBase;

/**
 * Tests the definition of navigation safe blocks.
 *
 * @group navigation
 */
class NavigationSafeBlockDefinitionTest extends BrowserTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = ['navigation', 'navigation_test'];

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * User with permission to administer navigation blocks and access navigation.
   *
   * @var \Drupal\user\UserInterface
   */
  protected $adminUser;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    // Create an admin user, log in and enable test navigation blocks.
    $this->adminUser = $this->drupalCreateUser([
      'configure navigation layout',
      'access navigation',
    ]);

    $this->drupalLogin($this->adminUser);
  }

  /**
   * Tests logic to include blocks in Navigation Layout UI.
   */
  public function testNavigationSafeBlockDefinition(): void {
    // Confirm that default blocks are available.
    $layout_url = '/admin/config/user-interface/navigation-block';
    $this->drupalGet($layout_url);
    $this->clickLink('Add block');

    $this->assertSession()->linkExists('Administration');
    $this->assertSession()->linkExists('Content');
    $this->assertSession()->linkExists('Footer');
    $this->assertSession()->linkExists('Navigation Shortcuts');
    $this->assertSession()->linkExists('User');
    $this->assertSession()->linkNotExists('Link');

    // Apply changes, clear cache and confirm that changes are applied.
    \Drupal::state()->set('navigation_safe_alter', TRUE);
    \Drupal::cache('discovery')->delete('block_plugins');

    $this->drupalGet($this->getUrl());
    $this->assertSession()->linkExists('Administration');
    $this->assertSession()->linkExists('Content');
    $this->assertSession()->linkExists('Footer');
    $this->assertSession()->linkExists('Link');
    $this->assertSession()->linkNotExists('Navigation Shortcuts');
  }

}