Làm cách nào để tôi tạo một liên kết từ một tệp mẫu?


10

Một mẫu twig đang hiển thị một danh sách các liên kết đi kèm với các lớp. Cơ bản:

{{ mylink }}

mã twig sẽ xuất ra một cái gì đó như

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

Không phải tất cả các liên kết có lớp. Tôi muốn viết một mẫu twig thay vào đó sẽ xuất ra một cái gì đó như thế này:

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

Những gì tôi đã thử:

  1. Tôi tìm mẫu twig để ghi đè. Thật không may, dường như các liên kết không được kết xuất bởi một mẫu twig.

  2. Tôi đã thử cập nhật biến twig như

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

    Nhưng nó sẽ không cho phép tôi làm điều đó.


Nó phải chỉ trong mẫu twig? Tôi có thể thay đổi đánh dấu và đặt các lớp từ UI (loại nội dung> quản lý biểu mẫu hiển thị).
Vagner

Câu trả lời:


6

Đây là một giải pháp chỉ dành cho một lĩnh vực cụ thể cần điều trị này; nó không phải là một giải pháp chung cho tất cả các liên kết ở khắp mọi nơi.

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 cuối cùng, tôi đã tìm kiếm 2 ngày cho một giải pháp cho vấn đề này. Tôi vẫn không thể hiểu làm thế nào twig đang xuất html khi chúng tôi chuyển nó item.link là một mảng. Bất cứ ai cũng có một tài liệu cho điều đó?
Guillaume Bois

Ôi trời ơi ... thật không may giải pháp này chỉ hoạt động một phần. Tôi muốn thay đổi các liên kết trình chuyển đổi ngôn ngữ và sử dụng item.link['#url']là cung cấp cùng một url cho tất cả các ngôn ngữ!
Guillaume Bois

@GuillaumeBois Bạn có thể kiểm tra drupal.stackexchange.com/a/199998/54619 để xem có giải quyết được vấn đề của 'trình chuyển đổi ngôn ngữ' không? Cảm ơn
Vagner

5

Tôi không tìm thấy cách thay đổi liên kết '#markup' trong twig, nhưng có cách để thay đổi liên kết trên giai đoạn kết xuất.
Tôi đã tạo ra mô-đun nhỏ này mở rộng chức năng Liên kết và làm cho nó có thể đưa một số nội dung vào liên kết được hiển thị. Vì vậy, hãy làm một số mã, tôi sẽ giải thích trong ý kiến ​​...

Cấu trúc tập tin mô-đun:

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

Nội dung tập tin:

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

Quan trọng:

Điều này sẽ làm việc cho tất cả các trường liên kết của bạn , chắc chắn, nếu bạn thay đổi định dạng của nó trong màn hình quản lý (chỉnh sửa loại nút của bạn).

Tôi hy vọng điều đó có thể hữu ích.

Yêu cầu @artfulrobot: Bạn có thể kiểm tra mô-đun này không? Tôi nghĩ rằng vấn đề dịch có thể được giải quyết theo cách này.


Vâng, cảm ơn bạn cho một câu trả lời dài và chi tiết. Tôi nghĩ rằng có một thất bại lớn trong lớp twig của d8 với các giải pháp lớn dựa trên php cho vấn đề chủ đề đơn giản. Nhưng cảm ơn vì đã đăng bài, v hữu ích.
artfulrobot

@artfulrobot Có lẽ bạn đang ở vị trí tốt hơn để trả lời câu hỏi này hơn tôi - bạn nghĩ câu trả lời nào ở đây là tiền thưởng?
Clive

@clive cảm ơn, nhưng tiền thưởng của bạn, cuộc gọi của bạn. Câu hỏi tôi hỏi là về Twig. Hầu hết các câu trả lời này liên quan đến việc thay thế hoặc mở rộng cốt lõi bằng rất nhiều PHP khó bảo trì hơn, vì vậy trong khi tôi biết ơn về đầu vào và họ cung cấp các cách để hoàn thành công việc, họ không trả lời câu hỏi IMO. Vấn đề theo chủ đề "đơn giản" này là rơm đã phá vỡ d8 con lạc đà của tôi, tôi sợ và cuối cùng tôi đã bỏ một dự án d8 3 tháng để bắt đầu lại từ đầu trong 7 - v đáng thất vọng nhưng trong 1 tuần tôi ' d bắt kịp hoàn toàn: - |
artfulrobot

Cảm ơn @artfulrobot, đã hiểu. Thật xấu hổ vì điều này đã không có một kết luận thỏa mãn hơn. Tôi sẽ để tiền thưởng tự động tự thưởng cho bất cứ điều gì cộng đồng đã bình chọn
Clive

cành là tuyệt vời. Tất cả các vấn đề xuất phát từ hệ thống theo chủ đề drupal, mà tôi nghĩ là một cách tiếp cận sai. Chỉ cần kiểm tra xem bạn phải làm thêm bao nhiêu công việc nếu bạn muốn tùy chỉnh một liên kết đơn giản. Điều này thật đáng thất vọng.
Zoltán Süle

4

bạn chỉ có thể thêm một mảng kết xuất vào #title, như:

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

Câu trả lời dài cũ:

Bạn có thể ghi đè dịch vụ tạo liên kết

Tạo một mô-đun (Altern_linkgenerator), với tệp thông tin thay thế_linkgenerator.info.yml

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

Tạo một tệp có tên thay thế_linkgenerator.service.yml

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

Tiếp theo là để tạo lớp, thêm một thư mục có tên là src src (theo tiêu chuẩn tự động tải PSR-4) và trong tệp này có tên là AlternativeLinkGenerator.php. (Đây là bản sao 1: 1, bạn cần điều chỉnh những thứ cho bạn)

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

}

Chỉnh sửa services.yml (thông thường tại các trang web / default / services.yml trong cơ sở mã Drupal 8 của bạn) và thêm vào như sau:

  services:
    link_generator:
      alias: alternative_linkgenerator.link_generator

đạo cụ đi đây


Cảm ơn, tôi sẽ cho nó đi. Tôi chỉ thực sự muốn nó làm điều đó trong các bối cảnh nhất định, mặc dù. Khó chịu khi phải làm một điều theo chủ đề thuần túy trong php sau thông báo twig lớn. Cảm ơn đề nghị của bạn.
artfulrobot

Chức năng đó dường như không được gọi. Tôi nghĩ đó là "liên kết với các yếu tố tiêu đề và URL riêng biệt". Không có template_preprocess_linksthứ gì được gọi (đó là một cái gì đó cụ thể, mặc dù nó là tên âm thanh chung).
artfulrobot

liên kết tiền xử lý mẫu dành cho danh sách liên kết theo như tôi thấy, bạn luôn có thể bật gỡ lỗi twig để xem chức năng mẫu / tiền xử lý nào được sử dụng cho đầu ra
rémy

Có, không ai trong số đó được sử dụng để định dạng liên kết. Trên thực tế core/lib/Drupal/Core/Utility/LinkGenerator.php, nó generate()được sử dụng và điều này buộc văn bản phải được chuyển qua Html::escape()nên không có cách nào để làm điều đó mà không hoàn toàn bỏ qua định dạng liên kết của Drupal.
artfulrobot

Bạn có thể ghi đè dịch vụ này như bất kỳ dịch vụ nào khác, xem tại đây tim.millwoodonline.co.uk/post/125163259445/ Lời
rémy

0

thử mã này:

{% 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 -%}

{% - endif%}

hoặc cái này (nó xuất phát từ: 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 %}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.