5

My question is for D8...

I have a field which is rendered as a link. Let say for simplicity that it will be rendered like this: <a href="url">My Title</a>

I would like to add a bootstrap icon inside the link to get a result like this: <a href="url"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>My Title</a>

I know that I can take the url and the title from within the preprocess function to reconstruct a new link (#markup)... But is it possible to simply add the icon code somewhere in the array to get the same result?

I am adding some more information to clarify:

1-The field which is rendered as a link is a term reference field rendered as a linked label

2-Here is my try in the preprocess_field function to achieve this

function mymodule_preprocess_field(&$vars) {
  $fn = $vars['element']['#field_name'];
  switch ($fn) {
    case 'my_field':
      foreach ($vars['items'] as $key => $item) {
        $icon = '<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>';
        $vars['items'][0]['content']['#title']=$icon.$item['content']['#title'];
      }
      break;
  }
}

3 Answers 3

7
+50

Use the FormattableMarkup class for this:

$markup = new FormattableMarkup('<a href="@url"><span class="glyphicon glyphicon-info-sign" aria-hidden="true /></a>', [
          '@url' => $url->toString(), // If $url is an Drupal\Core\Url object.
        ]);

$renderArray['your_element'] = $markup;

After edit:

Use the Markup class for this since your seem to be in control over your markup. If not use FormattableMarkup with placeholders for safety:

  function mymodule_preprocess_field(&$vars) {
    $fn = $vars['element']['#field_name'];
    switch ($fn) {
      case 'my_field':
        foreach ($vars['items'] as $key => $item) {
          $icon = '<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>';
          $uri = $item['content']['#title'];

          $formattedIcon = \Drupal\Core\Render\Markup::create($icon . $uri);

          $vars['items'][0]['content']['#title'] = $formattedIcon;
        }
        break;
    }
  }

From the FormattableMarkup docs:

When cast to a string, this object replaces variable placeholders in the string with the arguments passed in during construction and escapes the values so they can be safely displayed as HTML. See the documentation of \Drupal\Component\Render\FormattableMarkup::placeholderFormat() for details on the supported placeholders and how to use them securely. Incorrect use of this class can result in security vulnerabilities.

4
  • this is not really an answer to the question, as he does not want to add a new render element. but this is combinable with my answer!
    – rémy
    Commented Jun 26, 2017 at 11:23
  • It is an answer to the question. The variable $renderArray is just an example and could be replaced by any other variable or it could be directly assigned to the current render array.
    – mvdgun
    Commented Jun 26, 2017 at 11:33
  • Many thanks for your answer, could you tell me where I have to "insert" $markup in my render array (see my updated question)
    – Baud
    Commented Jun 26, 2017 at 12:15
  • I guess in your foreach() loop: $vars['items'][0]['content']['#title'] = $markup.
    – mvdgun
    Commented Jun 26, 2017 at 12:16
2

For the link field you can insert a markup-array in the title var, like this:

$icon = '<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>';
$variables['link_field_name']['title'] = [
  '#markup' => $icon . $variables['link_field_name']['title'],
];

Edit: For the term reference title use:

$vars['items'][0]['content']['#title'] = [
  '#markup' => $icon . $vars['items'][0]['content']['#title'],
];

Or like suggested from @Gun5m0k3 the new drupal 8 classy way:

$vars['items'][0]['content']['#title'] = \Drupal\Core\Render\Markup::create($icon . $vars['items'][0]['content']['#title']);
3
  • Your second code part is incorrect: the second argument of the FormattableMarkup class is missing. Currently your code would emit a TypeError. If no placeholders have to be used and your inputted HTML is considered safe (no user input) you can also use the Markup class.
    – mvdgun
    Commented Jun 26, 2017 at 11:38
  • Many thanks for your answer, I have edited my question because I don't have $variables['link_field_name']['title'] in my render array
    – Baud
    Commented Jun 26, 2017 at 12:13
  • @Gun5m0k3, true .. i was to quick ;)
    – rémy
    Commented Jun 26, 2017 at 12:37
2

One way to handle this is to create an inline_template render item:

  function mymodule_preprocess_field(&$vars) {
    $fn = $vars['element']['#field_name'];
    switch ($fn) {
      case 'my_field':
        foreach ($vars['items'] as $key => $item) {
          $vars['items'][0]['content']['#title'] = [
            '#type' => 'inline_template',
            '#template' => '{{ icon }} {{ title }}',
            '#context' => [
              'icon' => '<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>',
              'title' => $item['content']['#title'],
              ],
          ];
        }
        break;
    }
  }

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.