Bagaimana cara saya tema tautan dari file template?


10

Template ranting sedang membuat daftar tautan yang datang dengan kelas. Dasar:

{{ mylink }}

kode ranting akan menampilkan sesuatu seperti

<a href="#" class="someclass" >the text</a>

Tidak semua tautan memiliki kelas. Saya ingin menulis template ranting yang akan menampilkan sesuatu seperti ini:

<a href="#" class="someclass" >
  <span class="sprite someclass" ></span>
  the text</a>

Apa yang saya coba:

  1. Saya mencari template ranting untuk menimpanya. Sayangnya tampaknya tautan tidak dirender oleh templat ranting.

  2. Saya mencoba memperbarui variabel ranting seperti

    set mylink['#title'] = "<span>...</span>" ~ mylink['#title']

    Tapi itu tidak akan membiarkan saya melakukan itu.


Itu harus hanya di templat ranting? Saya dapat mengubah markup dan mengatur kelas dari UI (tipe konten> kelola formulir tampilan).
Vagner

Jawaban:


6

Berikut adalah solusi hanya ranting untuk bidang tertentu yang membutuhkan perawatan ini; itu bukan solusi umum untuk semua tautan di mana pun.

some-template.twig:

<ul class="field--name-field-links">
  {% for item in content.field_links %}
  {% if item['#title'] %}
    <li>
      <a href="{{ item['#url'] }}" class="{{ item['#options'].attributes.class|join(' ') }}" >
        {% if item['#options']['attributes']['class'] %}
          <span class="sprite {{ item['#options']['attributes']['class']|join(" ") }}"></span>
        {% endif %}
        {{ item['#title'] }}
      </a>
    </li>
  {% endif %}
  {% endfor %}
</ul>

1
OMG akhirnya, saya sudah mencari 2 hari untuk solusi untuk masalah ini. Saya masih tidak mengerti bagaimana ranting menghasilkan html ketika kami mengirimkannya item.link yang merupakan array. Adakah yang punya dokumen untuk itu?
Guillaume Bois

Ya Tuhan ... Sayangnya solusi ini hanya berfungsi sebagian. Saya ingin mengubah tautan pengalih bahasa dan menggunakan item.link['#url']memberi url yang sama untuk semua bahasa!
Guillaume Bois

@GuillaumeBois Bisakah Anda menguji drupal.stackexchange.com/a/199998/54619 untuk melihat apakah memecahkan masalah 'pengalih bahasa'? Terima kasih
Vagner

5

Saya tidak menemukan cara untuk mengubah tautan '#markup' di ranting, tetapi ada cara untuk mengubahnya pada fase render.
Saya membuat modul kecil ini yang memperluas fungsionalitas Tautan dan membuatnya dapat menyuntikkan beberapa hal pada tautan yang diberikan. Jadi mari kita lakukan beberapa kode, saya akan jelaskan di komentar ...

Struktur file modul:

better_link
 | - src
   | - Element
     | BetterLink.php
   | - Plugin
     | - FieldFormatter
       | BetterLinkFormatter.php
 | better_link.info.yml
 | better_link.module

Isi file:

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;
  }
}

Penting:

Ini akan berfungsi untuk semua bidang tautan Anda , tentu saja, jika Anda mengubah formatter-nya di kelola tampilan (mengedit tipe simpul Anda).

Semoga bermanfaat.

Permintaan ke @artfulrobot: Bisakah Anda menguji modul ini? Saya pikir masalah terjemahan bisa diselesaikan dengan cara ini.


Ya, terima kasih atas jawaban yang panjang dan terinci. Saya pikir ada kegagalan besar dalam ranting d8 dengan solusi berbasis php yang sangat besar untuk apa yang seharusnya menjadi masalah bertema sederhana. Tapi terima kasih sudah memposting, v bermanfaat.
artfulrobot

@artfulrobot Anda mungkin berada dalam posisi yang lebih baik untuk menjawab hal ini daripada saya - menurut Anda, manakah jawaban yang harus Anda berikan?
Clive

@berterima kasih, tapi karunia Anda, panggilan Anda. Pertanyaan saya adalah tentang Ranting. Sebagian besar jawaban ini melibatkan penggantian atau perluasan inti dengan banyak PHP yang sulit dikelola, jadi sementara saya berterima kasih atas masukannya dan mereka menyediakan cara untuk menyelesaikan pekerjaan, mereka tidak menjawab pertanyaan IMO. Masalah bertema "sederhana" ini telah menjadi masalah yang mematahkan punggung d8 pepatah unta saya, saya khawatir dan saya akhirnya membuang proyek d8 3 bulan untuk memulai dari awal di 7 - v mengecewakan tetapi dalam 1 minggu saya ' d berhasil sepenuhnya: - |
artfulrobot

Terima kasih @artfulrobot, mengerti. Sayang sekali ini tidak memiliki kesimpulan yang lebih memuaskan. Saya akan membiarkan pemberian hadiah otomatis itu sendiri atas apa pun yang telah dipilih oleh komunitas
Clive

