10

I'm implementing a node template that uses an image twice; once in a 'normal' way (i.e. using the image style defined in the field's display configuration for that view mode), and the other is as a css background-image property.

I need one of two things:

  1. (ideally) a way to get the URL for a different image style of the same image.

  2. a way to get the URL for the image field.

I'm struggling to use dump() and kint() to help myself to an answer. They both output far far too much (thanks to embedded links to "parent" etc.) and seem to not have the info I need. e.g. looking at dump(content.field_image) output the actual URL of the image is not there (so where does it come from such that it can be rendered with {{ content.field_image }}?!). kint() on the other hand dies completely if I pass an argument to it and the top-level version is again far too big to navigate. Debugging was soo much easier with phptemplate + xdebug. (Yes I know it's good that themers can't drop the database.)

There's an answer to (1) that implies you can't do it, but I don't understand why I can't get the existing URL in (2)?

6 Answers 6

11

You can get the image style url in a preprocess function and pass it to the node template. (in my case, I needed at the page level, I'm guessing this would still work for node)

Something like this, with "myimagefield" being the machine name for your image field, and "myimagestyle" being the machine name for your style, also make sure you include the Entity\ImageStyle.

use Drupal\image\Entity\ImageStyle;

/**
 * Implements hook_preprocess_page().
*/
function mytheme_preprocess_page(&$variables, $hook) {
  if ($variables['node']) {
    $node = $variables['node'];
    if($node->myimagefield[0]){
        $cover_image = $node->myimagefield[0]->entity->getFileUri();
        $image_url = ImageStyle::load('myimagestyle')->buildUrl($cover_image);
        $variables['my_image'] = $image_url;
    }
  }
}
2
  • 1
    the question says to pull the view mode from the field's display configuration. By doing the $image_url = ImageStyle::load('myimagestyle')->buildUrl($cover_image); how are you pulling the image style from the field's configuration? You simply added myimagestyle, but what if the same field is on multiple entities (e.g. nodes) where it requires different image styles? Commented Mar 9, 2018 at 16:54
  • Is it possible to get the relative URL path instead of the absolute one?
    – CocoSkin
    Commented May 21 at 15:28
18

The first part is already answered in the linked question, where there is the code how to do this. To answer the second part of the question, you can access the original image in the node object:

{{ file_url(node.field_image.entity.uri.value) }}

One remark about content:

In a node template the image field in content is not ready to be rendered. The field contains the configuration how it should be displayed and the field object which contains all raw data. Later this will be put together in the field, image-formatter and image templates. That is the reason you don't find the url you are looking for in content at this point.

In the node template you can use the fields on the top level of the content array, for example display the image field

{{ content.field_image }}

as configured in the view mode.

Edit:

There is a new filter in the module Twig Tweak. Now you can generate the image style url in twig directly from an uri or url of the original image:

{{ node.field_image.entity.uri.value | image_style('thumbnail') }} 
5
  • Thanks. So all the preprocess hooks get called when twig calls render e.g. at the point you go {{ content.field_image }} and not before? Also, I think the url i'll get from your suggestion is the original url - part 2 of my Q was asking for the url of the image style, as configures by the view mode. Is that possible? Commented Mar 15, 2016 at 13:10
  • This only works for regular uploaded images and not for entity referenced images. How can this be made to work with entity referenced images? Commented Sep 22, 2017 at 13:52
  • @paulcap1, don't know exactly what you mean, because an image field is a reference field (to a file entity). If you mean you have the image inside of a referenced entity, then you need .entity twice, first to get to the entity and second to the image.
    – 4uk4
    Commented Sep 22, 2017 at 15:24
  • 1
    @paulcap1, for example {{ node.field_ref.entity.field_image.entity.uri.value }}
    – 4uk4
    Commented Sep 22, 2017 at 15:31
  • @4k4. I am using the default Page content type. I have an entity referenced field called field_global_image. This uses the Image Bundle. The Bundles image field is called ""image" I tried it your way using {{ node.field_global_image.entity.image.entity.uri.value }} I also tried switching the fields like this {{ node.image.entity.field_global_image.entity.uri.value }} Neither worked. In my Answer in a seperate post, that is what worked for me. Commented Sep 23, 2017 at 12:29
8

Install the Twig Tweak Module https://www.drupal.org/project/twig_tweak

And this module Twig Field https://www.drupal.org/project/twig_field_value

If you are using regular image upload field images use this in your node template:

<img src="{{ node.field_regular_image.entity.uri.value | image_style('thumbnail') }} " >

If you are using entity reference image use this:

<img src="{{ file_url(content.field_global_image|field_target_entity.image.entity.uri.value | image_style('thumbnail'))}} " >
2
  • Note that in the example about using referenced entities image after field_target_entity refers to the image field on the referenced entity. You might have to adjust it.
    – daniels
    Commented Dec 11, 2017 at 14:22
  • 1
    Thanks! The entity reference example can also be accomplished without the twig_field_value module by: file_url(node.field_image.entity.field_referenced_image.entity.uri.value | image_style('thumbnail'))
    – John
    Commented Mar 29, 2018 at 15:54
2

With twig tweaks you don't need the twig_field_value module as in @paulcap1's answer.

{% set image_uri = content.field_sbb_background_image['#items']|file_uri %}
{% set image_url =  file_url(image_uri) %}

Or if you are printing out with an image style you don't even need the image url. To print, say, the image style thumbnail:

{{ image_uri|image_style('thumbnail') }}
2

Thanks to the other contributors. In my situation I needed something slightly different to get it working:

My solution that I found to work, with background image application of it

I found this to work with Drupal 9.2.4, with contrib module twig tweak 3.1.2

url({{ node.field_background_media.entity.field_media_image.0.entity.uri.value | image_style('background_image_xl') }});

Example - Background image for page

Here's my example to illustrate the above

I have a field in my content type 'Landing Page', the field is called 'Background Media', machine name field_background_media

In my twig template in my own custom theme, (in my case, web/themes/custom/clau2/templates/content/node--landing-page.html.twig )for my content type I have:

{%
  set bg_img_styled_url = node.field_background_media.entity.field_media_image.0.entity.uri.value | image_style('background_image_xl')
%}

Where background_image_xl is the machine name of an existing style, listed in admin/config/media/image-styles

And then also in my twig, I have, which performs the purpose of providing a background image for the whole page that my content of my content type is on.

<style>

#clau-page-container-id {
    background: linear-gradient( rgba(0, 0, 0, 0.5),rgba(0, 0, 0, 0.5) ), url({{ bg_img_styled_url }});
    height: 100vh;
    background-size: cover;
    background-position: left top;
    background-color: rgba(0,0,0,0.5);
}

