4

I am trying to programmatically set a link in a Drupal 8 view. The client wants an external link used if a certain link field is set, otherwise default the link to the node.

I am trying to figure out how to set this, and despite looking at hook_views_pre_render() and hook_views_post_render(), I'm not seeing any method to make this happen. I'm trying to go into result -

foreach ($view->result as $key => $value) {

}

However Kint is giving me data like this:

public _relationship_entities -> array(0)
public index -> integer7
public node_field_data_langcode -> string(2) "en"
public nid -> string(2) "99"

for each ResultRow.

I don't remember this being particularly difficult in Drupal 7 - is there something I'm missing here? How do I programmatically set a link in Drupal 8 dependent on certain conditions for a view row/field in a row?

5
  • So, for a specific node, if field_certain_link has a value, you want to have a views field linked to that value; if not, linked to the node. And you want to do this programmaticaly? Not via the Views configuration UI? Commented Feb 27, 2017 at 17:12
  • Is there a way to do that in the Views configuration UI? Assignment to a link is usually an either/or situation there - I know of no way to assign a link in certain circumstances but not others.
    – Jack Ryan
    Commented Feb 27, 2017 at 18:00
  • Is this the only condition "field_certain_link has a value set" or are there more? Commented Feb 27, 2017 at 18:04
  • That's the only condition really. If an external link field is set, generate markup with the link, otherwise generate the markup with the link to the node.
    – Jack Ryan
    Commented Feb 27, 2017 at 18:05
  • Yes, you can do that only via the UI, will post an answer below. Commented Feb 27, 2017 at 18:21

4 Answers 4

8
+100

The hook you're looking for is hook_views_view_field().

This hook allows you to alter the output of the field, and still is early enough to have the entity data for for that field.

In the example below, I'm checking if the node has a link field, field_my_link set, and if it's set, I alter the title output (which is normally linked to the node) to output to the link field's uri, but only if it's an external link.

function mymodule_preprocess_views_view_field(&$vars) {
  if ($vars['view']->id() != 'testview') {
    return;
  }
  $node = $vars['row']->_entity;
  if ($vars['field']->getField() == '.title' && $node->field_my_link->isEmpty() === FALSE) {
    if ($node->field_my_link[0]->isExternal()) {
      $link = $node->field_my_link[0]->view();
      $link['#title'] = $node->label();
      $vars['output'] = $link;
    }
  }
}

If you want to alter the output of one views field based on the output of another, use hook_views_view_fields():

function mymodule_preprocess_views_view_fields(&$vars) {
  if ($vars['view']->id() != 'testview') {
    return;
  }

  // Cast Markup object to string.
  $field_one_content = (string) $vars['fields']['field_1']->content;

  // Check if first field contains a substring, if so, update second field.
  if (strpos($field_one_content, 'my search string') > -1) {
    $vars['fields']['field_2']->content = \Drupal\Core\Render\Markup::create('hello world');
  }

}
4
  • Not quite what I want. I want to modify one field on the basis of another field, but this might be similar to what I want. I'll play around with it and see if I can get it working the way I want it.
    – Jack Ryan
    Commented Feb 27, 2017 at 18:17
  • I updated the answer with another option, to alter the data from the output of another views field.
    – oknate
    Commented Feb 27, 2017 at 18:34
  • I got it all working. Thank you. This is the answer I needed. I'll award the bounty once it lets me.
    – Jack Ryan
    Commented Feb 27, 2017 at 18:54
  • great! Glad to help.
    – oknate
    Commented Feb 27, 2017 at 19:02
1

If you're able to reconfigure the view to use "Rendered Content" instead of fields, it might be dead simple to create a view mode, configure the fields that display, and then provide a node--node-type--view-mode.html.twig template. Then you can preprocess the node, by view mode, and add/check variables before they are rendered in the template.

I say that, because it is easier than trying to wrestle with views at this level.

Here are similar questions revolving around this sort of thing:

Then, you would be able to reuse this view mode in other areas and create new Views to use this view mode, without configuring every View fields and doing the same overrides again and again. And, as you see, it is hard to debug. But debugging at the node / view mode level, much easier.

1

A recipe for doing this via the Views UI

You will need 3 fields,

  • one to get the NID
  • one to get the field_certain_link
  • one to render the link

You set up each field like this:

a) NID field: Hide it from display.

b) field_certain_link: Hide it from display and rewrite its value to be the raw URI, e.g. {{ field_certain_link__uri }}. You have to set a rewrite value for the no results part, this should be node/{{ nid }}, with nid coming from the first field.

c) This is a 'Global: Custom Text' views field. Enter the text of the link and select the rewrite>output as a custom link option. The link's value should be the value of the field_certain_link, sth like {{ field_certain_link }}

The views configuration should look sth like this now (the fields section):

enter image description here

That's it basically, after you are done, your custom text field is rendered as a link and depending on the value of field_certain_link, it links to the external link or the node.

This should look like this (first and second columns are visible only for debugging reasons). The second column demonstrates the conditional rewriting of the field, based on whether it has a value set or not. The first row has not value set for the field_certain_link field, and is therefore linked to the node:

enter image description here

Good luck!

P.S.: You could probably use only one field and rewrite using twig to write the conditions. This is an D7 recipe actually.

0

You might have to create a custom views formatter. These plugins take the data that is returned by a view and prepares it for display on the page. The 'Table' and 'Grid' formatter a are examples. I recently created one to take the results from a view and create a pie chart. In your case, you could query the important pieces and use the formatter to assemble them and render as a URL.

Another solution is to create a new field formatter. The formatter would accept the field, look up this other piece of information, and create the appropriate link.

1
  • Biggest problem I see with the field formatter is that I'd have to pull in data from another field (for the external link) into it. I'll think about the view formatter. That might work, though I don't feel that's necessarily the best solution - I feel it would basically be akin to code duplication to create "Views Table - but special!" in this context
    – Jack Ryan
    Commented Feb 27, 2017 at 16:27

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.