7

I have a node type "Article" that contains a repeating Paragraphs field. One of the paragraph types let's the user embed a view using a entity reference field. When rendering an Article node containing a views reference I embed the selected view in hook_preprocess_paragraph like this:

$view_id = $paragraph->field_view->target_id;
$view = \Drupal\views\Views::getView($view_id);
$view->setDisplay('embed_1');
$vars['content'] = $view->preview();

This is working fine except when I enable caching. For example one of my views lists nodes of the type "Event". When I add a new Event it does not show up in the listing until I clean the cache. I could force clean the cache when inserting / updating / deleting an "Event" but I would much rather use Drupal 8's cache tag system and only invalidate the cached content that contains event lists. The problem is I cannot get it to work.

So far I have tried adding cache tags to the node, the view, and the paragraph in hook_preprocess_paragraph and hook_preprocess_node like this:

$vars['paragraph']->addCacheTags(['node_list']);
...
$view->storage->addCacheTags(['node_list']);
...
$vars['node']->addCacheTags(['node_list']);

According to this page node_list can be used for node listings to invalidate the cache whenever a node is updated. But it has no effect. Maybe the preprocess hooks are to late to add cache tags?

What am I missing?

Edit:

After some more testing I found that if I edit an event, the changes can be seen in the listing and if I remove an event it disappears from the listing. The problem only occurs when adding new events.

3 Answers 3

11

Try to use buildRenderable(), that should ensure that the necessary cacheability metadata is added automatically.

$vars['content'] = $view->buildRenderable();

Hint: You might be interested in my Views Custom Cache Tag project. The node_list cache tag is invalidated every time any type of node is saved, even though your view only changes when an event changes. Using that module and a bit of custom code as shown on the project page, you have fewer cache invalidations and better performance.

3
  • How do I render the results of $view-buildRenderable() in my twig file? When using $view->preview() I could just do {{ content }} in my twig template but it does not work.
    – reekris
    Apr 25, 2016 at 7:12
  • 1
    It returns a render array, that should wok fine. Are you using an embed display? If so, I recently found a core bug there, see drupal.org/node/2711973. as a workaround, just set #embed => TRUE yourself in $variables['content'].
    – Berdir
    Apr 25, 2016 at 7:14
  • Yep, I'm using embed displays, and setting #embed => true manually works great! Thanks Berdir! Will definitely check out your module as well.
    – reekris
    Apr 25, 2016 at 7:46
3

Add the cache tag to the render array, not the object:

$vars['#cache']['tags'][] = 'node_list';

In preprocess you are working with render arrays, not objects. Look at this page of the documentation: https://www.drupal.org/developing/api/8/render/arrays/cacheability

2
  • Thanks for clearing that up! For my issue, Berdirs answer fixed my problem without having to add cache tags manually.
    – reekris
    Apr 25, 2016 at 7:47
  • Thanks for the feedback. I agree, that is a great answer from @Berdir. I upvoted it too.
    – 4uk4
    Apr 25, 2016 at 9:06
0

I solved a similar issue using the module Views Custom Cache Tag:

In the view editor, under Advanced, click on Cache, then select "Custom tag based". To have the view rerendered each time a node is changed, enter 'node_list' in the custom tag settings.

Your Answer

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

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