ranting luar biasa. Semua masalah berasal dari sistem theming drupal, yang saya pikir merupakan pendekatan yang salah. Cukup periksa berapa banyak pekerjaan tambahan yang harus Anda lakukan jika Anda ingin menyesuaikan tautan sederhana. Ini mengecewakan.
Zoltán Süle

4

Anda bisa menambahkan array render ke #title, seperti:

['#title'] = array('#markup' => '<i class="my-icons">yummy</i>' . $item['content']['#title']);

Jawaban lama:

Anda dapat mengganti layanan penghubung tautan

Buat modul (alternative_linkgenerator), dengan file info alternative_linkgenerator.info.yml

name: Alternative LinkGenerator
type: module
description: Adds alternative link generation.
core: 8.x

Buat file bernama alternative_linkgenerator.services.yml

services:
  alternative_linkgenerator.link_generator:
    class: Drupal\alternative_linkgenerator\AlternativeLinkGenerator

Berikutnya adalah membuat kelas, tambahkan folder bernama "src" (mengikuti standar autoloading PSR-4) dan dalam file ini disebut AlternativeLinkGenerator.php. (Ini adalah salinan 1: 1, Anda perlu menyesuaikan hal-hal untuk Anda)

class AlternativeLinkGenerator extends LinkGeneratorInterface {

  /**
   * The url generator.
   *
   * @var \Drupal\Core\Routing\UrlGeneratorInterface
   */
  protected $urlGenerator;

  /**
   * The module handler firing the route_link alter hook.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * The renderer service.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * Constructs a LinkGenerator instance.
   *
   * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
   *   The url generator.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer service.
   */
  public function __construct(UrlGeneratorInterface $url_generator, ModuleHandlerInterface $module_handler, RendererInterface $renderer) {
    $this->urlGenerator = $url_generator;
    $this->moduleHandler = $module_handler;
    $this->renderer = $renderer;
  }

  /**
   * {@inheritdoc}
   */
  public function generateFromLink(Link $link) {
    return $this->generate($link->getText(), $link->getUrl());
  }

  /**
   * {@inheritdoc}
   *
   * For anonymous users, the "active" class will be calculated on the server,
   * because most sites serve each anonymous user the same cached page anyway.
   * For authenticated users, the "active" class will be calculated on the
   * client (through JavaScript), only data- attributes are added to links to
   * prevent breaking the render cache. The JavaScript is added in
   * system_page_attachments().
   *
   * @see system_page_attachments()
   */
  public function generate($text, Url $url) {
    // Performance: avoid Url::toString() needing to retrieve the URL generator
    // service from the container.
    $url->setUrlGenerator($this->urlGenerator);

    if (is_array($text)) {
      $text = $this->renderer->render($text);
    }

    // Start building a structured representation of our link to be altered later.
    $variables = array(
      'text' => $text,
      'url' => $url,
      'options' => $url->getOptions(),
    );

    // Merge in default options.
    $variables['options'] += array(
      'attributes' => array(),
      'query' => array(),
      'language' => NULL,
      'set_active_class' => FALSE,
      'absolute' => FALSE,
    );

    // Add a hreflang attribute if we know the language of this link's url and
    // hreflang has not already been set.
    if (!empty($variables['options']['language']) && !isset($variables['options']['attributes']['hreflang'])) {
      $variables['options']['attributes']['hreflang'] = $variables['options']['language']->getId();
    }

    // Ensure that query values are strings.
    array_walk($variables['options']['query'], function(&$value) {
      if ($value instanceof MarkupInterface) {
        $value = (string) $value;
      }
    });

    // Set the "active" class if the 'set_active_class' option is not empty.
    if (!empty($variables['options']['set_active_class']) && !$url->isExternal()) {
      // Add a "data-drupal-link-query" attribute to let the
      // drupal.active-link library know the query in a standardized manner.
      if (!empty($variables['options']['query'])) {
        $query = $variables['options']['query'];
        ksort($query);
        $variables['options']['attributes']['data-drupal-link-query'] = Json::encode($query);
      }

      // Add a "data-drupal-link-system-path" attribute to let the
      // drupal.active-link library know the path in a standardized manner.
      if ($url->isRouted() && !isset($variables['options']['attributes']['data-drupal-link-system-path'])) {
        // @todo System path is deprecated - use the route name and parameters.
        $system_path = $url->getInternalPath();
        // Special case for the front page.
        $variables['options']['attributes']['data-drupal-link-system-path'] = $system_path == '' ? '<front>' : $system_path;
      }
    }

    // Remove all HTML and PHP tags from a tooltip, calling expensive strip_tags()
    // only when a quick strpos() gives suspicion tags are present.
    if (isset($variables['options']['attributes']['title']) && strpos($variables['options']['attributes']['title'], '<') !== FALSE) {
      $variables['options']['attributes']['title'] = strip_tags($variables['options']['attributes']['title']);
    }

    // Allow other modules to modify the structure of the link.
    $this->moduleHandler->alter('link', $variables);

    // Move attributes out of options since generateFromRoute() doesn't need
    // them. Include a placeholder for the href.
    $attributes = array('href' => '') + $variables['options']['attributes'];
    unset($variables['options']['attributes']);
    $url->setOptions($variables['options']);

    // External URLs can not have cacheable metadata.
    if ($url->isExternal()) {
      $generated_link = new GeneratedLink();
      $attributes['href'] = $url->toString(FALSE);
    }
    else {
      $generated_url = $url->toString(TRUE);
      $generated_link = GeneratedLink::createFromObject($generated_url);
      // The result of the URL generator is a plain-text URL to use as the href
      // attribute, and it is escaped by \Drupal\Core\Template\Attribute.
      $attributes['href'] = $generated_url->getGeneratedUrl();
    }

    if (!SafeMarkup::isSafe($variables['text'])) {
      $variables['text'] = Html::escape($variables['text']);
    }
    $attributes = new Attribute($attributes);
    // This is safe because Attribute does escaping and $variables['text'] is
    // either rendered or escaped.
    return $generated_link->setGeneratedLink('<a' . $attributes . '>' . $variables['text'] . '</a>');
  }

}

