Score:0

How to cache View block by content language?

us flag

I have a very simple (block) view to list a node's title. This view has an id from url contextual filter and a single filter to filter on Content language set for the page (by URL prefix). This block is then placed using Layout Builder on the Full Content view mode for this node type. The view is set to use Tag based caching. When I switch the page back and forth between languages; the title language does not change.

Disabling views caching fixes this.

A little digging and I see that Views cache context is based on Interface language but the Title is content; so it needs to be based on Content language. I have seen a few posts on setting cache context and cache tags but those don't seem to work.

So far I have tried this:

function mycustom_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
  $language_manager = \Drupal::languageManager();
  $langcode = $language_manager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
  if (isset($view->element['#cache']['contexts']) && is_array($view->element['#cache']['contexts'])) {
    foreach ($view->element['#cache']['contexts'] as $key => $context) {
      if (stristr($context, 'language_interface')) {
        unset($view->element['#cache']['contexts'][$key]);
      }
    }
    $view->element['#cache']['contexts'][] = 'languages:language_content';
    $view->element['#cache']['tags'][] = 'language:' . $langcode;
  }
}

None of this seems to help.

Is it possible I have fixed the view caching but the block is still not cached properly?

Score:1
cn flag

For Views rendering fields you can add the cache metadata to the field, so that it can be used already for the cached rows and then bubble up to the rendered view and block.

/**
 * Implements hook_preprocess_views_view_field().
 */
function mymodule_preprocess_views_view_field(array &$variables) {
  // target specific view and field
  $variables['#cache']['contexts'][] = languages:language_content';
}
Score:0
de flag

You can add a backend class for the block, then add a cache context on language to that block.

First, you need to get the config key for the view block. I believe it is views.view.[BLOCK_ID]. You can get the block ID in the advanced section of the view.

Next, you add a custom class to the block. Here is how that is done for the system branding block.

/**
 * Implements hook_block_alter().
 *
 * Changes the class for the system branding block to add a cache
 * context for language.
 */
function [MODULE]_block_alter(array &$definitions) {
  // Set custom callback for system menu block
  $definitions['system_branding_block']['class'] = 'Drupal\[MODULE]\Plugin\Block\SystemBrandingBlockOverride';
}

Then you can add a cache context on language to in the class:

namespace Drupal\[MODULE]\Plugin\Block;

use Drupal\system\Plugin\Block\SystemBrandingBlock;

/**
 * Adds group caching to the system branding block.
 */
class SystemBrandingBlockOverride extends SystemBrandingBlock {

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    $contexts = parent::getCacheContexts();

    $contexts[] = 'languages';

    return $contexts;
  }

}

Note that you may want to use one one of the following cache contexts instead:

  • languages:language_interface
  • languages:language_content
liquidcms avatar
us flag
Wouldnt be surprised if this also works; but 4k4's answer was 1 line - so picked that one.
Jaypan avatar
de flag
If his works, then all the better!
4uk4 avatar
cn flag
The system branding block is the only core block I know which doesn't render the block content. You don't need this workaround for other blocks. In the contrary, it often doesn't work for rendered content. In general it's the best approach to add the cache metadata to the most granular piece of content it belongs to and let it bubble up.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.