New contextual links are not available after a module is installed

Created on 27 July 2016, over 8 years ago
Updated 23 July 2024, 6 months ago

If a module defines a new contextual likes in a *.links.contextual.yml file they are not available unless 1 of these things happens:

  1. The user's permissions change
  2. The user opens a new browser session
  3. The user logs out and in.

This is because the contextual links are cached on the client-side and the cache is not cleared unless the hash created by the user's permissions hash changes.

I found while working on #2753941: [Experimental] Create Outside In module MVP to provide block configuration in Off-Canvas tray and expand site edit mode which creates a new contextual link.

This could be fixed by a relying on a hash of current modules installed in addition to permissions.

🐛 Bug report
Status

Needs work

Version

11.0 🔥

Component
Contextual 

Last updated 4 months ago

Created by

🇺🇸United States tedbow Ithaca, NY, USA

Live updates comments and jobs are added and updated live.
  • Contributed project blocker

    It denotes an issue that prevents porting of a contributed project to the stable version of Drupal due to missing APIs, regressions, and so on.

  • DrupalWTF

    Worse Than Failure. Approximates the unpleasant remark made by Drupal developers when they first encounter a particular (mis)feature.

  • Needs issue summary update

    Issue summaries save everyone time if they are kept up-to-date. See Update issue summary task instructions.

Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇬🇧United Kingdom catch
    +++ b/core/modules/contextual/contextual.module
    @@ -66,7 +67,11 @@ function contextual_page_attachments(array &$page) {
       }
     
    +  $definitions = \Drupal::service('plugin.manager.menu.contextual_link')->getDefinitions();
    +  ksort($definitions);
    +
       $page['#attached']['library'][] = 'contextual/drupal.contextual-links';
    +  $page['#attached']['drupalSettings']['contextual']['linkDefinitionsHash'] = hash('sha256', Settings::getHashSalt() . implode(':', array_keys($definitions)));
     }
    

    This looks like a good solution, but it needs a comment.

  • Status changed to Needs review almost 2 years ago
  • 🇺🇸United States smustgrave

    Added a comment.

  • Status changed to Needs work almost 2 years ago
  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
    1. +++ b/core/modules/contextual/contextual.module
      @@ -66,7 +67,13 @@ function contextual_page_attachments(array &$page) {
      +  // Pass a hash of the current contextual link definitions to the javascript
      

      nit: JavaScript

    2. +++ b/core/modules/contextual/contextual.module
      @@ -66,7 +67,13 @@ function contextual_page_attachments(array &$page) {
      +  $page['#attached']['drupalSettings']['contextual']['linkDefinitionsHash'] = hash('sha256', Settings::getHashSalt() . implode(':', array_keys($definitions)));
      

      I don't know if we should be using the hash salt for this, its kind of leaking privileged data, we really only want a hash, doesn't need to be secure

    3. +++ b/core/modules/contextual/js/contextual.js
      @@ -21,17 +21,31 @@
           if (typeof permissionsHash === 'string') {
      

      do we need the equivalent type check for the new hash?

  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
    +++ b/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php
    @@ -67,6 +67,29 @@ public function testContextualLinksVisibility() {
    +  protected function assertContextualLinkWithText(string $text) {
    +    $contextLinks = $this->assertSession()->waitForElement('css', ".contextual-links li a");
    +    $this->assertNotEmpty($contextLinks);
    +    foreach ($contextLinks as $contextLink) {
    +      if ($contextLink->getText() === $text) {
    +        break;
    +      }
    

    this doesn't fail if the link is missing, we need $this->fail() outside the loop

  • Status changed to Needs review almost 2 years ago
  • 🇺🇸United States smustgrave

    #59
    1 = fixed
    2 = removed hash salt
    3 = don't think we need it as there is a check before this code

    #60
    1 = actually showed the tests weren't working and false positive. Updated tests.

  • 🇺🇸United States tim.plunkett Philadelphia
    +++ b/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php
    @@ -67,6 +67,14 @@ public function testContextualLinksVisibility() {
    +    drupal_flush_all_caches();
    

    Use $this->resetAll() instead (and maybe a line break after, for readability)

  • Status changed to Needs work almost 2 years ago
  • 🇺🇸United States smustgrave

    So #61 the tests pass with the cache clear.

    Is the original goal to have contextual links appear without a cache clear?

    Not sure if the tests or fix need work but should of got red/green

  • 🇺🇸United States tim.plunkett Philadelphia

    afaik, a cache clear currently doesn't fix the bug in any way, because it's stored in sessionStorage:

    while data in localStorage doesn't expire, data in sessionStorage is cleared when the page session ends

    I'm not sure how best to ensure that a test is happening within the same page session. But that strikes me as the problem here

  • 🇺🇸United States SocialNicheGuru

    Number #54 patch no longer applies to Drupal 9.5.9.

  • 🇬🇧United Kingdom james.williams

    Here's a patch that applies to Drupal 9.5.x; just to assist those of us needing that. It includes the es6.js file and the transpiled version, since both are needed in D9.5 patches as far as I can see.

  • 🇦🇺Australia larowlan 🇦🇺🏝.au GMT+10
    +++ b/core/modules/contextual/tests/src/FunctionalJavascript/ContextualLinksTest.php
    @@ -64,6 +64,14 @@ public function testContextualLinksVisibility() {
    +    drupal_flush_all_caches();
    

    Does the comment in #9 help? It might remove the need for this and get you a failing test?

  • 🇷🇴Romania ion.macaria Bucharest, 🇷🇴

    I know Drupal 9 is close to the end. But for last months maybe it is necessary for someone:
    Drupal 9.5.11 patch.

  • 🇷🇴Romania ion.macaria Bucharest, 🇷🇴

    Update for broken patch:
    Core 9.5.11

  • last update about 1 year ago
    Patch Failed to Apply
  • last update about 1 year ago
    Custom Commands Failed
  • 🇮🇳India _utsavsharma

    Fixed failures in #70.

  • last update about 1 year ago
    30,341 pass
  • 🇷🇴Romania ion.macaria Bucharest, 🇷🇴

    Reroll patch for drupal 10.1.7

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MariaDB 10.3.22
    last update about 1 year ago
    Custom Commands Failed
  • last update about 1 year ago
    Custom Commands Failed
  • 🇮🇳India sourabhjain

    Fixed the #73 testing failed issue. Please review.

  • Status changed to Needs review about 1 year ago
  • Status changed to Needs work about 1 year ago
  • The Needs Review Queue Bot tested this issue.

    While you are making the above changes, we recommend that you convert this patch to a merge request . Merge requests are preferred over patches. Be sure to hide the old patch files as well. (Converting an issue to a merge request without other contributions to the issue will not receive credit.)

  • Status changed to Needs review about 1 year ago
  • Status changed to Needs work about 1 year ago
  • 🇺🇸United States smustgrave

    Was tagged for issue summary which is still needed. Please don't put tickets in review without checking core gates and any open tags.

    Now that we are mixing patches and MRs that will need to be cleaned up and noted in the updated issue summary.

  • 🇺🇸United States steyep

    I could not get the patch in #74 nor the diff from the MR to apply cleanly in 10.3. I've attached a re-rolled the patch for 10.3

Production build 0.71.5 2024