26

How do I programmatically render a view with contextual filters in Drupal 8?

In Drupal 7, I generally use the following code.

$view = views_get_view('test_view'); //test_view is the view machine name
$view->set_display("block"); //block is the view display name
$view->set_arguments($tid); //$tid is the argument to pass
$view->pre_execute();
$view->execute();
$content = $view->render();

Is there any alternative way to achieve this in Drupal 8?

2
  • What exactly do you want to pass as an argument? maybe you can achieve what you want through the View's UI.
    – No Sssweat
    Jun 30, 2016 at 10:50
  • Yes i know i can achieve that using view UI but that is not possible in my case, i want to achieve it by some code only.
    – Sanjay
    Jun 30, 2016 at 10:59

5 Answers 5

47

Basing on the code used by views_get_view_result(), I would use the following code, as code equivalent to the one you show in the question.

  $args = [$tid];
  $view = Views::getView('test_view');
  if (is_object($view)) {
    $view->setArguments($args);
    $view->setDisplay('block');
    $view->preExecute();
    $view->execute();
    $content = $view->buildRenderable('block', $args);
  }
9
  • 5
    That's not rendering, that's just getting the results. Not the same :) The preferred way to do this is to use $view->buildRenderable($display, $arguments), see drupal.stackexchange.com/questions/198920/…
    – Berdir
    Jun 30, 2016 at 12:20
  • Yes, I was wondering the same, about result versus rendering. :D
    – apaderno
    Jun 30, 2016 at 12:23
  • 1
    @GiorgosK With Drupal 8, you never use drupal_render(). It's enough you return a renderable array, which even a controller class can do.
    – apaderno
    Nov 5, 2017 at 8:31
  • 1
    @kiamlaluno well for my use which is to modify/override the output from a views REST EXPORT (json output) passing the $content to the field formatter was just outputing "Array" on the json output ... so after I passed the drupal_render($content) it actually gave me the rendered output on the json output ... am I missing something ? is there any place to understand what you just explained ?
    – GiorgosK
    Nov 5, 2017 at 18:20
  • 1
    @GiorgosK: if you use Drupal itself for display, you don't render these days, you leave it everything in a render array up to the last point and let the system do the rest. But if you need to lift the result from Drupal (maybe to put into a newsletter or similar), then you render, yes. But start not to use drupal_render(), it will be deprecated.
    – Gábor
    Jun 1, 2018 at 22:01
15

The easiest way to render a view in Drupal 8 is using the render element provided by core: https://api.drupal.org/api/drupal/core%21modules%21views%21src%21Element%21View.php/class/View/8.9.x

  $view = [
    '#type' => 'view',
    '#name' => 'test_view',
    '#display_id' => 'block',
    '#arguments' => [$tid],
    '#embed' => TRUE,
  ],
2
  • 3
    I didn't know that it's so easy. Thank you. Jun 12, 2021 at 12:52
  • 1
    This solution is extremely smart and elegant Dec 9, 2021 at 18:56
13
/**
 * Return the rendered view with contextual filter.
 * @param string $viewId - The view machine name.
 * @param string $displayId - The display machine name.
 * @param array $arguments - The arguments to pass.
 * 
 * @return object $result
 */
function getView($viewId, $displayId, array $arguments)
{
    $result = false;
    $view = Views::getView($viewId);

    if (is_object($view)) {
        $view->setDisplay($displayId);
        $view->setArguments($arguments);
        $view->execute();

        // Render the view
        $result = \Drupal::service('renderer')->render($view->render());
    }

    return $result;
}

/**
 * Get json output.
 * @return array $data
 */
function jsonData() {
    $data = [];
    $viewId = 'rest_comments';
    $displayId = 'rest_export_1';
    $arguments = [$nid];

    // Get the view
    $result = getView($viewId, $displayId, $arguments);

    if(is_object($result)) {
        $json = $result->jsonSerialize();
        $data = json_decode($json);
    }

    return $data;
}


/**
 * Get the view object.
 * @return object $view
 */
function view() {
    $viewId = 'rest_comments';
    $displayId = 'rest_export_1';
    $arguments = [$nid];

    // Get the view
    $view = getView($viewId, $displayId, $arguments);

    return $view;
}
5

To get the actual JSON output of the REST Export display you can do something like this:

$view = Views::getView('view_id');
$render_array = $view->buildRenderable('display_name', $args);
$rendered = \Drupal::service('renderer')->renderRoot($render_array);
$json_string = $rendered->jsonSerialize();
$json_object = json_decode($rendered);
4
  • Working like charm, thanks imclean. Jul 27, 2019 at 20:56
  • works perfectly, how to set the user requesting the view? e.g. the view requires a permission to show revisions.
    – SimoneB
    Dec 2, 2019 at 8:44
  • Just noticed that you're version doesn't work with some revisions, Santo Boldižar's does
    – SimoneB
    Dec 2, 2019 at 10:59
  • I was getting crazy trying to call a REST view from my module making the HTTP call, where I had difficulty passing the correct authentication, when it came to my mind that there had to be a way to call directly the view and I found this thread. (Comment added mainly to help search engines :) ) Jul 24, 2020 at 11:13
1

This works almost everywhere I use it:

use Drupal\views\Views; // above

$activeContestId = 100; 
$view = Views::getView('mymodule_contestants');
$view->setDisplay('block_1');
// contextual relationship filter
$view->setArguments([$activeContestId]);
$view->execute();
$rendered = $view->render();
$output = \Drupal::service('renderer')->render($rendered);

Source: Render a view with contextual filters programmatically in Drupal 9

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.