Skip to content
Snippets Groups Projects
Verified Commit 17b0403e authored by Lee Rowlands's avatar Lee Rowlands
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 4761995e
Branches
Tags
8 merge requests!11197Issue #3506427 by eduardo morales alberti: Remove responsive_image.ajax from hook,!11131[10.4.x-only-DO-NOT-MERGE]: Issue ##2842525 Ajax attached to Views exposed filter form does not trigger callbacks,!5423Draft: Resolve #3329907 "Test2",!3478Issue #3337882: Deleted menus are not removed from content type config,!2964Issue #2865710 : Dependencies from only one instance of a widget are used in display modes,!10223132456: Fix issue where views instances are emptied before an ajax request is complete,!617Issue #3043725: Provide a Entity Handler for user cancelation,!579Issue #2230909: Simple decimals fail to pass validation
Pipeline #395207 passed with warnings
Pipeline: drupal

#395229

    Pipeline: drupal

    #395227

      Pipeline: drupal

      #395222

        +4
        ......@@ -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".
        */
        ......@@ -99,6 +99,11 @@ public function theme($existing, $type, $theme, $path) : array {
        ],
        ];
        $items['menu_region__footer'] = ['variables' => ['items' => [], 'title' => NULL, 'menu_name' => NULL]];
        $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\CacheBackendInterface;
        use Drupal\Core\Cache\CacheableMetadata;
        ......@@ -18,6 +19,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\Core\Security\Attribute\TrustedCallback;
        use Drupal\Core\Session\AccountInterface;
        ......@@ -128,6 +130,7 @@ public function doBuildNavigation($build): array {
        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
        ......@@ -157,6 +160,8 @@ public function doBuildNavigation($build): array {
        ];
        $build[0] = NestedArray::mergeDeepArray([$build[0], $defaults]);
        $build[0]['content_top'] = $this->getContentTop();
        if ($logo_provider === self::LOGO_PROVIDER_CUSTOM) {
        $logo_path = $logo_settings->get('logo.path');
        if (!empty($logo_path) && is_file($logo_path)) {
        ......@@ -169,10 +174,36 @@ public function doBuildNavigation($build): array {
        }
        }
        }
        $build[0]['#cache']['contexts'] = ['user.permissions', 'theme', 'languages:language_interface'];
        return $build;
        }
        /**
        * 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 %}
        ......@@ -4,6 +4,7 @@
        namespace Drupal\navigation_test\Hook;
        use Drupal\Core\Cache\CacheableMetadata;
        use Drupal\Core\Hook\Attribute\Hook;
        use Drupal\Core\State\StateInterface;
        ......@@ -34,4 +35,53 @@ public function blockAlter(&$definitions): void {
        }
        }
        /**
        * Implements hook_navigation_content_top().
        */
        #[Hook('navigation_content_top')]
        public function navigationContentTop(): 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().
        */
        #[Hook('navigation_content_top_alter')]
        public function navigationContentTopAlter(&$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