9

I want to render a node's field inside a block. It works like this:

<?php

if ($node) {
  if (isset($node->field_body_secondary) && $field = $node->field_body_secondary->value) {
    $markup = render($field);
    $build = array(
      '#type' => 'markup',
      '#markup' => $markup,
    );
  }
}

return $build;

But this is not 100% as if I would just render the field normally, making it visible in the view mode settings.

0

I think the viewmode should be applied to the node, not to the field. So you need to get the viewbuilder and render the node. Afterwards you can pick the rendered array for the field from the node'r render array. Kind of like this:

$vb = [EntityTypeManager]->getViewBuilder('node'); // Drupal\node\NodeViewBuilder
$nodeview = $vb->view($node, $viewmode);
$fieldrenderarray = $nodeview[youfield-here];

P.S. You need to "[EntityTypeManager]" anyhow injected as @entity_type.manager service. Or get it in your Block-Plugin create() from $container->get('entity_type.manager').

  • 1
    not quite. $nodeview has #node as key – Alex Jul 22 '16 at 10:26
  • 1
    also, this renders the node, not seperate fields – Alex Jul 22 '16 at 10:32
  • 1
    Yes, I renders the node (and all it's fields). But this is what you adjust in your view mode settings. Maybe I got your question wrong. – Rainer Feike Jul 22 '16 at 10:37
  • 1
    "$nodeview[youfield-here];" is null, at least on Drupal 8.6.x – Onkeltem Apr 16 at 4:06
  • 1
    Replace "yourfield-here" with the machine name of your field. – Rainer Feike Apr 16 at 14:42
26

To render a single field with the display setting of a view mode you can use the view() method of the field:

Example for rendering the image in teaser format:

$build['image'] = $node->field_image->view('teaser');

Or the body in full:

$build['body'] = $node->body->view('full');
  • 1
    unfortunately, this does not respect the view mode settings, like labels and formatter settings – Alex Jul 26 '16 at 7:44
  • 1
    This should work, you can even use twig debug with this command. If you provide an existing view mode as string, the field will be formatted with this. If you provide an array you can give your own display settings, for example ['label' => 'inline' ] – 4k4 Jul 26 '16 at 8:16
  • 1
    i believe i tried that already but it didnt work. i will try again. thanks so far – Alex Jul 26 '16 at 8:18
  • 1
    I find it is respecting the formatter, but not the formatter settings. The output of this includes the correct settings. – Grayside May 1 '17 at 20:05
  • 1
    this essentially got me to the answer, where I can get my variable in .twig: $vars['var_name'] = $node_object->field_name->view()[0]; and then in twig, I can render {{ var_name }} – bdanin Oct 5 '17 at 23:04
4

This answer builds on https://drupal.stackexchange.com/a/208061/394

// Designate the field we want to render.
$field_name = 'body';
// Retrieve a render array for that field with the given view mode.
$render_array = $entity->$field_name->view('full');
// Render the result.
\Drupal::service('renderer')->renderRoot($render_array);

To completely programmatically render the field you finish by calling renderRoot(), which establishes a separate render context from what typical page responses would use -- a single render context for a request or sub-request. We could also use renderPlain(), but then it would escape all the things.

In the Drush repl but not in normal page execution, this threw a warning for me:

PHP warning:  DOMDocument::loadHTML(): Tag drupal-entity invalid in Entity, line: 1 in /drupal/core/lib/Drupal/Component/Utility/Html.php on line 286
2

related to Alex's answer, here is how I modified it to use config_pages and build a global_footer block:

<?php

public function build() {
$config_name = 'global_footer';
$config = config_pages_config($config_name);
$build = array();
$markup = array();

$fieldsToRender = array(
  'field_body', 'field_foo', 'field_bar'
);

$viewmode = 'default';
$entityType = 'config_pages';
$display = entity_get_display($entityType, $config_name, $viewmode);
$viewBuilder = \Drupal::entityTypeManager()->getViewBuilder($entityType);

foreach ($fieldsToRender as $field_name) {
  if (isset($config->{$field_name}) && $field = $config->{$field_name}) {
    $fieldRenderable = $viewBuilder->viewField($field, $display->getComponent($field_name));
    if (count($fieldRenderable) &&! empty($fieldRenderable)) {
      $markup[] = \Drupal::service('renderer')->renderRoot($fieldRenderable);
    }
  }
}

if (count($markup)) {
  $build = array(
    '#type' => 'markup',
    '#markup' => implode("", $markup),
  );
}

return $build;

}

It's probably better to render arbitrary fields from a config_pages setup as opposed to pulling data from a node, but I guess it really depends on the specific use-case as to which method is best.

2

Thanks to Rainer Feike's answer I came to the solution:

<?php

public function build() {
  $node = \Drupal::routeMatch()->getParameter('node');
  $build = array();
  $markup = array();

  $fieldsToRender = array(
    'field_node_ref', 'field_foo', 'field_bar',
  );

  $viewmode = 'default';
  $entityType = 'node';
  $display = entity_get_display($entityType, $node->getType(), $viewmode);
  $viewBuilder = \Drupal::entityTypeManager()->getViewBuilder($entityType);

  foreach ($fieldsToRender as $field_name) {
    if (isset($node->{$field_name}) && $field = $node->{$field_name}) {
      $fieldRenderable = $viewBuilder->viewField($field, $display->getComponent($field_name));
      if (count($fieldRenderable) &&! empty($fieldRenderable)) {
        $markup[] = \Drupal::service('renderer')->renderRoot($fieldRenderable);
      }
    }  
  }

  if (count($markup)) {
    $build = array(
      '#type' => 'markup',
      '#markup' => implode("", $markup),
    );
  }

  return $build;

}

Using $viewBuilder->viewField I can render any fields separately I need. I just need to find out how to add caching depending on the view mode settings, but this is another question :)

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.