6

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.

3
  • Something like this perhaps? drupal.org/project/field_formatter_class Commented Jan 13, 2017 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
    Commented Jan 13, 2017 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. Commented Jan 19, 2017 at 10:46

4 Answers 4

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.

2
  • 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 ... Commented Jan 17, 2017 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
    Commented Jan 24, 2017 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.

3
  • 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.
    – 4uk4
    Commented Jan 18, 2017 at 8:42
  • 1
    ... doesn't support link classes for linked entities, for other links it does!
    – 4uk4
    Commented Jan 18, 2017 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
    Commented Jan 24, 2017 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

3
  • Updated my answer with visual proof that it works.
    – No Sssweat
    Commented Jan 24, 2017 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
    Commented Jan 24, 2017 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
    Commented Jan 24, 2017 at 17:29
3

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.

3
  • 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
    Commented Sep 25, 2019 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
    Commented Oct 21, 2019 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
    Commented Oct 23, 2019 at 8:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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