15

I try to embed a view in a specific node. I found tutorials for doing this with Drupal 7 and PHP-Templates:

<?php print views_embed_view('view_name'); ?>

But I look for a way in Drupal 8 with twig-Templates. I tried to call the views_embed_view() function in the hook_node_view() and assign it to the node so that I can print it out in the twig-Template. But it seems that this hook never gets called.

Any hints/solutions how to do this in the Drupal 8 way?

6 Answers 6

22

Twig Views Embed

This module allows to embed views with a twig function.

{{ views_embed_view('view_name', 'view_id') }}

The above module was depreciated in favour of

Twig Tweak

Twig Tweak module provides a Twig extension with some useful functions and filters that can improve developer experience.

Ex: {{ drupal_view('view_name', 'view_machine_name') }}

You can find the view_machine_name over here

8
  • @TiMESPLiNTER just giving you a heads up.
    – No Sssweat
    Commented Apr 9, 2016 at 5:37
  • Since when? Version? Commented Aug 31, 2017 at 17:23
  • 1
    @VishalKumarSahu since my answer was posted, Mar 18 '16. I think the module still works, it's just that it's no longer being maintained or being developed any further.
    – No Sssweat
    Commented Aug 31, 2017 at 17:36
  • Perfectly perfect. It works great and I am having good experience with it. Thanks Commented Aug 31, 2017 at 17:39
  • Twig Tweak ! Good Module
    – Harish ST
    Commented Jul 31, 2018 at 11:50
8

This is the way it worked for me in Drupal 8 beta 12 sub-theme of Classy.

In the your_theme.info.theme file

function stjameskidsclub_preprocess_node(&$variables){
  $stuff  = views_embed_view('policy_documents', 'embed_1', 28);
  $variables["my_view"] = \Drupal::service('renderer')->renderRoot($stuff);
}  

I copied the node.html.twig and surrounded the article tags (or the area you wish to replace) with a twig block. I placed this in the /template/content folder.

{% block replace_area %}
  <article{{ attributes.addClass(classes) }}>

    ...

  </article>  
{% endblock replace_area %}

Then I created a node--2.html.twig (replace 2 with desired node) in the /template/content folder with the following code.

{% extends "node.html.twig" %}

{% block replace_page %}
  {{ my_view }}
{% endblock %}
1
  • Worth to say this will work inside your module as well
    – Augusto
    Commented Apr 27, 2021 at 8:11
4

The first problem you're fighting with is that rendered entities like nodes are now cached by default, so hook_node_view() is only called once after a cache clear/saving that node.

However, this is fairly easy to disable, see settings.local.php.

Then, putting the output of a view in $build is fairly easy and more or less works like in 7.x. Instead of using the embed function, consider using $views = Views::getView() and then $views->buildRenderable()

Two tips:

  • Make the key you use for $build available as an extra field in hook_entity_extra_field_info(), then check the display if the component is enabled (see how user_user_view() does that. That allows you to configure the weight/placement of the view in the UI and also hide it on certain view modes.
  • If your view has a page, then it is a bit more complicated, as the node output is cached. You need to make the cache key aware of the pager then, see comment_entity_build_defaults_alter() for an example (not a view, but that is the closest example that core has).
2
  • First of all thx for this great answer. Well I "enabled" the settings.local.php and cleared all caches. But my hook themename_node_view() in themename.theme still gets not called. Have you any idea why this could be the case? Commented Dec 19, 2014 at 12:48
  • 1
    There is a snippet in settings.php that you need to uncomment (at the end). to make sure that settings.local.php is loaded, add invalid PHP that results in a fatal error. if your site doesn't fail, the file doesn't get loaded.
    – Berdir
    Commented Dec 19, 2014 at 20:11
2

As Berdir alluded to View->buildRenderable is what you're looking for, but to give some more context in a module you'll need to do the following.

//use core libraries
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;

//use views class
use \Drupal\views\Views;

function hook_node_view(&$build, $node, $display, $view_mode){

 $thisView = Views::getView('view_name');

 $build['arbitrary_render_array_key_here'] = $thisView->buildRenderable('block_1',array($your_arguments));

}

Then in your page template you can access it with

{{ page.content.theme_name_content }}
1
  • 1
    All of this was a single liner in Drupal 7. Interesting.
    – W.M.
    Commented Apr 9, 2016 at 8:06
0

Within views, you can create a block with your relevant data.

After block creation, you can assign the block to appear in your desired content area (footer/header/content/etc). Assign it, and then click "configure". You should be able to "Show block on specific pages". Selecting "Only the listed pages" and adding /node/your-node-number to the page specification should limit that view/block to appearing only with your desired node.

Cheers!

1
  • Thx for your answer :-). But then I have to create a content area for each case then. So if I like to have first text, then the view and then again text. Or if I like to have first text and then the view or first the view and then text. Then I have to create 3 different content areas which I render in the specific node temapltes. But the views_embed_view() approach is much easier and cleaner I guess. Commented Dec 14, 2014 at 12:24
0

I know you mention you'd like to use twig templates but you could use the Views Reference Field module to avoid having to dig around in templates. Also gives the advantage of being able to add it to any fieldable entity so that content editors can configure the view / output.

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.