I have created a custom Block that extends BlockBase. I don't want the content to be cached for anonymous users (also not for authenticated users). To be more precise, caching would be fine but depending on some url query argument. In my case the url contains a parameter 'mode' (?mode=1 or ?mode=2 and so on). Depending on the parameter the content of the block varies.

I added the following function:

 public function getCacheContexts() {
    return Cache::mergeContexts(parent::getCacheContexts(), array('url.query_args:mode'));

Still the block content seems to be cached. Is it neccessary to disable the internal page cache module? Actually I don't want to globally disable caching, I just want my block to be cached correctly depending on the url parameter mode.

  • 2
    Possible duplicate of How to removed a block from being cached? – No Sssweat Jan 11 '18 at 9:56
  • The internal page cache doesn't use cache contexts, but it uses the full url including query string for the cache key, so this should work. – 4k4 Jan 11 '18 at 10:00
  • Maybe it is important to say that I'm not using the block directly but using display suite I have added it as a block field. This block field is now included in one of my content types. The url I'm calling is /node/1?mode=1 The block is definetly cached. When I change it to mode=2 it still shows the wrong result. The block is reading the request and then generating some output depending on the value $request = \Drupal::request(); $mode = $request->query->get('mode'); ... – Thomas0878 Jan 11 '18 at 12:08
  • Looks like DS is being treated as an Entity field and therefore the caching is the same as the entity. You may need to modify the entity's cache settings to include the url.query_args:mode context. See: drupal.stackexchange.com/a/192136 – CG Monroe Jan 11 '18 at 17:21

The problem is, you don't render the block in a normal way and Display Suite is obviously not able to retrieve the plugin cache metadata.

Most times it is a better option to include the cache metadata in the render array together with the data it depends on:

public function build() {
  $build = [];
  $request = \Drupal::request();
  $mode = $request->query->get('mode');
  $build['mode'] = [
    '#markup' => t('The query argument is mode=@mode.', ['@mode' => $mode]),
  $build['#cache']['contexts'][] = 'url.query_args:mode';
  return $build;

Then the cache metadata can bubble up, no matter where and how this block content is embedded.

  • Works for me, thanks! What still confuses me is the relation to the internal page cache. When do I have to disable this module? – Thomas0878 Jan 12 '18 at 10:51
  • You don't have to because the internal page cache uses the full url including the query arguments by default. The context you set here is only for the dynamic render cache of the block/node/page or where you embed the content. – 4k4 Jan 12 '18 at 10:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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