2

I'm trying to override the file-link.html.twig to display the size next to the file link (also the file MIME type, but I think I can figure that out once I figure out how to display the size) but so far I've been failing spectacularly. I assume this must be super simple and I'm missing something obvious.

Using kint($variables) in the function themename_preprocess_file_link(&$variables) I see the filesize:

$args array (1)
array (15
'file' => Drupal\file\Entity\File(27) 
"contents" tab:
    protected values -> array(13)
    'filesize' => array(1)
    'x-default' => string(7) "2245389"

But I can't figure out how to turn this into a variable I can use in a template file.

I tried following How can I override template_preprocess_file_link function? but then I couldn't figure out what was suppose to be the variable to use in the template file. Also, his "code" just seems to be same as what is on https://api.drupal.org/api/drupal/core%21modules%21file%21file.module/function/template_preprocess_file_link/8.6.x.

2
  • I know this isn't exactly what you are asking for, but you can use tokens to display the file size and mime type (handy if you are using display suite, for example). [file:size] & [file:mime] - or you can access them in the twig if you install Twig Tweak drupal_token([file:size]) -- drupal.org/project/twig_tweak
    – 100pic
    Feb 26, 2019 at 5:58
  • How do I use token in a node template? I tried this for a referenced media file but it doesn't work? {{ drupal_token('node.myfield.entity|file:size') }} Nov 1, 2019 at 11:24

2 Answers 2

3

Using HOOK_preprocess_field(&$variables):

/**
 * Implements HOOK_preprocess_field().
 *
 * @inheritdoc
 */
function HOOK_preprocess_field(&$variables) {
  $element = $variables['element'];
  // Check that field_name is set.
  if (isset($element['#field_name'])) {
    // Checking for field_name, but could check for field_type.
    if ($element['#field_name'] == 'field_name') {
      // Set our file size to a variable.
      $fileSize = $element[0]['#file']->filesize->value;
      // Edit our title for the field display.
      $element[0]['#file']->filename->value = $element[0]['#file']->filename->value . ' ' . $fileSize;
    }
  }
}

Using HOOK_preprocess_file_link(&$variables):

/**
 * Add the "file-link.html.twig" template to your theme and adjust as needed.
 * 
 * Twig variables:
 * - {{ fileLinkDisplay.fileBundle }}
 * - {{ fileLinkDisplay.fileCreatedTime }}
 * - {{ fileLinkDisplay.fileChangedTime }}
 * - {{ fileLinkDisplay.fileFid }}
 * - {{ fileLinkDisplay.fileLangcode }}
 * - {{ fileLinkDisplay.fileMime }}
 * - {{ fileLinkDisplay.fileName }}
 * - {{ fileLinkDisplay.fileOwnerId }}
 * - {{ fileLinkDisplay.fileOwnerName }}
 * - {{ fileLinkDisplay.fileOwnerUserPictureUrl }}
 * - {{ fileLinkDisplay.fileSize }}
 * - {{ fileLinkDisplay.fileSizeFormatted }}
 * - {{ fileLinkDisplay.fileStatus }}
 * - {{ fileLinkDisplay.fileUrl }}
 * - {{ fileLinkDisplay.fileUuid }}
 */

function HOOK_preprocess_file_link(&$variables) {
  if (isset($variables['file'])) {
    $variables['fileLinkDisplay'] = [
      'fileBundle' => $variables['file']
        ->bundle(),
      'fileCreatedTime' => $variables['file']
        ->getCreatedTime(),
      'fileChangedTime' => $variables['file']
        ->getChangedTime(),
      'fileFid' => $variables['file']
        ->fid->value,
      'fileLangcode' => $variables['file']
        ->langcode->value,
      'fileMime' => $variables['file']
        ->getMimeType(),
      'fileName' => $variables['file']
        ->getFilename(),
      'fileOwnerId' => $variables['file']
        ->getOwnerId(),
      'fileOwnerName' => $variables['file']
        ->getOwner()->name->value,
      'fileOwnerUserPictureUrl' => file_create_url($variables['file']
        ->getOwner()->user_picture->entity->uri->value),
      'fileSize' => $variables['file']
        ->getSize(),
      'fileSizeFormatted' => format_size($variables['file']
        ->getSize()),
      'fileStatus' => $variables['file']
        ->status->value,
      'fileUrl' => file_create_url($variables['file']
        ->getFileUri()),
      'fileUuid' => $variables['file']
        ->uuid->value,
    ];
  }
}

See https://gitlab.com/prestosaurus/file-link-display/blob/master/file_link_display.module

Then your file-link.html.twig might look like:

{#
/**
 * @file
 * Theme override for a link to a file.
 *
 * @see template_preprocess_file_link()
 */
#}
{{ attach_library('classy/file') }}
<span{{ attributes }}>{{ icon }} {{ link }} {{ fileLinkDisplay.fileSize }} {{ fileLinkDisplay.fileMime }}</span>
7
  • 1
    In a preprocess function, you never use echo, not even for debugging purposes.
    – apaderno
    Feb 26, 2019 at 7:37
  • True, the echo I have is just so the user can see the result of $element['#title'] and that it is not quantified or altered in other processes. Do not leave this in your function. Feb 26, 2019 at 7:46
  • What would you hope to achieve with this code? Currently you're just altering some variables within a function, you're not changing anything that would be altered in the template
    – Clive
    Feb 26, 2019 at 8:37
  • I updated my answer a bit. The #title was just what I was working with. The first function will rewrite the label of the field and append the filesize value. Feb 26, 2019 at 15:44
  • Thank you for the detailed response. I'm not sure its all clicking in my head. Why "HOOK_preprocess_field" and not "HOOK_preprocess_file_link"? Feb 26, 2019 at 20:51
0

I a m not a big fun of twig_tweak because data need to be treated before the view or the twig step even when Drupal 8 is'nt an MVC Framework. And finally we will create templates using the rich Twig engine. I will do something like :

/**
 * Implements hook_preprocess_node.
 */
function mytheme_preprocess_node(&$variables) {
// Format downloadable files:
  if ($node->hasField('field_document')) {
    $items = $node->field_document->getValue();
    $variables['item_for_download'] = [];
    foreach ($items as $key => $item) {
      $media = Media::load($item['target_id']);
      $fid = $media->field_media_document[0]->getValue()['target_id'];
      $file = File::load($fid);
      $variables['item_for_download'][$key]['url'] = $file->url();
      // Size don't matter :p .
      $variables['item_for_download'][$key]['size'] =
      \Drupal::token()->replace("[file:size]", ['file' => $file]);
      $variables['item_for_download'][$key]['file_name'] = $file->getFilename();
      $variables['item_for_download'][$key]['file_mime_type'] = $file->getMimeType();
      // This custom field was added to the Media entity :
      $variables['item_for_download'][$key]['link_title'] = $media->get('field_download_link_text')->getString();
    }
  }

Next in my target node.html.twig I can call my array this way :

{% if item_for_download is not empty %}
        {% for item in item_for_download %}
          <div>
            <div> <a href="{{ item.url }}" class=""> {{ item.link_title }} ( {{ item.size }} ) </a></div>
          </div>
        {% endfor %}
      {% endif %}

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.