Skip to content
Snippets Groups Projects
Verified Commit d93c93cc authored by Théodore Biadala's avatar Théodore Biadala
Browse files

Issue #3463142 by plopesc, m4olivei, larowlan, penyaskito: Allow modules to...

Issue #3463142 by plopesc, m4olivei, larowlan, penyaskito: Allow modules to hook into top of content section of new core navigation
parent 1f81a9dd
Branches
Tags
No related merge requests found
Pipeline #403526 passed with warnings
Pipeline: drupal

#403541

    Pipeline: drupal

    #403532

      Pipeline: drupal

      #403529

        +1
        ......@@ -70,6 +70,7 @@
        } only %}
        </div>
        {{ content.content_top }}
        {{ content.content }}
        </nav>
        ......
        <?php
        /**
        * @file
        * Hooks related to the Navigation module.
        */
        /**
        * @addtogroup hooks
        * @{
        */
        /**
        * Provide content for Navigation content_top section.
        *
        * @return array
        * An associative array of renderable elements.
        *
        * @see hook_navigation_content_top_alter()
        */
        function hook_navigation_content_top(): array {
        return [
        'navigation_foo' => [
        '#markup' => \Drupal::config('system.site')->get('name'),
        '#cache' => [
        'tags' => ['config:system.site'],
        ],
        ],
        'navigation_bar' => [
        '#markup' => 'bar',
        ],
        'navigation_baz' => [
        '#markup' => 'baz',
        ],
        ];
        }
        /**
        * Alter replacement values for placeholder tokens.
        *
        * @param $content_top
        * An associative array of content returned by hook_navigation_content_top().
        *
        * @see hook_navigation_content_top()
        */
        function hook_navigation_content_top_alter(array &$content_top): void {
        // Remove a specific element.
        unset($content_top['navigation_foo']);
        // Modify an element.
        $content_top['navigation_bar']['#markup'] = 'new bar';
        // Change weight.
        $content_top['navigation_baz']['#weight'] = '-100';
        }
        /**
        * @} End of "addtogroup hooks".
        */
        ......@@ -138,6 +138,12 @@ function navigation_theme($existing, $type, $theme, $path) {
        ],
        ];
        $items['navigation_content_top'] = [
        'variables' => [
        'items' => [],
        ],
        ];
        return $items;
        }
        ......
        ......@@ -3,6 +3,7 @@
        namespace Drupal\navigation;
        use Drupal\Component\Utility\NestedArray;
        use Drupal\Component\Utility\SortArray;
        use Drupal\Core\Block\BlockPluginInterface;
        use Drupal\Core\Cache\CacheableMetadata;
        use Drupal\Core\Config\ConfigFactoryInterface;
        ......@@ -17,6 +18,7 @@
        use Drupal\Core\Menu\LocalTaskManagerInterface;
        use Drupal\Core\Plugin\Context\Context;
        use Drupal\Core\Plugin\Context\ContextDefinition;
        use Drupal\Core\Render\Element;
        use Drupal\Core\Routing\RouteMatchInterface;
        use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
        use Symfony\Component\HttpFoundation\RequestStack;
        ......@@ -111,6 +113,7 @@ public function buildNavigation(array &$page_top): void {
        if ($storage) {
        foreach ($storage->getSections() as $delta => $section) {
        $build[$delta] = $section->toRenderArray([]);
        $build[$delta]['#cache']['contexts'] = ['user.permissions', 'theme', 'languages:language_interface'];
        }
        }
        // The render array is built based on decisions made by SectionStorage
        ......@@ -139,6 +142,8 @@ public function buildNavigation(array &$page_top): void {
        ],
        ];
        $build[0] = NestedArray::mergeDeepArray([$build[0], $defaults]);
        $build[0]['content_top'] = $this->getContentTop();
        $page_top['navigation'] = $build;
        if ($logo_provider === self::LOGO_PROVIDER_CUSTOM) {
        ......@@ -155,6 +160,33 @@ public function buildNavigation(array &$page_top): void {
        }
        }
        /**
        * Gets the content for content_top section.
        *
        * @return array
        * The content_top section content.
        */
        protected function getContentTop(): array {
        $content_top = [
        '#theme' => 'navigation_content_top',
        ];
        $content_top_items = $this->moduleHandler->invokeAll('navigation_content_top');
        $this->moduleHandler->alter('navigation_content_top', $content_top_items);
        uasort($content_top_items, [SortArray::class, 'sortByWeightElement']);
        // Filter out empty items, taking care to merge any cacheability metadata.
        $cacheability = new CacheableMetadata();
        $content_top_items = array_filter($content_top_items, function ($item) use (&$cacheability) {
        if (Element::isEmpty($item)) {
        $cacheability = $cacheability->merge(CacheableMetadata::createFromRenderArray($item));
        return FALSE;
        }
        return TRUE;
        });
        $cacheability->applyTo($content_top);
        $content_top['#items'] = $content_top_items;
        return $content_top;
        }
        /**
        * Build the top bar for content entity pages.
        *
        ......
        {#
        /**
        * @file
        * Default theme implementation to display the navigation content_top section.
        *
        * Available variables:
        * - items: An associative array of renderable elements to display in the
        * content_top section.
        *
        * @ingroup themeable
        */
        #}
        {% if items is not empty %}
        <div class="admin-toolbar__content-top">
        {{ items }}
        </div>
        {% endif %}
        ......@@ -8,6 +8,7 @@
        declare(strict_types=1);
        use Drupal\Component\Utility\Html;
        use Drupal\Core\Cache\CacheableMetadata;
        /**
        * Implements hook_preprocess_HOOK().
        ......@@ -17,3 +18,50 @@ function navigation_test_preprocess_block__navigation(&$variables) {
        // in tests.
        $variables['attributes']['class'][] = Html::cleanCssIdentifier('block-' . $variables['elements']['#plugin_id']);
        }
        /**
        * Implements hook_navigation_content_top().
        */
        function navigation_test_navigation_content_top(): array {
        if (\Drupal::keyValue('navigation_test')->get('content_top')) {
        $items = [
        'navigation_foo' => [
        '#markup' => 'foo',
        ],
        'navigation_bar' => [
        '#markup' => 'bar',
        ],
        'navigation_baz' => [
        '#markup' => 'baz',
        ],
        ];
        }
        else {
        $items = [
        'navigation_foo' => [],
        'navigation_bar' => [],
        'navigation_baz' => [],
        ];
        }
        // Add cache tags to our items to express a made up dependency to test
        // cacheability. Note that as we're always returning the same items,
        // sometimes only with cacheability metadata. By doing this we're testing
        // conditional rendering of content_top items.
        foreach ($items as &$element) {
        CacheableMetadata::createFromRenderArray($element)
        ->addCacheTags(['navigation_test'])
        ->applyTo($element);
        }
        return $items;
        }
        /**
        * Implements hook_navigation_content_top_alter().
        */
        function navigation_test_navigation_content_top_alter(array &$content_top): void {
        if (\Drupal::keyValue('navigation_test')->get('content_top_alter')) {
        unset($content_top['navigation_foo']);
        $content_top['navigation_bar']['#markup'] = 'new bar';
        $content_top['navigation_baz']['#weight'] = '-100';
        }
        }
        <?php
        declare(strict_types=1);
        namespace Drupal\Tests\navigation\Functional;
        use Drupal\Core\Cache\Cache;
        use Drupal\Core\Url;
        use Drupal\Tests\BrowserTestBase;
        // cspell:ignore foobarbaz baznew
        /**
        * Tests for navigation content_top section.
        *
        * @group navigation
        */
        class NavigationContentTopTest extends BrowserTestBase {
        /**
        * {@inheritdoc}
        */
        protected static $modules = ['navigation', 'navigation_test', 'test_page_test'];
        /**
        * {@inheritdoc}
        */
        protected $defaultTheme = 'stark';
        /**
        * {@inheritdoc}
        */
        protected function setUp(): void {
        parent::setUp();
        $this->drupalLogin($this->createUser([
        'access navigation',
        ]));
        }
        /**
        * Tests behavior of content_top section hooks.
        */
        public function testNavigationContentTop(): void {
        $test_page_url = Url::fromRoute('test_page_test.test_page');
        $this->drupalGet($test_page_url);
        $this->assertSession()->elementNotExists('css', '.admin-toolbar__content-top');
        \Drupal::keyValue('navigation_test')->set('content_top', 1);
        Cache::invalidateTags(['navigation_test']);
        $this->drupalGet($test_page_url);
        $this->assertSession()->elementTextContains('css', '.admin-toolbar__content-top', 'foobarbaz');
        \Drupal::keyValue('navigation_test')->set('content_top_alter', 1);
        Cache::invalidateTags(['navigation_test']);
        $this->drupalGet($test_page_url);
        $this->assertSession()->elementTextContains('css', '.admin-toolbar__content-top', 'baznew bar');
        }
        }
        0% Loading or .
        You are about to add 0 people to the discussion. Proceed with caution.
        Please register or to comment