4

I have a module with a custom block MyCustomBlock.php that get the nid of the current page and pass the value to the block template:

$node = \Drupal::routeMatch()->getParameter('node');
$nid = $node->nid->value;
return array(
  'currentnid' => $nid,
);

Inside the template I print the passed value {{ currentnid }}, but it only works cleaning the cache! For example, if I load the page with nid 5 it prints 5, but if I move to page with nid 3 it prints 5. Cleaning the cache and reloading page with nid 3 I get the value 3 printed. I think it is a problem with the template caching system in D8, do you have any idea about this?

  • 1
    If you have page_cache enabled then nothing will help you for anonymous users. If you have only dynamic_page_cache enabled or the user is logged in you should use the cache context as mentioned below or you can use lazy builder(still only for dynamic_page_cache / no cache). – user21641 Jan 29 '16 at 20:47
4

Blocks are cached. However blocks are also context-aware in Drupal 8. Per the documentation page regarding Cache Contexts:

Cache contexts provide a declarative way to create context-dependent variations of something that needs to be cached. By making it declarative, code that creates caches becomes easier to read, and the same logic doesn't need to be repeated in every place where the same context variations are necessary.

The Cache API documentation page is a good read for everyone.

A Block plugin should implement getCacheContexts. I think that in this case it should either be "route.name" or "url.path". You may need to delve into this a bit more for your particular use case.

  public function getCacheContexts() {
    return array('route.name');
  }
  • 1
    Thanks a lot! I have read the documentation about the cache context and it is quite clear now. In my specific case I have solved using "url.path" as context. It works fine now! @mradcliffe – Gabriele Jan 30 '16 at 9:14
  • See also my response. You can do it like this, but I'd recommend to at least call the parent::getCacheContexts() too and merge those together. – Berdir Jan 30 '16 at 13:58
7

The proper way to do this would be use contexts. Plugin contexts, not cache contexts.

Similar to NodeType condition plugin, put something like this in your plugin annotation:

* context_definitions = {
*  "node" = @ContextDefinition("entity:node", label = @Translation("Node"))
* }

And then get the node using $this->getContextValue('node').

This has two advantages:

  • Your block doesn't rely on global state directly. It could for example be used also in page manager, with a different node.
  • Drupal automatically understands that your block varies by whatever node is passed in. If using the current node, it will vary by route, if it would e.g. be a node from a static page manager context, it wouldn't. It will also include cache tags, in case the node is changed in a way that would affect your output.
  • Thank you, I will try implementing this solution as well and if I will be able to get it works I'll keep it. – Gabriele Jan 30 '16 at 14:07
  • Oh, this is really nice to know! +1 – mradcliffe Jan 30 '16 at 17:06
  • I tried this method but it stops working overall, the block doesn't seem to execute, I can't even print a string out. Log messages don't say anything and no PHP errors. The marked answer worked for me though. – Chayemor Nov 30 '16 at 19:03

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.