Make menu pager block cacheable

Created on 28 May 2025, 2 months ago

Problem/Motivation

Block is not cacheable as of this resolved issue. If `max-age` is bubbled up to the page (e.g. using cache_control_override module), all pages displaying this block are also uncacheable by Drupal's Internal Page Cache module or reverse proxies (e.g. Varnish).

Steps to reproduce

  1. Install and enable this module
  2. Place the block to a page/url
  3. Inspect the Cache-Control headers of the page; it's probably cacheable based on what is configured at admin/config/development/performance
  4. Install and enable cache_control_override module which bubbles up the max-age
  5. Clear the cache and re-inspect the Cache-Control headers; page is not cacheable

Proposed resolution

Make the block cacheable, and set the appropriate cache tags and contexts:

First, we need to remove the current getCacheMax that returns 0 and makes the block not cacheable.

    /**
    * {@inheritdoc}
    *
    * @todo Make cacheable in https://www.drupal.org/node/2483181
    */
    public function getCacheMaxAge() {
        return 0;
    }

Then we need to make sure that when menu changes take place, the cache of the block is invalidated as well. This is easily achievable by:

/**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    // Implementation copy from SystemMenuBlock::getCacheTags.
    // Code will need update if https://www.drupal.org/project/drupal/issues/2488918
    // is implemented.
    $cache_tags = parent::getCacheTags();
    $cache_tags[] = 'config:system.menu.' . $this->getDerivativeId();
    return $cache_tags;
  }

Finally, we need to take into account changes in entities related to the menu links; e.g. if the node related to the previous menu link generated gets unpublished, the block cache should be invalidated as well, and a new previous link (if any) is rendered instead. This is trickier:

Mentioned issue addressed the same problem by using the cache tag node_list. This will do the job, but creates performance issues; a random node edit will invalidate all caches for pages using this block. Core addresses this problem by calculating the cacheable meta for each menu link separately and then and bubbling it up: see MenuLinkTree::build. This is the correct approach.

So, the solution is to either replicate the core code to this module's code (in menuPagerFlattenTree and menuPagerGetNavigation) or alter the current implementation as follows:

  1. Invoke DefaultMenuLinkTreeManipulators::flatten instead of custom flattening implementation
  2. Invoke MenuLinkTree::build to prepare the tree along with its cacheability metadata
  3. Perform all necessary alterations based on the generated $build and $build['#items']: remove the ignored paths, apply the parent restriction (if any), cherry pick the previous/next links, change the link labels, etc.

Remaining tasks

All the above.

User interface changes

None.

API changes

None.

Data model changes

None.

Feature request
Status

Active

Version

3.0

Component

Code

Created by

🇬🇷Greece akz

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024