1

I have a block and I’m trying to wrap a link around it:

{% block paragraph %}
  <div{{ attributes.addClass(classes) }}>
    {% block content %}
        <a href="{{ content.field_link.0['#url'] }}">
          {{ content }}
        </a>
    {% endblock %}
  </div>
{% endblock paragraph %}

But when the code is output, the link is above the block instead of around it, and it gets input into multiple other places inside the content. You can see everywhere there’s a /node/2, but nowhere is it doing anything useful (except for wrapping around the “Office” image, which comes from the {{ content }} and not from the wrapped link).

<div data-quickedit-entity-id="paragraph/5594" class="paragraph paragraph--transporter-item paragraph--view-mode-default" data-quickedit-entity-instance-id="0">
  <a href="/node/2">
    <!-- THEME HOOK: 'field' -->
    <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' -->
  </a>

  <div class="paragraph--transporter-item__icon field field--name-field-icon field--type-entity-reference field--label-hidden field__items" data-quickedit-field-id="paragraph/5594/field_icon/en/default">
    <a href="/node/2">
      <!-- THEME HOOK: 'media' -->
      <!-- BEGIN OUTPUT from 'core/modules/media/templates/media.html.twig' -->
    </a>

    <div data-quickedit-entity-id="media/9" class="contextual-region" data-quickedit-entity-instance-id="0">
      <a href="/node/2">
        <div data-contextual-id="media:media=9:changed=1561152189&amp;langcode=en" data-contextual-token="8VIDU3VuOojWGK9hX_jn8ERolu-tvAZdOewrYfTFUwA" class="contextual" role="form">
          <button class="trigger visually-hidden focusable" type="button" aria-pressed="false">Open  configuration options</button>
          <!-- THEME HOOK: 'links__contextual' -->
          <!-- BEGIN OUTPUT from 'core/modules/system/templates/links.html.twig' -->
          <ul class="contextual-links" hidden=""><li class="quickedit"><a href="" role="button" aria-pressed="false">Quick edit</a></li><li><a href="/media/9/edit?destination=/node/2">Edit</a></li><li><a href="/media/9/delete?destination=/node/2">Delete</a></li></ul>
          <!-- END OUTPUT from 'core/modules/system/templates/links.html.twig' -->
        </div>

        <!-- THEME HOOK: 'field' -->
        <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' -->
      </a>
      <div data-quickedit-field-id="media/9/field_media_image/en/default" class="field field--name-field-media-image field--type-image field--label-visually_hidden field__items quickedit-field">
        <a href="/node/2">
          <div class="field__label visually-hidden">Image</div>
        </a>
        <div class="field__item">
          <a href="/node/2">
            <!-- THEME HOOK: 'image_formatter' -->
            <!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
          </a>
          <a href="http://arboreal.lndo.site/sites/default/files/2019-06/0010-office.svg">
            <!-- THEME HOOK: 'image' -->
            <!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
            <img src="/sites/default/files/2019-06/0010-office.svg" alt="Office" typeof="foaf:Image" width="" height="">
            <!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
          </a>
          <!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
        </div>
      </div>
      <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' -->
    </div>
    <!-- END OUTPUT from 'core/modules/media/templates/media.html.twig' -->
  </div>
  <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' -->

  <!-- THEME HOOK: 'field' -->
  <!-- BEGIN OUTPUT from 'modules/contrib/fences/field.html.twig' -->
  <div class=".paragraph--transporter-item__label field field--name-field-link field--type-link field--label-hidden field__items" data-quickedit-field-id="paragraph/5594/field_link/en/default">
    <a href="/node/2">Office</a>
  </div>
  <!-- END OUTPUT from 'modules/contrib/fences/field.html.twig' -->
</div>

Why is this happening, and how do I get it so it just outputs the link in the one place and around the whole block?

  • Seems a bit there's a missing <a> or </a> somewhere else on your page. What template exactly are you editing there? – leymannx Jun 27 at 18:13
  • 2
    This is happening because you are nesting links, and this is not allowed in HTML. The client browser will close your wrapping link as soon as it hits an inner, nested link from inside your block. – Hudri Jun 27 at 19:21
  • 1
    Also this is hard to debug when quickedit is enabled. The code and debug output should match so that one reading the question can see how they are connected. – 4k4 Jun 28 at 6:27
  • @Hudri, you were right. Dev Tools automatically closed links, whereas View Source showed only the one wrapping link (and the link around the label). – Ragdoll Jul 9 at 17:53
0

This is not the answer you are looking for...

I would recommend not wrapping your block in a link. This is bad SEO and difficult for screen readers and other assistive technologies to decipher.

Instead, place the link at the end of your block and use CSS to absolute position it to cover your entire block.

Markup:

<div class="my-block>
  <h2>Title</h2>
  <p>Some content</p>
  <a class="my-block-link" title="My helpful title for screen readers"></a>
</div>

Styles:

.my-block {
  position: relative;

  a.my-block-link {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
}

It is important to achieve accessibility as much as possible.

  • Thanks. Good things to think about. I haven’t had accessibility issues when doing this in ordinary HTML, and it’s valid according the the spec. This solution may require me to rebuild hover mechanics in JavaScript, which is also not ideal. I would still like to wrap the block with a link, but I’ll be sure to test accessibility and weigh the pros and cons. – Ragdoll Jun 27 at 17:33
  • This was the answer I was looking for. I solved the hover mechanics with CSS by contextualizing it on the parent element: .my-block:hover img { transform: …; transition: …;}. Thank you! – Ragdoll Jul 9 at 17:47
3

I would recommend a 2 step approach to this.

  1. Add a link at the bottom of your block that links to the node like so:
<a class="my-block-link" href="node/1" title="My helpful title for screen readers">Full node</a>
  1. Use a jQuery snippet to link the whole block
$(document).on('click', '.contextual-region', function(e) {
  console.log('block clicked');
  window.location = $(this).find('.my-block-link').attr('href');
});
  1. UX Bonus points - Add this css for your linked block:
.contextual-region { cursor: pointer; }

EDIT:

I'll add a non JS way to make everyone happy:

{% block paragraph %}
  <div{{ attributes.addClass(classes) }}>
    {% block content %}
        <a href="{{ content.field_link.0['#url'] }}">
          <div class="content-container-needed">
          {{ content }}
          </div>
        </a>
    {% endblock %}
  </div>
{% endblock paragraph %}

  • Disagree about javascript. – Kevin Jun 27 at 23:06
  • I believe unless he wants to add another container inside its the only way with his markup structure. – Mazzy Jun 27 at 23:11
  • If you use a js on click function you may also want to implement contextmenu. – Prestosaurus Jun 28 at 5:35
  • 1
    @Kevin – Imagine having a card consisting of an image, a title and a teaser text. Then only the descriptive title should be linkwrapped for SEO. But the whole card should be clickable for UX. Than the technique from this very answer is the way to go. – leymannx Jun 28 at 6:40
  • @leymannx Indeed, the accepted answer with no anchor text is terrible for SEO – Mazzy Jul 15 at 21:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.