</style>

Where #clau-page-container-id is set in in my html.html.twig template, web/themes/custom/clau2/templates/layout/html.html.twig : -

  <body{{ attributes.addClass(body_classes).setAttribute('id', 'clau-page-container-id') }}>

( As an aside, in manage display tab of content type, this field is actually in the disabled section of the 'Full' view mode in 'manage display' for my content type ( admin/structure/types/manage/landing_page/display/full ), for my purpose - I am using it to provide a background image and don't want it output again by {{ content }} . This is only really relevant to my case. If the field is enabled the other steps will still work, because I've seen them myself to have. )

As another aside, my example means that Media entity (and convenient media browser of existing content) can be used for choosing a background image, re-using existing images, without the need for an additional contrib module.

There are good modules like bg_img_field, look and modifiers but at time of writing I'm not aware of them using the Media field type, instead they seem to use the 'legacy' image field type - less flexibility - i.e. can't browse for and re-use existing images. See further discussion about this here

See my example in action here:

(website I'm working on). I think the screenshot gives good value as to how the above twig actually provides the markup and image output.

my example in action - web page and insect element / inspect source

And from that we can observe that the required image with the image style applied is used - in that markup shown in the screenshot, the image path is: sites/default/files/styles/background_image_xl/public/2020-10/Join-us-img.jpg which contains the background_image_xl image style machine name, so that the path as a whole selects the image of that style.

1

I had a similiar scenario, and needed to get the URL of an image to use for the CSS for a background image for the whole page, except I was using a media entity instead of a file entity. I thought it might be useful to note it here. I also wanted to use the original image URL instead of a particular style. I used a modified version of the first answer:

use Drupal\file\Entity\File;
    
    // Get media file path to add to template variables to use as background image in template

    function mytheme_preprocess_page(&$variables, $hook) {
      if (isset($variables['node'])) {
        $node = $variables['node'];
       
        if($node->field_image_media[0]){
          $media_entity = $node->field_image_media[0]->entity;
          $file_id = $media_entity->getSource()->getSourceFieldValue($media_entity);
          $bg_file = File::load($file_id);          
          $path = $bg_file->createFileUrl();
          $variables['bg_image'] = $path;
        }
      }
    }

The difference is after returning the media entity, I then needed an extra step to get the entity for the file, before returning the file URL. (Thanks to Akhilavnair's comment in the How to get image file uri from media entity id thread, in showing how to retrieve the File entity from the media entity)

As this is a page preprocess function the variable was not available for the html.html.twig template, and only for the page.html.twig template. This meant to get the background image to apply to the whole page I needed to wrap the <header>, <main> and <footer> html elements in a <div> and apply the style to that wrapper <div>.

To retrieve the path and apply the styling I added the following to my page.html.twig:

{% if bg_image is defined %}
  {% set bg_style = "background-image:url('" ~ bg_image ~ "'); background-size: cover;" %}
{% endif %}

<div class="box-wrapper" style="{{ bg_style }}">
  <header>
    ...
  </header>
  <main>
    ...
  </main>
  <footer>
    ...
  </footer>
</div>

The image I am retrieving from the media field can also be used within the manage display form as normal using any of the available image styles, or it can hidden (as in my case). And voila:

The Happy Man Tree

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.