Skip to main content

Display Modes with Context

Date
2023-06-29
Client
Amon Carter

Often times we use a specific display of a node for many use cases throughout a site. We can use it in a list of view results and in another spot for a "related content" section somewhere else. Most of the markup is exactly the same except we may need to use different heading levels. However, if that markup is cached, then it will be incorrect in one of the spots.

One way of solving this is adding something to the cache data in order for Drupal to cache them separately. And this is how we do it:

First, we need to set the heading level.

/**
 * Implements hook_views_pre_render().
 */
function example_views_pre_render(ViewExecutable $view) {
  $display = $view->getDisplay();
  // Set Heading levels.
  if ($view->storage->id() == 'my_example_view') {
    foreach ($view->result as &$row) {
      $row->_entity->heading_level = 3;
    }
  }
}

For this example in "My Example View" results, I know I want all the headings set to h3. I just add a new attribute to those entities, and here I call it heading_level and set it to a heading level number. That number can be used in hook_preprocess_node() and the twig template to render the correct heading html element.

In order for this to be cached separately, I need to change something in the cache settings for this rendered element. I could add it in a number of places, however, since the heading level could be set in a number of places and potentially altered somewhere else, I want to set the cache data as late as possible and hopefully only in one place. We can use hook_node_build_defaults_alter() to add a unique key to the cache keys.

/**
 * Implements hook_node_build_defaults_alter().
 */
function example_node_build_defaults_alter(array &$build, EntityInterface $entity, $view_mode) {
  if (isset($entity->heading_level)) {
   $build['#cache']['keys'][] = "h" . $entity->heading_level;
 }
}

Depending on your use case, you could add cache tags or even a cache context, but for this simple example, all we need is a cache key.

If you look at the database after rendering this node, you will see a cache id that looks something similar to entity_view:node:5:teaser:h3.

Checkout the Drupal Cache API For more detailed information.

Related Tech