템플릿 파일의 링크를 테마로 만들려면 어떻게합니까?


10

나뭇 가지 템플릿은 클래스와 함께 제공되는 링크 목록을 렌더링합니다. 기본 :

{{ mylink }}

나뭇 가지 코드는 다음과 같이 출력됩니다

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

모든 링크에 클래스가있는 것은 아닙니다. 대신 다음과 같이 출력하는 나뭇 가지 템플릿을 작성하고 싶습니다.

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

내가 시도한 것 :

  1. 나뭇 가지 템플릿을 재정의하려고했습니다. 불행히도 링크는 나뭇 가지 템플릿으로 렌더링되지 않는 것 같습니다.

  2. 나는 나뭇 가지 변수를 다음과 같이 업데이트하려고 시도했다.

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

    그러나 그렇게 할 수는 없습니다.


작은 템플릿에만 있어야합니까? UI에서 마크 업을 변경하고 클래스를 설정할 수 있습니다 (콘텐츠 유형> 표시 양식 관리).
Vagner

답변:


6

이 치료가 필요한 특정 분야에 대한 작은 가지 해결책이 있습니다. 모든 링크에 대한 일반적인 솔루션은 아닙니다.

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 마침내, 나는이 문제에 대한 해결책을 찾기 위해 2 일을 찾고있었습니다. 우리가 배열 인 item.link를 전달할 때 twig가 html을 출력하는 방법을 여전히 이해할 수 없습니다. 누구든지 그 문서를 가지고 있습니까?
기 illa 부아

어머나 ... 불행히도이 솔루션은 부분적으로 만 작동합니다. 언어 스위처 링크를 변경하고 사용하고 item.link['#url']있으며 모든 언어에 대해 동일한 URL을 제공하고 있습니다!
기 illa 부아

@GuillaumeBois 캔 당신은 테스트 drupal.stackexchange.com/a/199998/54619 의 언어 스위처 '의 문제를 해결할 수 있는지? 감사합니다
Vagner

5

나뭇 가지에서 링크 '#markup'을 변경하는 방법을 찾지 못했지만 렌더링 단계에서 변경하는 방법이 있습니다.
링크 기능을 확장하고 렌더링 된 링크에 물건을 넣을 수있는이 작은 모듈을 만들었습니다. 그래서 코드를 작성해 보겠습니다.

모듈 파일 구조 :

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

파일 내용 :

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

중대한:

이것은 관리 링크 에서 포맷터를 변경하면 (노드 유형 편집) 모든 링크 필드 에서 작동합니다 .

도움이 되길 바랍니다.

@artfulrobot에 요청 :이 모듈을 테스트 할 수 있습니까? 이런 식으로 번역 문제를 해결할 수 있다고 생각합니다.


네, 길고 자세한 답변을 주셔서 감사합니다. d8의 작은 레이어에는 간단한 테마 문제가 무엇인지에 대한 PHP 기반의 솔루션으로 막대한 실패가 있다고 생각합니다. 그러나 게시 해 주셔서 감사합니다. v 도움이되었습니다.
artfulrobot

@artfulrobot 당신은 아마 나보다 이것에 대답하기에 더 좋은 위치에있을 것입니다-여기에있는 답변 중 어떤 것이 현상금에 가야한다고 생각합니까?
Clive

@ 클라이브 감사하지만 현상금, 전화. 내가 물었던 질문은 나뭇 가지에 관한 것이었다. 이러한 답변의 대부분은 코어를 유지 보수하기 어려운 많은 PHP로 교체하거나 확장하는 것과 관련이 있으므로 입력에 감사하고 작업을 수행하는 방법을 제공하지만 IMO 질문에는 대답하지 않습니다. 이 "단순한"테마 문제는 속담 한 낙타의 d8을 돌파 한 빨대 였고, 두렵고 7 개월 만에 d8 프로젝트를 3 개월 만에 끝내기 시작했습니다. v 실망 스럽지만 1 주일 만에 d 완전히 붙 잡았다 :-|
artfulrobot

@artfulrobot에게 감사드립니다. 이것이 더 만족스러운 결론을 얻지 못한 것은 부끄러운 일입니다. 커뮤니티가 투표 한 모든 것에 대해 바운티가 자동으로 상을 받도록하겠습니다
Clive

나뭇 가지가 놀랍습니다. 모든 문제는 드루팔 테마 시스템에서 비롯된 것으로, 잘못된 접근법이라고 생각합니다. 간단한 링크를 사용자 정의하려면 추가 작업이 얼마나 필요한지 확인하십시오. 실망입니다.
Zoltán Süle

4

#title에 다음과 같이 렌더 배열을 추가 할 수 있습니다.

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

오래된 대답 :

링크 생성기 서비스를 재정의 할 수 있습니다

정보 파일 alternative_linkgenerator.info.yml을 사용하여 모듈 (alternative_linkgenerator)을 작성하십시오.

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

alternative_linkgenerator.services.yml이라는 파일을 만듭니다

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

다음으로 클래스를 생성하고“src”(PSR-4 자동로드 표준에 따름)라는 폴더를 추가하고이 안에 AlternativeLinkGenerator.php라는 파일을 추가하십시오. (이것은 1 : 1 사본입니다.

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

}

services.yml (일반적으로 Drupal 8 코드베이스의 sites / default / services.yml에 있음)을 편집하고 다음을 추가하십시오.

  services:
    link_generator:
      alias: alternative_linkgenerator.link_generator

소품은 여기에 간다


고마워, 내가 갈게 그래도 특정 상황에서만 그렇게하고 싶습니다. 그랜드 브랜치 발표 후 PHP에서 순수한 테마 작업을 해야하는 성가신. 제안 해 주셔서 감사합니다.
artfulrobot

그 함수는 호출되지 않은 것 같습니다. "별도의 제목 및 URL 요소가있는 링크"에 대한 것입니다. 어느 쪽도 아니하지 않습니다 template_preprocess_links것은 호출되는 (즉의 뭔가 특정, 그것은 일반적인 소리가 나는 이름도 불구하고).
artfulrobot

템플릿 전처리 링크는 내가 아는 한 링크 목록 용입니다. 출력에 사용 된 템플릿 / 전처리 기능을 확인하기 위해 항상 나뭇 가지 디버그를 활성화 할 수 있습니다.
rémy

예, 둘 다 링크 형식을 지정하는 데 사용되지 않습니다. 사실 core/lib/Drupal/Core/Utility/LinkGenerator.php'들 generate()사용하고, 텍스트를 통해 전달되는이 힘은 Html::escape()그렇게 완전히 드루팔의 링크 포매터를 우회하지 않고 그것을 할 방법이 없습니다.
artfulrobot

이 서비스는 다른 서비스처럼 무시할 수 있습니다. tim.millwoodonline.co.uk/post/125163259445/…
rémy

0

이 코드를 사용해보십시오 :

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

또는 이것 중 하나 ( 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 %}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.