Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough

Render programmatically a unique field from a node or an entity with Drupal 8

It may sometimes be necessary to render a single field of a content or entity. For example, for a simplified display of contents relating to the content consulted, the use of specific fields in other contexts, etc. Obtaining programmatically the rendering of a field may be problematic for the Drupal 8 cache invalidation system, since the resulting render array would not contain the cache tags of the source entity. So this field displayed In another context can not be invalidated if the source node were to be updated.

Let's take a look at some solutions available to us.

Using View Mode

To avoid this problem, and to avoid having to start managing the cache tags manually (Drupal 8 is already doing very well, and certainly better), we can opt for a specific view mode for the entity in question, and this view mode will only contain the field that we want to display. Thus, we will render this field individually, by simply displaying this content in this specific view mode, and thus all the cache tags or context linked to our source content will be added automatically to the page in which this field will be used. And we do not have to manage the tags caches of the source node, instead of Drupal 8 core.

Rendering an individual field programmatically

This last solution applies if this type of need remains marginal, and the number of fields to be displayed individually is limited, because if we were to create as many view modes as individual fields, for a very large number of fields, this option could quickly become indigestible, time consuming and very painful to maintain.

We can then use a few lines of code to render this individual field, and be able to inject it into any page.

This snippet will allow us to retrieve the render array for a field individually.

/**
 * Implements hook_preprocess_HOOK().
 */
function my_module_preprocess_node(&$variables) {
  /** @var \Drupal\node\NodeInterface $node */
  $node = $variables['elements']['#node'];

  $entity_type = 'node';
  $entity_id = 2;
  $field_name = 'body';

  /** @var \Drupal\node\NodeInterface $source */
  $source = \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id);
  $viewBuilder = \Drupal::entityTypeManager()->getViewBuilder($entity_type);
  $output = '';

  if ($source->hasField($field_name) && $source->access('view')) {
    $value = $source->get($field_name);
    $output = $viewBuilder->viewField($value, 'full');
    $output['#cache']['tags'] = $source->getCacheTags();
  }

  if ($node->id() == '1') {
    $variables['content']['other_body'] = $output;
  }

}

In this example, we retrieve the body field from a node (with the id 2), reconstruct its render array in the "full" view mode, and then add to the array the cache tag of the node Source (node:2). Finally, we add this field in the variables supplied to the Twig template for the node whose id is 1.

Without adding the source node's cache tag with the line below, then if the source node is updated, its body field rendered in another context will remain the same. Or worse, if we unpublish this source content, some of its content will always be visible in another context.

$output ['# cache'] ['tags'] = $source->getCacheTags();

It is enough to check in the headers of the page on the content (node ​​1), without this addition, only the cache of the current node is present (node:1).
 

Entêtes de la page et debug des cache tags

By adding the source node cache tag to the render array of the individual field, we ensure that this field is always up-to-date, regardless of the context in which it is displayed. Thus we can check the cache tags of the content (node ​​1) on which we injected this field coming from the node 2.

Entêtes de la page et debug des cache tags

We now have the cache tag node:2 present in the headers, making sure that this page will be invalidated as soon as the source content is modified. We can now, in all tranquility, resort to this method to inject individual fields of any entity into another context.

It is enough to not forget the cache tags (among others), and during the development phase, it is necessary to think to activate the cache on a regular basis (which does not deactivate the caches definitively during the development phase?). We were able to see, the cache system, its management, its invalidation, must be an integral part of the development process, otherwise there will certainly be some issues when deploying to production the Drupal 8 project.

Author: 
Original Post: 

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web