Je n'ai pas trouvé de moyen de changer le lien '#markup' dans twig, mais il y a moyen de le changer pendant la phase de rendu.
J'ai créé ce petit module qui étend les fonctionnalités de Link et permet d'injecter des trucs sur le lien rendu. Permet donc de faire du code, je vais vous expliquer dans les commentaires ...
Structure des fichiers du module:
better_link
| - src
| - Element
| BetterLink.php
| - Plugin
| - FieldFormatter
| BetterLinkFormatter.php
| better_link.info.yml
| better_link.module
Contenu du fichier:
better_link.info.yml
name: 'Better link'
type: module
package: 'Field types'
description: 'A very nice better link'
core: '8.x'
dependencies:
- field
- link
better_link.module
<?php
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
* Just some words about the module.
*/
function better_link_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.better_link':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Provide a improved link formatter and renderer for a custom link markup.') . '</p>';
$output .= '<p>' . t('Will be added a span html tag right before link content.') . '</p>';
$output .= '<p>' . t(' - Link class can be added throught manage display.') . '</p>';
$output .= '<p>' . t(' - Span class can be added throught manage display.') . '</p>';
return $output;
}
}
BetterLinkFormatter.php
<?php
/**
* @file
* Contains \Drupal\better_link\Plugin\Field\FieldFormatter\BetterLinkFormatter.
*/
namespace Drupal\better_link\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Form\FormStateInterface;
use Drupal\link\Plugin\Field\FieldFormatter\LinkFormatter;
/**
* Plugin implementation of the 'better_link' formatter.
*
* @FieldFormatter(
* id = "better_link",
* label = @Translation("Better Link"),
* field_types = {
* "link"
* }
* )
*/
class BetterLinkFormatter extends LinkFormatter {
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
$settings = parent::defaultSettings();
//Keeping simple...
$settings['span_class'] = '';
$settings['link_class'] = '';
//... but feel free to add, tag_name, buble_class, wraper_or_inside
return $settings;
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$form = parent::settingsForm($form, $form_state);
//Make sure that you always store a name that can be used as class
$settings['link_class'] = Html::cleanCssIdentifier(Unicode::strtolower($this->getSetting('link_class')));
$settings['span_class'] = Html::cleanCssIdentifier(Unicode::strtolower($this->getSetting('span_class')));
$this->setSettings($settings);
$form['link_class'] = array(
'#title' => $this->t('Inject this class to link'),
'#type' => 'textfield',
'#default_value' => $settings['link_class'],
);
$form['span_class'] = array(
'#title' => $this->t('Inject this class to span'),
'#type' => 'textfield',
'#default_value' => $settings['span_class'],
);
return $form;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = parent::settingsSummary();
//Same here. Somehow if you use setSettings here don't reflect in settingsForm
$settings['link_class'] = Html::cleanCssIdentifier(Unicode::strtolower($this->getSetting('link_class')));
$settings['span_class'] = Html::cleanCssIdentifier(Unicode::strtolower($this->getSetting('span_class')));
$this->setSettings($settings);
//Summary is located in the right side of your field (in manage display)
if (!empty($settings['link_class'])) {
$summary[] = t("Class '@class' will be used in link element.", array('@class' => $settings['link_class']));
}
else {
$summary[] = t('No class is defined for link element.');
}
if (!empty($settings['span_class'])) {
$summary[] = t("Class '@class' will be used in span element.", array('@class' => $settings['span_class']));
}
else {
$summary[] = t('No class is defined for span element.');
}
return $summary;
}
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$elements = parent::viewElements($items, $langcode);
//Yeah, here too, same 'problem'.
$settings['link_class'] = Html::cleanCssIdentifier(Unicode::strtolower($this->getSetting('link_class')));
$settings['span_class'] = Html::cleanCssIdentifier(Unicode::strtolower($this->getSetting('span_class')));
foreach ($items as $delta => $item) {
//Lets change the render element type and inject some options that will
//be used in render phase
if (isset($elements[$delta]['#type'])) {
$elements[$delta]['#type'] = 'better_link';
$elements[$delta]['#options']['#link_class'] = $settings['link_class'];
$elements[$delta]['#options']['#span_class'] = $settings['span_class'];
}
}
//Next step, render phase, see ya...
return $elements;
}
}
BetterLink.php
<?php
/**
* @file
* Contains \Drupal\better_link\Element\BetterLink.
*/
namespace Drupal\better_link\Element;
use Drupal\Core\Render\Element\Link;
/**
* Provides a better_link render element. Almost the same as link.
*
* @RenderElement("better_link")
*/
class BetterLink extends Link {
/**
* {@inheritdoc}
*/
public function getInfo() {
$class = get_class($this);
return array(
'#pre_render' => array(
array($class, 'preRenderLink'),
),
);
}
/**
* {@inheritdoc}
*/
public static function preRenderLink($element) {
//Hello again. Lets work.
//Before Drupal create the rendered link element lets inject our stuff...
//...Our class to link
$element['#options']['attributes']['class'][] = $element['#options']['#link_class'];
//...Build span classes
$span_classes = $element['#options']['#span_class'] . ' ' . $element['#options']['#link_class'];
//...And get rid them.
unset($element['#options']['#link_class']);
unset($element['#options']['#span_class']);
//Lets Drupal do the hard work
$element = parent::preRenderLink($element);
//Here is where the magic happens ;)
if (!empty($element['#markup'])) {
//Inject our span right before link content.
$element['#markup'] = str_replace('">', "\"><span class='$span_classes'></span>", $element['#markup']);
//Side comment - Thank you spaceless, str_replace can be used here
}
//Now, whatever you change in your url or another object will not maintain,
//the only thing that will be returned in the end is
//$element['#markup'], so this is the only thing you can change.
return $element;
}
}
Important:
Cela fonctionnera pour tous vos champs de lien , bien sûr, si vous changez son formateur dans la gestion de l'affichage (modification de votre type de nœud).
J'espère que cela peut être utile.
Demande à @artfulrobot: pouvez-vous tester ce module? Je pense que ce problème de traduction peut être résolu de cette façon.