8

Sorry for the code in the title, I couldn't think of a clearer way to ask it.

I have several nodes of the location content type, and a view outputting teasers of those nodes. I want to do some custom stuff in node--location.tpl.php to affect the teasers everywhere they're displayed. When I do a simple dpm($node) to get at the variables, some field values are not always in the same place.

For instance, I have field_phone that just has identically formatted phone numbers. For the first node in this view, that field is structured as $node->field_phone['und'][0]['safe_value']. But for the second node, it's simply $node->field_phone[0]['safe_value'].

I know that und has to do with translations, and perhaps means "undefined". I'm not doing anything with translations or localization or languages on the site, so it's not like this node is any different from other nodes that way.

What causes this, and is there a function or something that can help me test for and get at the value easily, or do I have to roll my own?

EDIT: Chris Rockwell below points out field_get_items(). This seemed to solve my problem on the site I was working on the other day. But now, on a different site, it's failing for exactly the reason I bring up here.

I have a view that outputs three nodes. For some reason, when I dpm($node) in the node--node-type.tpl.php file, I get six variable dumps. The first one has $node->field_link_image['und'][0], while all five others — INCLUDING the duplicate of this same node — just has $node->field_link_image[0]. And now, field_get_items() is silently failing and returning false on those last five nodes.

So I go back to my original question: What causes this difference between some node variables and others, and what can I do about it?

4
  • I edited my answer. I believe you should be using field_view_value() and the delta on the $item passed to it. – Chris Rockwell Aug 7 '13 at 14:23
  • Also, does field_link_image accept multiple values? – Chris Rockwell Aug 7 '13 at 14:41
  • @75th-trombone I have exactly the same problem, did you found the solution? – sepehr Oct 27 '13 at 9:35
  • @75th-trombone have you used nodeblock module in that particular project? – sepehr Oct 27 '13 at 9:55
8
+50

The lack of the 'und', or LANGUAGE_NONE level data seems to indicate that the field has lost the ability to be translated. I've never encountered such a field.

field_get_items() as already pointed out is the canonical way to safely retrieve field data. Any fields that don't work with field_get_items should be considered broken.

I would hazard a guess that you either

  1. Have a broken contrib module that re-arranges field data and doesn't know better than to sometimes remove the language level.
  2. Your field settings have just broken somewhere along the way. Potentially because of a reason similar to above.

Does the problem keep happening on newly created fields?

Can you reproduce on a clean install?

5
  • 2
    I have seen this happen, but not in a long time, so I can't point to a culprit. – mpdonadio Aug 7 '13 at 20:42
  • All I can really think of then is bringing in the heavy artillery, debug the field API, which is quite a complicated piece of code. – Letharion Aug 8 '13 at 8:30
  • 2
    Over a year later, I finally figured out what this problem is, or at least part of it. It's when I use dpm() in node--whatever.tpl.php for a content type used in a view. It's dpm() itself. When I don't run dpm(), all the $node instances in the view are correct. When I do, all but the first have the language level stripped out. Crazy. – 75th Trombone Oct 27 '14 at 15:20
  • Just, wow.. Thanks @75thTrombone for the follow up. I've just debugging this for far too long. – enzipher Aug 19 '15 at 5:34
  • @75th Trombone IS RIGHT!! The same problem here, thanks – Incredible Apr 13 '16 at 14:26
3

I believe you need a combination of field_get_items() and field_view_value().

In your case (I can't test this):

$item = field_get_items('node', $node, 'field_phone'); // unsafe to print
$output = field_view_value('node', $node, 'field_phone', $item[0]);
print $output;

EDIT: In the above code, line 2 ($output = ...), I added in $item[0] because I failed to see that $item requires a delta. This allows for fields which have multiple values to be iterated over and passed through field_view_value(). I believe you are skipping the important step of using field_view_value().

If using the above code (including field_view_value()) doesn't solve this, I would need more information; e.g. seeing your node.tpl.php and possibly a content type export.

4
  • I think you have an $image that needs to be $item, but field_get_items is exactly what I needed. Its result has the safe_value (not just the value), which should be safe to print, right? I don't need field_view_value because I want to output the variable directly, not with the render function. – 75th Trombone Jul 29 '13 at 19:59
  • That result would be safe to print, but I'm fairly certain you can not rely on safe_value being present. I'd have to do some digging to confirm though. Thanks for mentioning the typo, fixed. – Chris Rockwell Jul 29 '13 at 20:22
  • Well, this seemed to work on the last site I tried it on, but I'm looking at an instance of it failing right now. I'm reopening this question; see my edit above. – 75th Trombone Aug 6 '13 at 21:13
  • You mention field_get_items() in your edit, but not field_view_value() - are you using it? field_view_value() is a renderable array, so you should be able to get the value directly from that. Additionally, why would someone down vote the answer that solved the original problem, but doesn't seem to work for the new problem? – Chris Rockwell Aug 7 '13 at 3:54
0

Here's the function I'm using until I find a better answer. In addition to fixing the language issue, it should also always return a numeric array, so you can be confident in foreaching over the result.

function get_field($field, $lang = 'en', $fallback = 'en') {
    $var = FALSE;
    if(!empty($field[$lang])) {
        $var = $field[$lang];
    } elseif(!empty($field[$fallback])) {
        $var = $field[$fallback];
    } elseif(!empty($field['und'])) {
        $var = $field['und'];
    } elseif(!empty($field)) {
        $var = $field;
    }

    if(empty($var)) {
        return false;
    }

    if(!empty($var[0])) {
        return $var;
    } else {
        return array($var);
    }
}
-3

If you take a look at this https://api.drupal.org/api/drupal/includes%21bootstrap.inc/constant/LANGUAGE_NONE/7

this is a safer value to use and will work for any defined language, including no language.

1
  • 2
    I don't understand how that helps me or answers my question. It doesn't somehow get me the und-free version if I ask for it. $node->field_location[LANGUAGE_NONE][0]['safe_value'] will fail for that second node just as much as $node->field_location['und'][0] will. – 75th Trombone Jul 29 '13 at 19:10

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.