Edit services.yml (biasanya di situs / default / services.yml di basis kode 8 Drupal Anda) dan tambahkan yang berikut ini:

  services:
    link_generator:
      alias: alternative_linkgenerator.link_generator

alat peraga ada di sini


Terima kasih, saya akan mencobanya. Saya hanya benar-benar ingin melakukannya dalam konteks tertentu. Mengganggu harus melakukan hal bertema murni di php setelah pengumuman ranting besar. Terima kasih atas saran Anda.
artfulrobot

Fungsi itu sepertinya tidak disebut. Saya pikir itu untuk "tautan dengan elemen judul dan URL yang terpisah". Tidak juga template_preprocess_linksdipanggil (itu sesuatu yang spesifik, meskipun itu nama generik yang terdengar).
artfulrobot

tautan praproses templat adalah untuk daftar tautan sejauh yang saya lihat, Anda selalu dapat mengaktifkan ranting debug untuk melihat fungsi templat / praproses yang digunakan untuk output
rémy

Ya, keduanya tidak digunakan untuk memformat tautan. Sebenarnya core/lib/Drupal/Core/Utility/LinkGenerator.php's generate()digunakan dan pasukan ini teks yang akan melewati Html::escape()sehingga tidak ada cara untuk melakukannya tanpa benar-benar melewati link di formatter Drupal.
artfulrobot

Anda dapat mengganti layanan ini seperti yang lainnya, lihat di sini tim.millwoodonline.co.uk/post/125163259445/…
rémy

0

coba kode ini:

{% if links -%}
  {%- if heading -%}
    {%- if heading.level -%}
  <{{ heading.level }}{{ heading.attributes }}>{{ heading.text }}</{{ heading.level }}>
{%- else -%}
  <h2{{ heading.attributes }}>{{ heading.text }}</h2>
   {%- endif -%}
  {%- endif -%}
  <ul{{ attributes }}>
{%- for item in links -%}
  <li{{ item.attributes }}>
        {%- if item.link -%}

    <!--{{ item.link }} this line must stay -->

    <a href="{{ item.link['#url'] }}"
      {{ item.attributes.addClass(classes) }}
      {{ item.attributes.setAttribute('title', item.text ) }}
      {{ item.attributes.setAttribute('lang', item.link['#options'].language.id ) }}
      {{ item.attributes.setAttribute('aria-label', item.text ) }}>
        <img alt="{{ item.link['#title'] }}" src="/themes/subtheme/img/flag_{{ item.link['#options'].language.id }}.jpg" class="align-center">
    </a>


    {%- elseif item.text_attributes -%}
      <span{{ item.text_attributes }}>{{ item.text }}</span>
    {%- else -%}
      {{ item.text }}
    {%- endif -%}
  </li>
{%- endfor -%}

{%- berakhir jika %}

atau yang ini (ini berasal dari: https://github.com/liip/bund_drupal_starterkit_theme/blob/master/templates/navigation/links--language-block.html.twig ):

{% if links and links|length > 1 -%}
  <ul>
    {%- for item in links -%}
      <li>
        {%- if item.link -%}

      <!--{{ item.link }} to do: remove this line without breaking the urls -->

      {% if item.link['#options'].language.id == current_language %}
        {% set classes = ['active'] %}
      {% else %}
        {% set classes = [''] %}
      {% endif %}
      {% set url = path(item.link['#url'].routeName, item.link['#url'].routeParameters, item.link['#url'].options) %}

    {%- else -%}
      {% set classes = ['disabled'] %}
      {% set url = '#' %}
    {%- endif -%}

    <a href="{{ url }}"
      {{ item.attributes.addClass(classes) }}
      {{ item.attributes.setAttribute('title', item.text ) }}
      {{ item.attributes.setAttribute('lang', item.link['#options'].language.id ) }}
      {{ item.attributes.setAttribute('aria-label', item.text ) }}>
        {{ item.link['#options'].language.id | upper }}
    </a>
  </li>
{%- endfor -%}
  </ul>
{%- endif %}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.