6

I have some custom block types that display in a region in my site. I have noticed that when changing the contents of these blocks, like an image, text, or title, that when you save and visit the page, the block data is cached and doesn't show the new changes. This is problematic because the client keeps reporting this as a bug, but I can't see where or why it won't update.

Is there a way to have it invalidate when saving a block so that a cache clear isn't necessary? I figured this would be normal behavior, but I have to clear it (while logged in as UID 1 even), and I don't think I am doing anything weird or have a contrib module installed that would interfere with this.

Edit: I am not using Panels or anything - this is core block.

6
  • Does this block have/use a custom template file, and if yes, can you post the code in your Q?
    – No Sssweat
    Commented Jan 14, 2017 at 3:16
  • It does, but I don't have it on this computer. Will have to update later. In some parts, it checks if block_content.field_name... exists before rendering the content.field_name. Does that cause it?
    – Kevin
    Commented Jan 14, 2017 at 4:54
  • Maybe, but I doubt it. You could also temporarily rename of the template file, so it does not use it, and see if saving works then. Perhaps this upvoted comment from 4k4 may solve your problem.
    – No Sssweat
    Commented Jan 14, 2017 at 5:27
  • If you not render {{ content }} in a block template you loose the cache data. The main problem here is that unlike other entities block_content has not a template and you are forced to use the parent template block, which is not really the right place to theme the inside of block_content.
    – 4uk4
    Commented Jan 14, 2017 at 9:00
  • Still, invalidation should work just fine, cache tags bubble up. For whom exactly does it not update? authenticated users, anonymous users? If it's anonymous, maybe you simply have an external cache (varnish, ..) that doesn't support tag-based invalidation
    – Berdir
    Commented Jan 14, 2017 at 10:05

2 Answers 2

13

The problem is, that the cache tag block_content:[id] does not bubble up and the tag is missing in the cache entry. Without this cache tag the cache entry can't be invalidated when saving a modified custom block.

Here are two workarounds:

Twig template (Workaround 1)

If you theme a block template and you render single fields

{{ content.field_field1 }}
{{ content.field_field2 }}

then you also need to render the rest of content:

{{ content|without('field_field1', 'field_field2') }}

That's because content contains the cache tag of the block content entity, which otherwise won't bubble up.

Preprocess (Workaround 2)

As an alternative option for rendering {{ content }} you can add the cache tag at the top of variables in preprocess.

mytheme.theme

function mytheme_preprocess_block(&$variables) {
  if ($variables['base_plugin_id'] == 'block_content') {
    $renderer = \Drupal::service('renderer');
    $renderer->addCacheableDependency($variables, $variables['content']['#block_content']);
  }
}

Then you no longer depend on the twig template to render all of content.

You'll find in Drupal\block\BlockViewBuilder::preRender() more workarounds for issues with bubbling up data from the content render array. You could use this code, which there is only applied in special circumstances, for all cache data from block content to bubble up to the top level:

use Drupal\Core\Cache\CacheableMetadata;

function mytheme_preprocess_block(&$variables) {
  $content = $variables['content'];
  CacheableMetadata::createFromRenderArray($variables)
          ->merge(CacheableMetadata::createFromRenderArray($content))
          ->applyTo($variables);
}

But I don't know which side effects that would have in other places. If it would be that easy the block view builder would do this already. So it's better to tackle only that specific problem with the one missing tag and use the first version of the preprocess function.

2
  • Turns out thats what it is. I had to do {{ content.without(args) }}
    – Kevin
    Commented Jan 17, 2017 at 15:17
  • And I can confirm that if you're preprocessing, your code using addCacheableDependency() works perfectly, thanks! Commented Mar 17, 2017 at 15:22
-1

Setting cache max age to 0 saved my day.

function MODULE_NAME_preprocess_block(&$variables) {
    if ($variables['base_plugin_id'] == 'block_content') {
        $variables['#cache']['max-age'] = 0;   
    } 
}
1
  • Wouldn't this prevent all blocks from ever being cached?
    – gcalex5
    Commented Nov 19, 2019 at 12:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.