One of my sites has a listing of content shown as teaser. The teaser for this content type is defined to show the title, an image, and a few other fields. In the listing, the image is linked to the content so that the visitor may click on the image (or the title) to open the content. All this is easily achievable through regular Drupal site building.
I wanted to change the functionality so that clicking on the image would open the content in a new tab. This is easy for the title, as the title is linked right from within the template (
node--content-type--teaser.html.twig). I just have to add the
target="_blank" attribute for the
<a> tag for the title and I am done. Doing this for the image is not so easy.
Challenges with the Image Formatter
The reason it isn’t easy for the image is the image field formatter provided by the Drupal core. It provides an option to render the image as a link and link it to either the content or the file itself, but no option to open it in a new tab.
Digging through the code for image formatter, I found the template that drives it at
image-formatter.html.twig. This template also does not help us much directly, as we cannot conditionally modify this template only for teasers for certain content types, like I wanted. If I override this file, it will affect the image formatter everywhere.
I stumbled upon an approach when searching for solutions for this, hoping I will run across an issue in Drupal core which would add this feature. I would simply apply the patch and voila, I would solve my problem, give feedback if it worked, and open source wins. Unfortunately, there was no such issue but I found something related: Image formatter does not support URL/Link options.
Sidenote: I could have created a feature request to add this feature and maybe I’ll do it when I get a chance. Today, I was just eager to get this working.
Back to the issue. I see there is a change in the template to use the
link function rather than just writing an
<a> tag. This is not very helpful to me. But the issue summary described my problem, and it is strange that the patch (which was committed) does not fix it. So, I dug in more. I read the test in the patch which gave me the approach how I can implement it.
Since my solution depends on the above patch, it would work only with Drupal 8.7.4 or later. The test in the patch added attributes to the link by accessing the build array and directly setting the attribute on the URL object that is passed to the template. I realised I could do the same with
In the code sample above, I am targeting the specific content type and display mode (teaser) I want to modify. I use
Element::children to loop through all the items in the field and access the URL object. I directly call
setOption on the URL object to set the attribute
It might seem a lot of work but this is the fastest way I know (and minimal code change). If you know of a better way, or of the Drupal core issue that would have given this option, please let me know in the comments. I hope this post was useful. Thanks for reading.