1

I have a case where in my node's template I need an image style URL from the Media entity referenced by this node. I need a raw value of this URL to use it like that: <div style="background-image: url('[my-image-url-goes-here]')">

I know multiple ways of achieving this, like using twig_tweak module (but I think it would be an overkill) or preprocessing hook (feels ugly), or creating custom twig filters for extracting data that I need. Actually I could even do something like that: content.field_media_image|render|striptags|spaceless to isolate URL returned by rendered Media display but that is especially ridiculous and would work with only single value. After few hours of research I started considering creating a custom formatter for entity_reference fields, that would just output raw data, like for example:

[
  '#url' => $my_image_style_url,
]

That looks nice, I could then just set it as a formatter of my entity_reference field referencing my Media image entity and I could use this #url in my node as I wish. But it seems to have one weakness. I cannot set cache tags on that, because it's not renderable - it would be rendered in parent template that may not have cache tags that would ensure that it would be cleared if one of values sent to it that way, would change for reasons unrelated to this node. So it doesn't feel like a right solution in the end.

Now I'm starting to realize that I cannot reliably do what I wanted, because by isolating one information from a field like that, I'm automatically ignoring its cache tags. Is making ugly preprocessing hooks the only option I have for that? Am I missing something?

9
  • Whether it feels ugly or not, a preprocessor is how to do this. You'll set up a variable containing the image style URL, and use that in your template. This will respect caching systems.
    – Jaypan
    Mar 8, 2020 at 1:25
  • The field formatter interface requires view() to return a render array, which then, when rendered, will bubble cache data. All hacks you find on the internet hacking {{ content }} are bad examples like the one in your question. The solution of your problem is adding a template (which might be an inline template if you don't want to make the extra effort to provide one in the module) and adjusting the CSS rather than trying to produce a verbatim HTML output.
    – 4uk4
    Mar 8, 2020 at 11:01
  • Actually I think I found a solution. In my formatter I can return my values AND return cache tags, and then just render these cache tags in template I'm using my values in, like so {{ {'#cache': content.field_myfield.0['#cache']} }}. That way cache tags will be actually bubbled and I can freely use any values returned from my formatter. It isn't prettiest solution but is vastly cleaner than using preprocessing if I have configurable output - like with image styles - this configuration can be stored in formatters and changed per field easily. I think that may be actually the cleanest way. Mar 8, 2020 at 18:38
  • But you still need to get a value from inside of the fields render array, which is not a good idea, because the position of the value can change at any time, for example by using a layout module. Why not render the inline CSS in the field directly and target the div container with CSS selectors?
    – 4uk4
    Mar 8, 2020 at 19:34
  • What you can do from the field is to bubble up an attachment along with the cache metadata to add the CSS to <head> , see drupal.stackexchange.com/a/212395/47547
    – 4uk4
    Mar 8, 2020 at 19:59

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.