0

I'm using a hook_preprocess function (hook_preprocess_entity_print) to alter the content within a paragraph field prior to rendering (replacing some strings based on a regex). This works great when I'm working on the node, but not when I'm trying to do the same on a revision of the node.

This works for the node:

/**
 * Implements hook_preprocess_entity_print().
 */
function mymodule_preprocess_entity_print(&$variables) {
  $route = \Drupal::routeMatch();
  $entity_id = $route->getParameter('entity_id');
  $node = \Drupal::entityTypeManager()->getStorage('node')->load($entity_id);
  $type = $node->getType();
  if ($type === 'product_child') {
    foreach ($node->get('field_submittal_wysiwyg') as $paragraph) {
      $type = $paragraph->entity->getType();
      switch ($type) {
        case 'submittal_2_col':
          $field_submittal_text = $paragraph->entity->field_submittal_text_1->value;
          $field_submittal_text = mymodule_token_replace($field_submittal_text, $variables);
          $paragraph->entity->field_submittal_text_1->value = $field_submittal_text;
          break;
      }
    }
  }
}

When I decided to make these same replacements work when rendering a revision of the node, I tried this first:

/**
 * Implements hook_preprocess_entity_print().
 */
function mymodule_preprocess_entity_print(&$variables) {
  $route = \Drupal::routeMatch();
  $entity_id = $route->getParameter('entity_id');
  $revision_id = $route->getParameter('revision_id');
  $node_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($revision_id);
  $type = $node_revision->getType();
  if ($type === 'product_child') {
    foreach ($node_revision->get('field_submittal_wysiwyg') as $paragraph) {
      $type = $paragraph->entity->getType();
      switch ($type) {
        case 'submittal_2_col':
          $field_submittal_text = $paragraph->entity->field_submittal_text_1->value;
          $field_submittal_text = mymodule_token_replace($field_submittal_text, $variables);
          $paragraph->entity->field_submittal_text_1->value = $field_submittal_text;
          break;
      }
    }

  }
}

I can confirm that I'm getting the correct values for the draft revision in $field_submittal_text. But when I try to set the value of the paragraph, it works only for the published node.

I figured I must not be loading the paragraph revisions referenced within the node revisions. So I then tried to address that:

/**
 * Implements hook_preprocess_entity_print().
 */
function mymodule_preprocess_entity_print(&$variables) {
  $route = \Drupal::routeMatch();
  $entity_id = $route->getParameter('entity_id');
  $revision_id = $route->getParameter('revision_id');
  $node_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($revision_id);
  $type = $node_revision->getType();
  if ($type === 'product_child') {
    $field_submittal_wysiwyg = $node_revision->field_submittal_wysiwyg->referencedEntities();
    foreach ($field_submittal_wysiwyg as $paragraph) {
      $paragraph_type = $paragraph->getType();
      switch ($paragraph_type) {
        case 'submittal_2_col':
          $field_submittal_text = $paragraph->field_submittal_text_1->value;
          $field_submittal_text = mymodule_token_replace($field_submittal_text, $variables);
          $paragraph->field_submittal_text_1->value = $field_submittal_text;
          break;
      }
    }
  }
}

Again, I can confirm that I'm getting the correct values for $field_submittal_text based on the revision that I'm trying to load. But the last line before the break isn't changing what is rendered.

What do I need to do to set the value of the paragraph field for a revision before rendering?

ETA: I'm attempting to replace some product attribute values in several paragraph WYSIWYG fields with values from another field, based on a product_id sent in through the route parameters. So I need access to multiple fields in order to do these replacements.

4
  • Doesn't the $variables already contain the entity and by that also the parent entity? That means there's no need to get the node from the route. Getting the parent entity from the $variables also means your code would work even when you are not viewing a node on its canonical URL (in views for example).
    – leymannx
    May 23, 2023 at 7:22
  • It's not surprising that I made it more complicated than it needs to be. For some reason, accessing entities programmatically has confused me. Thanks for the advice; I'll look into stripping it down to changing $variables directly.
    – Mark
    May 24, 2023 at 13:58
  • So far, in $variables, I'm able to find only the published versions of the paragraph fields I'm seeking to alter. I can't locate the draft version. This is the case regardless of whether I'm viewing the published revision or a draft. This is why I went to the extra step of loading the node_revision.
    – Mark
    May 24, 2023 at 18:31
  • (I do wonder if I might be missing the values I'm seeking due to a max_depth for my dump() statement.)
    – Mark
    May 24, 2023 at 18:37

1 Answer 1

1

The purpose of a preprocess hook is to prepare the variables printed in the template. Check the {{...}} statements in the Twig template.

Some other options:

  • Look for a different template that prints the variable you want to change.
  • Create a custom text filter and add it to the text format.
  • Add a #post_render callback, see How to alter page content?
3
  • I added a little more context to my question. I'm trying to change some text strings (essentially token strings) in a few paragraph wysiwyg fields with values from another field (product data text field) based on a product_id sent in the route parameters. So I need access to multiple fields at once. All this needs to occur prior to handing over to entity_print to render the PDF. I handled this for the published revision of the node using this preprocess hook; now just trying to make the same thing work for a draft revision.
    – Mark
    May 24, 2023 at 17:30
  • 1
    Instead of the futile attempt to change objects out of scope in a preprocess hook, you might consider storing the computed data in a new field. The simplest Drupal way for a computed field is an extra field, if you don't want to define a custom field plugin. See webomelette.com/creating-pseudo-fields-drupal-8. You can also consider putting the extra field inside the paragraph type, it's easier to access the different fields (read-only!) from there.
    – 4uk4
    May 24, 2023 at 20:31
  • I was able to accomplish what I needed with hook_ENTITY_TYPE_view(). Thanks!
    – Mark
    May 29, 2023 at 15:32

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.