5

I'm using Drupal 8 and building a view. I have a field, which happens to be a title field, and I have set it to link to content. I would like to know how I can simply add a btn class to the anchor tag. Right now the output looks like this:

<a href="/node/{id}" hreflang="en">... custom text ...</a>

I know I can use the Rewrite Results view feature to accomplish this, however, I need more power than that because I am building a theme for a client. The theme needs to be more generic, so I need to be able to accomplish this in a template. Is there template suggestion/hook that would allow me to override this in a template such as .../templates/views-view-field--link.html.twig? Or is there a theme function that I could use to override the markup by adding the class I would like?

I've considered using the views-view-field.html.twig template and overriding the node_view type to accomplish this, but I'm not sure how to do that whilst keeping the custom text a user could be using because it's really hard to debug the field options.

Edit

I forgot to mention, this needs to rely on Drupal core. I can't expect the user to install any additional modules for it to work.

  • Something like this perhaps? drupal.org/project/field_formatter_class – Shane Birley Jan 13 '17 at 4:53
  • @ShaneBirley thanks for the suggestion. I should have mentioned in my question that I have rely on core and can't expect the client or user to install any additional modules, but thanks for your suggestions. Perhaps I can learn from how they've done it in their module. – Pzanno Jan 13 '17 at 14:47
  • @Pzanno You can add a wrapper span in views style settings If you can theme according to class of wrapper span of anchor tag. – Sumit Madan Jan 19 '17 at 10:46
5

Along with Wims suggestion, I would suggest (as I usually do) to bypass fields in views, and render the view mode of the entity in question. Usually, this is sufficient in most cases if this is a presentation based view, and not a 'report' style view (where records are in table format and fields serve as cell data).

Then, supply the twig template for view modes, where the title is linked, and you can add the class(es) there. Now when you use that view mode to render in Views, it uses one template and is consistent, and Views that rely on rendering entities become easier to maintain and quicker to setup.

Here is an article that explains the difference and the benefit: https://www.amazeelabs.com/en/blog/views-field-rewriting-to-views-modes

That said, no, links themselves do not have a twig file (where you would see the anchor tag markup). I have seen the |merge option before that Wim linked to, though I have been unsuccessful in getting that to work in 8.2.5.

You could also implement theme_preprocess_field and supply the class to the attributes before it is rendered, though as you can imagine, if you have a lot of these, it'll be some work.

  • Hey Kevin, not to hijack your answer, but maybe you want to beter explain what you mean by presentation based view? Just a wild guess what it might be: like a grid, or slideshow or something? FYI: report style view is clear enough ... – Pierre.Vriens Jan 17 '17 at 9:35
  • Thanks for the answer. I like the idea of using view modes and will be doing it as much as possible as it provides the most flexibility over presentation. However, in special cases it won't be very applicable. Such as when you have a view that uses a relationship with another content type or any other case that must use fields instead of view modes. – Pzanno Jan 24 '17 at 14:45
4
+50

Override just one field

There is a detailed answer in this Q: Overriding views-view-field.html.twig for specific fields.

You can simply use views-view-field--fieldname.html.twig. Use core/modules/views/templates/views-view-field.html.twig as the base template. It also contains information about which variables you can use:

view: The view that the field belongs to.
field: The field handler that can process the input.
row: The raw result of the database query that generated this field.
output: The processed output that will normally be used.

Override all links

Use field--node--field-link.html.twig which you can get from this source. It contains all the information about variables you can use.

Remember

Of course, don't forget to clear your cache after creating the new template or making changes to it.

  • 2
    I think the second part of your answer, use field--node--field-link.html.twig, is the best option. One thing, for this to work you have to check "Use field template" in STYLE SETTINGS of the field. - If you don't check this option, that means you use views field formatting, you would have to implement a custom views field plugin, because the built in one doesn't support link classes. – 4k4 Jan 18 '17 at 8:42
  • 1
    ... doesn't support link classes for linked entities, for other links it does! – 4k4 Jan 18 '17 at 8:55
  • 1
    As @4k4 said there are some limitations but checking the use field template option does allow the flexibility I'm wanting. I wish there was a similar solution for using the views field formatting templates. Looks like I'll have to use a combination of all answers to accomplish this seemingly easy task. – Pzanno Jan 24 '17 at 14:41
