1

I have two templates: - a child that is printing each item in a list; - and a parent that calls it there is also an intermediate Field template that is not involved.

The parent has preprocess access to node field data that each child (node teaser) call needs to use. The child is printing items in a multivalue entity reference field.

How can the child get the data from the parent felds so it can print the right html?

Edit: Just in case it's not clear, the situation is:

paragraph_entity        <== preprocess hook can see field_settingsN which change how "B" and "A" render (e.g. add/change attrs, class).
  -> field_settings_1
  -> field_settings_2
  -> field_references   <== have a defined template "B"
    -> 1.. entity refs to nodes
      -> node           <== have a defined (teaser) template "A"
  • There is nothing pointing from the child to the parent. The child doesn't know if it is referenced, unless you query the database for parents (there can be more than one) having the child's target id or join both entity tables in a View. – 4k4 May 12 at 8:58
  • I was hoping the parent can save some data in the environment of the child... is that possible? – rivimey May 12 at 13:18
  • 1
    100% doable. Actually did this within the last week, answer coming right up. – Nick Wilde May 12 at 13:45
1

Done this a couple times, but really got the caching better last time so that it works perfectly... I've put in some fairly verbose comments, but if anything is unclear just shout.

/**
 * Implements HOOK_preprocess_paragraph().
 */
function HOOK_preprocess_paragraph(array &$vars) {
  /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
  $paragraph = $vars['paragraph'];
  // Change 'content_reference' to be your paragraph bundle's machine name.
  if ($paragraph->bundle() === 'content_reference') {
    // Instead of 10 set that to be the max number of references in the field.
    foreach (range(0, 10) as $i) {
      // Change all references to 'field_content_reference' to use your field's
      // machine name.
      if (!isset($vars["content"]["field_content_reference"][$i])) {
        break;
      }
      /** @var \Drupal\node\Entity\Node $node */
      $node = $vars["content"]["field_content_reference"][$i]["#node"];

      // Example change to the Node.
      $node->field_parent_paragraph = $paragraph;
      $changed = TRUE;

      if (isset($changed)) {
        // If we've changed the node, give a new cache id.
        // THIS IS IMPORTANT!
        $vars["content"]["field_content_reference"][$i]['#cache']['tags'][] = "paragraph:{$paragraph->id()}";
        $vars["content"]["field_content_reference"][$i]['#cache']['keys'][] = "paragraph";
        $vars["content"]["field_content_reference"][$i]['#cache']['keys'][] = $paragraph->id();
      }
    }
  }
}

Follow that up with something like:

/**
 * Implements HOOK_preprocess_node().
 */
function HOOK_preprocess_node(array &$vars) {
  /** @var \Drupal\node\Entity\Node $node */
  $node = $vars['node'];
  if (isset($node->field_parent_paragraph)) {
    $paragraph = $node->field_parent_paragraph;
    $vars['content']['#attributes']['class'][] = $paragraph->field_settings_1->value;
  }
}
  • Thanks, Nick. If I understand, you're setting a value on just the in-memory copy of referenced nodes, so when they are rendered they can look up their parent and determine the needed settings? – rivimey May 12 at 14:07
  • I don't want to risk saving such local changes, because a given referenced node may well be referenced from more than one place. – rivimey May 12 at 14:08
  • Pretty much. In that example I didn't actually set any parent reference - instead I set the title on the node to match an imaginary title field on the paragraph. I'll do a slight change actually to match your example need a bit better. – Nick Wilde May 12 at 14:09
  • As long as you don't call $node->save() it won't save the changes anywhere. – Nick Wilde May 12 at 14:10
  • 1
    That's great..For the sake of other readers, I presume in the second part the field_paragraph should be field_parent_paragraph? – rivimey May 12 at 14:15

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.