TL;DR: You're going to need to spend your time in Drupal's Twig templates, often using colourful language, before certain things will start to click together, but using devel and kint and knowing about the magical 'entity' keyword will speed up this ghastly process!
Drupal's data structures can seem a bit mad when you're inside a Twig template and you just want to get to data, but when you understand the object-oriented nature of Drupal 8 a bit better, and that most things are entities, there are some nifty tricks that you can employ to get to data inside of Twig templates without resorting to PHP preprocess.
Let me begin with an example from the previous project I worked on because I can directly compare it to the pattern lab we've just launched and our solution on this project was significantly cleaner. Both projects implemented paragraphs (the module) to create content and the media module to handle files, videos and imagery. Here was a typical entity reference chain we need to traverse in order to get to the data we needed to populate a pattern lab component.
PARAGRAPH > IMAGE FIELD > MEDIA ENTITY > FILE ENTITY > FILE URI
In order to access the URL for an image on a paragraph, we needed to do lots of entity hopping in order to reach the file entity and convert its URI value. On the previous project, we were doing this via preprocess due to the nature of the entity reference chain:
<?php
use Drupal\file\Entity\File;
use Drupal\image\Entity\ImageStyle;
use Drupal\media\Entity\Media;
/**
* Implements hook_preprocess_paragraph().
*
* full_image paragraph type.
*/
function themename_preprocess_paragraph__full_image(&$vars) {
/** @var Paragraph $paragraph */
$paragraph = $vars['elements']['#paragraph'];
if ($paragraph->hasField('field_image') && $paragraph->field_image->count()) {
// Load the media entity and image file entity.
/** @var Media $media */
$media = Media::load($paragraph->field_image->target_id);
if (is_object($media)) {
/** @var File $file */
$file = File::load($media->field_image->target_id);
if (is_object($file)) {
// Lookup the image style from the active config object.
$image_style = \Drupal::config('core.entity_view_display.paragraph.full_image.default')->get('content.field_image.settings.view_mode');
// Define the variables usable in the template
$vars['full_image']['url'] = ImageStyle::load($image_style)->buildUrl($file->getFileUri());
$vars['full_image']['alt'] = $media->field_image->alt;
}
}
}
}
But it turns out there's a magic entity keyword in Twig which allows us to do all of the above in a much more simple process right inside of the TWIG template:
{% include '@organisms/paragraphs/image/image.twig' with {
"img_src": paragraph.field_image.entity.field_media_image.0.entity.uri.value|image_style('medium'),
"img_alt": paragraph.field_image.entity.field_media_image.0.alt,
} %}
Imagine my despair at how much preprocess code exists in that previous project, knowing you can magically traverse an entity reference chain right inside of TWIG ?!
There are many Drupalisms that you just have to learn in order to get to the data you require, and as mentioned in Lesson 6, there are modules which will help with this as well. Essentially the devel (and its bundled devel kint module) are going to be essential to mining through the data structures to get to where you need to.