3

I need to be able to accomplish this in a template

This needs to rely on Drupal core. I can't expect the user to install any additional modules

Based on these constraints:

OPTION A

create views-view-field--field-name.html.twig

Inside put <div class="btn">{{ output -}}</div>

Then in your CSS file .btn a { .... };


But I really need to have the class inside the <a> tag... Ok then:

OPTION B

Inside mytheme.theme

use Drupal\Core\Url;
use Drupal\Core\Link;

function mytheme_preprocess_views_view_field(&$variables) {

  // check if it's the title field and also if "Link to the Content" (from the Views UI) is checked marked. 

  if ($variables['field']->options['field'] == 'title' && $variables['field']->options['settings']['link_to_entity'] == TRUE){

    // kint($variables['field']); <-- if you need to use kint

    $og_link = $variables['field']->original_value;

    // make this into XML so we can grab the href value

    $xml_link = new SimpleXMLElement($og_link);

    global $base_url;

    // problem is that $base_url contains the /drupal folder path (http://example.com/drupal) in url 
    // also the xml_link has it too (/drupal/node/5).
    // Since we only need of them to have it 
    // lets grab some parts of the $base_url by parsing it.

    $complete_url = parse_url($base_url);

    $complete_url = $complete_url['scheme'] . '://www.' . $complete_url['host'] . $xml_link['href'];

    // Now create a brand new link

    $url = Url::fromUri($complete_url);
    $link_options = array(
      'attributes' => array(
        'class' => array(
          'btn',
        ),
      ),
    );
    $url->setOptions($link_options);
    // $xml_link = the title between the <a>title</a> tags
    $link = Link::fromTextAndUrl(t((string)$xml_link), $url )->toString();

    // re-writes, sets the output to our link.
    $variables['output'] = $link;
  } 

}

Basically, we grab the url of the title and the title text. Then we create a brand new link (the Drupal way) using those values and add the class btn to our link and set the field output to our newly created link.

Result

enter image description here

  • Updated my answer with visual proof that it works. – No Sssweat Jan 24 '17 at 15:07
  • Thanks for the answer. I think the css solution works best for me in most cases. However, it's always best to apply the class on the element it was meant for so thanks for providing a way to actually do that. It's unfortunate that it takes that much custom code to do something so trivial. – Pzanno Jan 24 '17 at 17:12
  • 1
    I tried your .theme solution and I'm getting an error on the xml parse line. For reference the $og_link variable is of type Drupal\Core\Render\Markup. Also, fyi, my twig debug is on so theme suggestions are showing up in the markup -- probably causing the problem. Update, after turning of twig debug I got passed that error. – Pzanno Jan 24 '17 at 17:29
2

I've achieved the same result in this way, without doing anything with custom templates or code, only with rewriting of the result:

enter image description here

It is for a commerce product instead of node, but i think that it works with every entity. I think that for the most of cases it should be easiest and without the need for coding and new templates.

  • This is by far the best answer. Trying to do it with a template or preprocess function is an absolute mess compared to Francesco's answer. – arnoldbird Sep 25 at 14:00
  • I had to add a "Link to Content" field (excluded from display) before this field, allowing {{ view_node }} to be used as a replacement pattern for the href. – manafire Oct 21 at 19:47
  • So you had to add 2 times "Link to Content" ? one to use as replacement of the second? seems strange to me, the example above was on a product but i rewrited the "link to product" itself... tokens has always have been available on the field itself. Are you sure that the first added field was a "Link to content"? – Francesco Oct 23 at 8:00

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.