As the subject says:  Simply, how in Drupal 8 do I get a file linked on a page to open in a new window/tab (target="_blank").  I don't see anything in the interface and can't find a module that seems to support this.  Back with my Drupal 6 sites, i could hack a file and add the attribute.  Can I modify a theme somehow to do this?  Can someone give me a quick tutorial?

Thanks much!

Comments

pwetter’s picture

So, found something that get's the job done, but probably isn't the proper solution.

Modify: /core/modules/file/file.module

Find the template_preprocess_file_link function.

Below:

$options['attributes']['type'] = $mime_type . '; length=' . $file->getSize();

Add:

$options['attributes']['target'] = '_blank';
msypes’s picture

This violates rule #1 (at least my rule #1) when using Drupal: "Don't hack core."
Go with the suggestion below, as I am going to, having come across this page looking for the same thing. FWIW, I'm also going to try adding download as an attribute.

Michael

pwetter’s picture

As I said, “probably not a proper solution”, like duct tape.  Once it was posted, I did go with the hook addition to my theme to fix the issue

msypes’s picture

Unfortunately, I had to create a custom template for the containing entity (a paragraph in my case) of the media file and hardcode the <a> tag with download as an attribute. Very unsatisfying.

Michael

jamiebs45’s picture

If you prefer not to update core, use a hook_preprocess_file_link function in your theme file to add the target attribute on the generated link. Here's an example:

function hook_preprocess_file_link(&$variables) {
  if($variables['link'] && $variables['link'] instanceof \Drupal\Core\GeneratedLink){
    $doc = new DOMDocument();
    $doc->loadHTML($variables['link']->getGeneratedLink());
    $node = $doc->getElementsByTagName('a')[0];
    $node->setAttribute('target', '_blank');
    $variables['link']->setGeneratedLink($doc->saveHTML());
  }
}

By the time this hook runs, the file link HTML has already been generated. So, we have to parse the HTML into a DOMDocument object, set the target attribute and then write the modified HTML back out into the generated link.

pwetter’s picture

Thank you!  This works perfectly!  Exactly what I was looking for.

aiphes’s picture

Does it would work for link field data ? Because actually it does nothing on my website. 

Dev Server Shared Hosting
8 websites powered by drupal 6,8 & 9 - Hosted by Always Data

pwetter’s picture

No.  In my experience, it only opens links to files in a new window.  Not, general links.  My issue was dealing with file field links that I wanted to open in new tab. 

aiphes’s picture

for linkfields, this module give option to choose attribute: https://www.drupal.org/project/link_attributes/issues/3055369

but not to set it by default,  for the moment.

Dev Server Shared Hosting
8 websites powered by drupal 6,8 & 9 - Hosted by Always Data

aiphes’s picture

Hi. I try your code but file field aren't opened in blank and attributes isn't change.

I put your code into my .theme file in replacement of my buggy code (that work until D8.8.1). 

Dev Server Shared Hosting
8 websites powered by drupal 6,8 & 9 - Hosted by Always Data

adominique’s picture

For media files links that use instanceof \Drupal\Core\Url, alternative hook process is:

function as_d8w3css_preprocess_file_link(&$variables) {
  if($variables['link'] && $variables['link']['#url'] instanceof \Drupal\Core\Url){
     
      $options = $variables['link']['#url']->getOptions('attributes');
      $options['attributes'] +=  ['target' => '_blank'];
      $variables['link']['#url']->setOptions($options);
      
  }
}

This will add the target under object url attributes:

Array
(
    [#type] => link
    [#url] => stdClass Object
        (
            [__CLASS__] => Drupal\Core\Url
            [urlGenerator:protected] => 
            [urlAssembler:protected] => 
            [accessManager:protected] => 
            [routeName:protected] => 
            [routeParameters:protected] => Array
                (
                )

            [options:protected] => Array
                (
                    [attributes] => Array
                        (
                            [type] => application/pdf; length=1
                            [target] => _blank
                        )

                    [external] => 1
                )
...
amneh.shawish’s picture

This code solved my issue, Thank you adominique

danflanagan8’s picture

I made a Field Formatter on a recent project for creating more configurable file download links. You get to choose whether or not to open the file in a new tab, whether the browser should add the download attribute to the link, and the link text. You could put this in a custom module at your_module/src/Plugin/Field/FieldFormatter. Depending on what link text you want to display, it might not work for you, but I thought it would be worth throwing out there.

<?php

namespace Drupal\your_module\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\file\Plugin\Field\FieldFormatter\FileFormatterBase;
use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface;

/**
 * Plugin implementation of the 'file_download_link' formatter.
 *
 * @FieldFormatter(
 *   id = "file_download_link",
 *   label = @Translation("File Download Link"),
 *   weight = "100",
 *   field_types = {
 *     "file"
 *   }
 * )
 */
class FileDownloadLink extends FileFormatterBase {

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    $options = parent::defaultSettings();
    $options['link_text'] = 'Download';
    $options['new_tab'] = TRUE;
    $options['force_download'] = TRUE;
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $element = parent::settingsForm($form, $form_state);
    $element['link_text'] = [
      '#type' => 'textfield',
      '#title' => 'Link Text',
      '#default_value' => $this->getSetting('link_text'),
      '#description' => 'This text is linked to the file',
      '#required' => TRUE,
    ];
    $element['new_tab'] = [
      '#type' => 'checkbox',
      '#title' => 'Open file in new tab',
      '#default_value' => $this->getSetting('new_tab'),
    ];
    $element['force_download'] = [
      '#type' => 'checkbox',
      '#title' => 'Force Download',
      '#default_value' => $this->getSetting('force_download'),
      '#description' => 'This adds the <i>download</i> attribute to the link, which works in many modern browsers.',
    ];
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    $summary = ['Link text: ' . $this->getSetting('link_text')];
    if ($this->getSetting('new_tab')) {
      $summary[] = 'Open in new tab';
    }
    if ($this->getSetting('force_download')) {
      $summary[] = 'Force download';
    }
    return $summary;
  }

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = [];

    foreach ($this->getEntitiesToView($items, $langcode) as $delta => $file) {

      //options for the link, like classes
      $file_type_explosion = explode("/", $file->getMimeType());
      $file_type = end($file_type_explosion);
      $options = [
        'attributes' => [
          'class' => [
            'file-download',
            'file-download-' . $file_type,
          ],
        ]
      ];
      if ($this->getSetting('new_tab')) {
        $options['attributes']['target'] = '_blank';
      }
      if ($this->getSetting('force_download')) {
        $options['attributes']['download'] = TRUE;
      }

      //make the render array
      $elements[$delta] = [
        '#type' => 'link',
        '#title' => $this->getSetting('link_text'),
        '#url' => Url::fromUri(file_create_url($file->getFileUri())),
        '#options' => $options,
        '#cache' => [
          'tags' => $file->getCacheTags(),
        ],
      ];
    }

    return $elements;
  }

}
DD 85’s picture

Please create a project with a ready-made module.

danflanagan8’s picture

https://www.drupal.org/project/file_download_link

Let me know if there are any problems.