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. Aug 7, 2013 at 14:23
  • Also, does field_link_image accept multiple values? Aug 7, 2013 at 14:41
  • @75th-trombone I have exactly the same problem, did you found the solution?
    – sepehr
    Oct 27, 2013 at 9:35
  • @75th-trombone have you used nodeblock module in that particular project?
    – sepehr
    Oct 27, 2013 at 9:55

4 Answers 4

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, 2013 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, 2013 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. Oct 27, 2014 at 15:20
  • Just, wow.. Thanks @75thTrombone for the follow up. I've just debugging this for far too long.
    – dxc
    Aug 19, 2015 at 5:34
  • @75th Trombone IS RIGHT!! The same problem here, thanks
    – Incredible
    Apr 13, 2016 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. Jul 29, 2013 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. Jul 29, 2013 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. Aug 6, 2013 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? Aug 7, 2013 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. Jul 29, 2013 at 19:10

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.