I have a working preprocess function that allows me to grab an image for use as a background in the page template from a node if the field exists. It falls back on a default image if supplied, the function looks like this:
<?php
/**
* Implements hook_preprocess_page() for page.html.twig.
*/
function mymodule_preprocess_page(array &$vars) {
// Preprocess the hero image if it exists (it should on all nodes).
if (isset($vars['node']->field_hero)){
$field_hero = $vars['node']->get('field_hero')->getValue();
// If a file has been uploaded, get it.
if (!empty($field_hero)){
$hero_id = $field_hero[0]['target_id'];
$file = File::load($hero_id);
// Otherwise get the default if there is one.
} else {
$default_image = $vars['node']->getFields()['field_hero']->getFieldDefinition()->getSetting('default_image');
$file = Drupal::service('entity.repository')->loadEntityByUuid('file', $default_image['uuid']);
}
// If a file has been found (there might not be a default), get its path.
if ($file){
$path = $file->getFileUri();
$vars['hero'] = ImageStyle::load('hero_image')->buildUrl($path);
}
}
}
Finding the default file is a convoluted mess of steps that requires loading all of the fields... there has got to be a better way to do this. Is there?