0

I am new to Drupal and building a theme with Drupal 8 + PatternLab. Instead of printing the actual paragraphs, I just extract the data from the fields and pass it to the front-end twig modules. For example, I have a "Hero" paragraph with a nested "Video" paragraph. The "Hero" paragraph has a "Title" field and the "Video" paragraph has a "Video URL" field. The "Video URL" field is of type "Media", which would be a reference to an entity. Here is the template for the paragraph:

// paragraph--hero.html.twig {% include '@organisms/o-hero.twig' with { title: data.title, video_url: ??? } %}

Here is the THEME.theme:

function THEME_preprocess_paragraph(&$variables) {
  foreach ($variables['content'] as $field => $fieldData) {
    if (isset($fieldData['#field_type'])) {
      $newField = preg_replace('/^field_/', '', $field);

      // text
      if (in_array($fieldData['#field_type'], ['string', 'string_long', 'text', 'text_long'])) {
        if ($fieldData['#is_multiple']) {
          $variables['data'][$newField] = array_map(function ($item) {
            return $item['value'];
          }, $fieldData['#items']->getValue());
        } else {
          $variables['data'][$newField] = $fieldData['#items']->getValue()[0]['value'];
        }
      }

      // link
      if (in_array($fieldData['#field_type'], ['link'])) {
        $link = $fieldData[0];
        $title = $link['#title'];
        $url = $link['#url']->toString();
        $target = $link['#options']['attributes']['target'] ?? null;
        // echo '<pre>'; var_dump($link); exit;
        if (!$fieldData['#is_multiple']) {
          $variables['data'][$newField] = [
            'title' => $title ? $title : null,
            'href' => $url ? $url : null,
            'target' => $target ? $target : null
          ];
        }
      }

      // image
      if (in_array($fieldData['#field_type'], ['entity_reference'])) {
        if (!$fieldData['#is_multiple']) {
          if (isset($fieldData[0]['#media']->field_media_image)) {
            $image = $fieldData[0]['#media']->field_media_image;

            $imageUri = $image->entity->uri->value;
            $imageUrl = file_create_url($imageUri);

            $variables['data'][$newField] = [
              'alt' => $image->alt,
              'sizes' => [
                'default' => $imageUrl
              ]
            ];
          }
        }
      }
    }
  }
}

This way I get the data variable with only the data I need in the front-end. But the problem is that when using a nested Paragraph, it won't go through the pre-process functions since it's not actually being rendered, only its data are being extracted. Now, I can access the "Video URL" media inside the "Video" paragraph, but it only gives back the Entity ID value, and it doesn't get populated with the actual Entity values so I can extract the video thumbnail / title / url.

I am not sure if I could explain this correctly, but I want to be able to access content.field_video_paragraph fields same way I access the main paragraph field content.field_title.

2

I'd advice not to loop through the render array content, but go directly for the entity object, in your case $paragraphObject = $variables['paragraph']

Once you have the object, you can always query any data you want, to drill through a referenced/nested entity, use ->entity:
$paragaph->hostfield->first()->entity->field_whatever->value

For paragraphs, you can also query upwards:
$parentEntity = $paragraph->getParentEntity()

The example above works similar for almost all entity templates like node.html.twig or paragraph.html.twig and actually wouldn't need any preprocessing at all, since the entity object is passed to Twig:

Most of the time you can use
entity.fieldname.index.value

E.g. for a simple plain text field:
{{ paragraph.field_whatever.0.value }}

For nested paragraphs or referenced entities you can use:
{{ paragraph.hostfield.0.target_id }} /* only numeric ID of ref.ent. */
{% paragraph.hostfield.0.entity %} /* referenced entity object, can be queried again */
{{ paragraph.hostfield.0.entity.field_whatever.0.value }} /* field value of a nested paragraph */

For your hero paragraph you could do something like

{% include 'hero.twig' with { title: paragraph.field_title.0.value } %}

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.