As far as I could understand, the module does not allow to include fields from a referenced node other than the title. I wonder if there are plans to improve on this regards, by allowing the inclusion of all fields from the referenced node specified in the nodereference field.

CommentFileSizeAuthor
#16 content.module_17.patch2.04 KBkarens

Comments

merlinofchaos’s picture

Project: Views (for Drupal 7) » Content Construction Kit (CCK)
Component: Code » nodereference.module

That's up to CCK.

tmp’s picture

This would be a great feature. I could certainly use it.

yched’s picture

A clean and generic solution for this seems difficult to figure out.
This should probably be implemented as formatters for the field, but this would require one additional formatter per target field. Plus, referenceable nodes can be of several types (even more so now that http://drupal.org/node/78825 has been committed), so you'd have to include _all_ possible fields, which is a lot (probably too much).

This ought to be possible at least through theming of the noderef (view) field : you get the nid, do a node_load and display whatever custom things you want, but i'm not sure that even this is currently possible.
I'll try and look into this.

karens’s picture

I can see a couple possibilities here. Once, as yched said, is to just do a node_load in the theme. That is certainly the simplest idea, esp since there are so many different fields you might want to include. Plus someone had done some research on the speed of views queries that include lots of cck fields and found that it is fastest to just query for the nid and do a node_load in the theme to get whatever other fields are wanted.

There's another possibility. In Event Views and Views Calendar (http://www.drupal.org/project/calendar) I'm using a field within a field as a selector, and we could do something similiar with nodereferences. In the calendar module I define a field called 'Calendar: Start Date' and where you would ordinarily see options you instead see a drop-down selector with all views-enabled date fields and you can select which one you want to use as the Calendar start date. For nodereference, we could display a drop down selector of all other views fields to let you select the field you want to use in the view. That solution is much more complicated, maybe too complicated, but should be possible.

karens’s picture

There is one more way to do this. We could call views_pre_view() in the nodereference module and jump in there and do a node load and tweak the results before they get displayed. We could combine that with some sort of selector in the field settings where you indicate which fields you want to bring into the view item.

yched’s picture

The theme / nid / node_load solution is definitely the most flexible one - but it requires some php coding. I still have to check it's currently feasible.

I have mixed feelings about your third idea : views-related behaviour are best IMO kept in the views UI (problem is : where ? see below) - putting these in the field / widget settings form seems... i don't know... not right. Maybe it's juste me.

The second idea would IMO be the best way to go, but the problem is : where in the (view) field UI would we stick the list of (CCK) fields ? The only place I can see is the "Options" column, which for CCK fields is already used by the "formatters" dropdown. Which is why I wrote that this would mean adding one formatter per cck field.

merlinofchaos’s picture

This is almost like a sub-view or something.

It's a really difficult problem to solve in a clean way.

moshe weitzman’s picture

mfrederickson did a viewfield module recently. not sure if that helps here.

karens’s picture

See related discussion at http://drupal.org/node/60756. The more I think about this, the more I am leaning toward keeping the nodereference module in core fairly simple, then using add-on modules (like maybe viewsfield) to get more functionality. You can also insert an embedded view in your theme, or even do a node_load in your theme and display anything you like, so there are alternatives.

There's almost no end of things you *could* add into this module, so it's hard to know where to draw the line :-)

moshe weitzman’s picture

Well, I think this is a pretty important need. Once one groks the coolness of views and node references, he immediately wants to show these additional fields and learns he has to resort to themeing. thats a bit lame IMO, given how much functionality we already deliver without any code. lets give more!

I also like karen's "second" idea.

mfredrickson’s picture

Title: Nodereferences: not just the title » Nodereferences: use view plugins for formatting

Perhaps we can move toward a compromise: formatting using views plugins?

Eaton recently submitted a patch to viewfield that does this:

http://cvs.drupal.org/viewcvs/drupal/contributions/modules/viewfield/vie...

Perhaps we can do the same with node reference selections? This would require a change to the CCK api, specficially:

function nodereference_field_formatter($field, $item, $formatter, $node)

would need to operate on _all_ of the items in the node reference field (so it could mock up a view and pass it to the view plugin).

function nodereference_field_formatter($field, $items, $formatter, $node)

where $items is the full array of values.

I think this API change makes CCK more consistent as well, and allows for a lot of formatting options.

I think the return value should be an array of rendered HTML or the $items should be passed by reference. That way theme functions can behave like they did before.

Of course, we could also just keep the standard link/title formatters and add these as additional formatters.

karens’s picture

Having the formatter operate on all items at once would break many other things since the behavior now is to return a single value. It could be modified to work if we also passed an optional $delta value (so that the $delta value of the items list is returned if provided, otherwise the whole list is returned). Either way, it would require not only changes in all contrib modules but also anywhere anyone has used content_format() in a theme or custom module.

Another way is to have the nodereference module opt out of default handling of the view using the new callbacks so it can do things its own way. As an example of how that can work, look at the pollfield module which uses custom handling of its view and has a collection of formatters, some of which return displays of the whole collection of $item values and others which display individual items.

yched’s picture

Problem is that opting out of default 'view' op is done for the field, thus impacting _all_ formatters.
Not really in line with the supposed modularity of the formatters (you can implement formatters in an external module, without the original field module even being aware of it).

It's true we have an inconsistency between hook_field ops (operate on the $items array of all the values of the field) and the formatters (only operate on individual values). There is the need of a way to group the display of multiple values in one 'thing' (a google map, a view, a graph, whatever...).

I can't think of any backwards-compatible solution for now, but this definitely needs investigation and ideas.

yched’s picture

Suggestion :
what about allowing a third field in hook_field_formatter_info :

function hook_field_formatter_info() {
  return array(
    'global' => array(
      'label' => 'Whatever',
      'field types' => array('text'),
      'scope' => CONTENT_CALLBACK_ALL_VALUES
    ),
  );
}

and modifying _content_field_view with something like :

  if ($formatter['scope'] = CONTENT_CALLBACK_ALL_VALUES) {
    $node_field[0]['view'] = content_format($field, $node_field, $formatter, $node);
  }
  else {
    foreach ($node_field as $delta => $item) {
      $node_field[$delta]['view'] = content_format($field, $item, $formatter, $node);
    }
  }

Still rough on the edge, and definitely not the way you'd define a clean and consistent API from scratch, but this could provide the feature while staying compatible. What do you guys think ?

Side note (CCK 2.0 stuff - if any ever -, probably) : more generally, there is a need for 'per single value' vs 'all field values' declinations of the various field and widget ops, with 'per single value' being the default and most commonly used version. This would allow us to reintegrate most multiple value management into content.module and hardwire consistent behaviour and interesting features - see also http://drupal.org/node/119102#comment-203076 for instance...

karens’s picture

I hadn't thought about the problem of opting out and still allowing other modules to define formatters, so that's a good point.

The problem with your CALLBACK approach is that you then will always get the whole array or not, which is still problematic, i.e. what if I sometimes want a single value and sometimes the whole array, as with the pollfield module, or what if another module wants to insert a formatter and that module wants something different than what is called by the field module?

So, how about a different approach - use the formatter to control it. Add a parameter to each formatter as to whether that formatter needs a single value or the whole thing, with the default being the single value that is used now. Then foreign modules could insert formatters that need the whole array, for instance.

LIke:

function text_field_formatter_info() {
  return array(
    'default' => array(
      'label' => 'Default',
      'field types' => array('text'),
     'values' => CONTENT_CALLBACK_SINGLE_VALUE,
    ),
    'plain' => array(
      'label' => 'Plain text',
      'field types' => array('text'),
      'values' => CONTENT_CALLBACK_SINGLE_VALUE,
    ),
    'trimmed' => array(
      'label' => 'Trimmed',
      'field types' => array('text'),
     'values' => CONTENT_CALLBACK_SINGLE_VALUE,
    ),
    'grouped' => array(
      'label' => 'Grouped',
      'field types' => array('text'),
      'values' => CONTENT_CALLBACK_ALL_VALUES,
    ),
  );

Then the content module would use that value to determine whether to pass in the current item or the whole array.
}
?>

karens’s picture

Status: Active » Needs review
StatusFileSize
new2.04 KB

Here's a patch that would do it. I tried this with the pollfield module and it works fine.

karens’s picture

Hmm, I still think this is the right approach, but that way assumes you always know whether to pass in a single item or the whole array for a particular formatter, which could be confusing. The advantage is that this method doesn't change content_format so it won't break anything out there (like templates that are now using content_format('myfield', $myfield[0]). You just need to know that if you are using a formatter that needs the whole array you must give it content_format('myfield', $myfield) instead of content_format('myfield', $myfield[0]);

The alternative would be to refactor content_format to always expect the whole array and then use the formatter info to determine whether to call the fields formatter with the whole array at once or iterate through the array and call the fields formatter on each individual item. That seems better in a way because content_format() is doing the thinking, but that will break anything now using content_format('myfield', $myfield[0]), which could be in all kinds of places in custom modules and themes. They would then need to give it $myfield instead and then do something with the returned array.

yched’s picture

Actually, if you re-read my suggestion in #14, putting the CONTENT_CALLBACK_ALL_VALUES setting in hook_field_formatter was the idea. So I guess we both agree on that ;-)

And I also think that we can't really afford to break existing templates out there. Even though my personal opinion is that using the 'display settings' tab should be preferred to using content_format in template files.

Small remark regarding the CONTENT_CALLBACK_ALL_VALUES / CONTENT_CALLBACK_SINGLE_VALUE constants : we should probably set them to 0x0008 and 0x0010 to leave the door open for binary combinations with the existing constants.

yched’s picture

Also, mfredrickson, I'd be interested to know how you would implement your idea in #11 if the stuff in #14-#16 got in ?

karens’s picture

Sorry yched, I misread your original idea, so yes, we're on the same track with slightly different ideas about what to call the key (and I don't care which to call it).

And I agree about not breaking existing things, which means the 'cleaner' implementation of always passing the whole array to content_format and passing back an array of formatted items instead of a single formatted item is going to be problematic.

But that particular issue is slightly off-track from the original issue of how to display other referenced node info so this thread has gotten a bit confusing.

The content_format patch would clean up the pollfield module, and probably will help others, irregardless of whether it fixes this issue, so I'd give it a thumbs up whether or not it helps the nodereference problem, but I'd also like to hear how it would affect Mark's solution.

fago’s picture

regarding the nodereference problem you might also have a look at this one: http://drupal.org/node/123482

However views fusion goes a different way. It doesn't use a node_load() but it does appropriate joins and so it directly retrieves the data with the views query.

mfredrickson’s picture

KarenS, yched: I think this solution will meet my needs. I think my code might look something like


/**
 * Implementation of hook_field_formatter_info().
 */
function nodereference_field_formatter_info() {
  // ... existing formatter declarations
  
  include_once(drupal_get_path('module', 'views') .'/views_cache.inc');
  $plugins = _views_get_style_plugins();
  foreach ($plugins as $type => $details) {
    $formatters[$type] = array(
      'label' => $details['name'],
      'field types' => array('nodereference'),
			'scope' => CONTENT_CALLBACK_ALL_VALUES
    );
  }
  
  return $formatters;
}

function nodereference_field_formatter($field, $data, $formatter, $node) {
	switch($formatter) {
		case 'old stuff':
			// you know what goes here
			break;
		default:
			//create a view using $data (which is a bunch of nids)
			$view->page_type = $formatter;
			return views_build_view($view, ...);
	}
}

+1 to the patch.

Would CCK be interested in a patch like the above for nodereference? Or should this live somewhere else (e.g. viewfield)?

yched’s picture

Thanks Mark.
Actually my question was rather about the '//create a view using $data (which is a bunch of nids)' part :-)
I assume you have a means to filter a view in order to select only a given set of nids.
But I guess we want the user to define his own view (with his own fields list... this is where this whole thread started).

As to where this belongs (noderef or viewsfield), my initial feeling would be noderef, but if there's any reason this would be more relevant or cleanly integrated with viewfield, then it's fine by me...

moshe weitzman’s picture

I am a bit lost. The original intent of this issue was to make available additional fields from the referenced node in a table View (for example). Does the formatter stuff we are discussing address that need?

yched’s picture

moshe - The way I see it there are two directions actually :

- The one you mention (merging fields from the referenced node in a table View, as additional columns) would probably be Views fusion stuff and be handled in the thread fago mentioned in comment 21 above.
But this only involves the node in a views context, not the display of the noderef field (say, on the node page)

- The 'view formatter' direction this thread is taking aims at providing a way to display extended info about referenced nodes as the output of the noderef field - It's a formatter , so it acts on the (referer) node page / teaser, in the noderef (views) field ... wherever the noderef field is displayed.

I bit confusing, I must admit...

discursives’s picture

great discussion, thank you for taking the time to look into this. it's where i am going soon, and i can see you blazing a trail that i will, of course, help to idiot-proof, in my own special way :)

mfredrickson’s picture

@yched: If I remember correctly, if you pass a $view object that includes the results to views_build_view, it won't bother running the queries, and will just do the formatting. This would be one way to build the view. (This scenario would would allow formatting by selecting a view style plugin, eg: table, teaser list, calendar)

The other way (and I might like this more), would be to alter the SQL and drop the entire 'where' component and just replace it with 'node.nid in (X ... Y)'. In this scenario, formatting would be done by selecting a specific view (e.g. tracker, frontpage, my_view_with_my_exposed_filters, etc).

I'm leaning towards the first option, to begin with, and just using all the node fields as fields in the view.

merlinofchaos’s picture

mfrederickson: Hm. I don't have a 'just the formatting' part mode of the view, but it would be a good feature request.

I do have the other half -- just get the results.

elio’s picture

Title: Nodereferences: use view plugins for formatting » Why we can't use Handlers?

I have a node that has three products references with a node reference, I just want to visualize the price and the link to the chart.

I am looking to cook a view with handlers that recover the informations throw the tables, do you think is the right way??

Thanks,
elio

fago’s picture

Title: Why we can't use Handlers? » Nodereferences: use view plugins for formatting

please don't change the title.

I don't really get, why passing the whole item array to the formatter would enable the node reference formatter to display extended info about referenced nodes? Could you explain this to me?

Personally I've always worked around such things by trying to keep things where I think they belong to. So how the display of the referenced node should look like is the task of its theme/cck display settings. Then just add formatting options for the nodereference field like show teaser/ show full node view.

For doing such things with table/list views, obviously I'm using views_fusion, which also enables one to sort the view with this fields, which won't be possible with any formatting approach.

elio’s picture

Thanks for your help!

mcreature’s picture

Subscribing"

rickvug’s picture

subscribing

mlncn’s picture

Subscribing... [off topic: is there a place to put PHP snippets for doing this via the theme?]

noah@groups.drupal.org’s picture

subscribing

guardian’s picture

subscribing

moshe weitzman’s picture

Version: 4.7.x-1.x-dev » 6.x-1.x-dev
Status: Needs review » Needs work

I just reread this interesting thread. Seems like we converged on a solution in #28. Need a patch, please.

mandclu’s picture

Version: 6.x-1.x-dev » 5.x-1.5

I hope I won't add to any confusion here, but I've been exploring a similar issue, and thought I'd share a solution I came up with that may suit some. I simply added an option for the referenced node to be displayed as either a teaser or a full node view. Here are the modified functions I used:

function nodereference_field_formatter_info() {
  return array(
    'default' => array(
      'label' => 'Default',
      'field types' => array('nodereference'),
    ),
    'plain' => array(
      'label' => 'Plain text',
      'field types' => array('nodereference'),
    ),
    'teaser' => array(
      'label' => 'Teaser',
      'field types' => array('nodereference'),
    ),
    'full' => array(
      'label' => 'Full node view',
      'field types' => array('nodereference'),
    ),
  );
}

function nodereference_field_formatter($field, $item, $formatter, $node) {
  $text = '';
  if (!empty($item['nid'])) {
    $referenced_node = node_load($item['nid']);
    if ($referenced_node) {
      $text = l($referenced_node->title, 'node/'. $referenced_node->nid);
    }
  }

  switch ($formatter) {
    case 'plain':
      return strip_tags($text);

    case 'teaser':
      return node_view($referenced_node, TRUE, FALSE, FALSE);

    case 'full':
      return node_view($referenced_node, FALSE, TRUE, FALSE);

    default:
      return $text;
  }
}

The version I'm working with is a little different that some of the others mentioned in the discussion so YMMV. Ironically, this doesn't actually solve my own problem, as what I'm trying to create is a nested table view, but I have a feeling I can accomplish what I need through some Views theming. Also note that the node view in this scenarion doesn't actually put the title of the referenced node in. This is what I wanted, but you could add another formatter for Title + Full node, etc.

yched’s picture

@surge_martin : your proposal is not really related, and has in fact already been added to the dev versions of CCK (with some issues currently whit reference cycles - A references B, which references C, which references A...) - see http://drupal.org/node/152016

yojoe’s picture

I have the following scenario:
- Content type 'country'
- Content type 'state'; a state must reference a 'country' node
- Content type 'region'; a region must reference a 'country' node
- Content type 'city'; a city must reference a 'state' and a 'region' node
- Content type 'building'; a building must reference a 'city' node

On the page that is displayed for a building, I do not only need some fields of the directly referenced city node, but also some fields of the indirectly referenced region, state and country nodes. Currently I do this by doing a node_load of the city, region, state. I have the following code in the template.php file of my theme:

/**
 * Override or insert PHPTemplate variables into the templates.
 */
function _phptemplate_variables($hook, $vars) {
  switch($hook) {
    case 'page' :
      ...
      break;
    
    case 'node':
      if( $variables['field_city'] ) {
        $variables['city'] = node_load($variables['field_city'][0]['nid']);
        $variables['field_region'] = $variables['city']->field_region;
        $variables['field_state'] = $variables['city']->field_state;
      }

      if( $variables['field_region'] ) {
        $variables['region'] = node_load($variables['field_region'][0]['nid']);
        $variables['field_country'] = $variables['region']->field_country;
      }

      if( $variables['field_state'] ) {
        $variables['state'] = node_load($variables['field_region'][0]['nid']);
        $variables['field_country'] = $variables['state']->field_country;
      }

      if( $variables['field_country'] ) {
        $variables['country'] = node_load($variables['field_country'][0]['nid']);
      }

      break;
    }
    return $variables;
}

This way I have the completely loaded nodes for the city, region, state and country as variables ($city, $region, $state, $country) available when a 'building' node is to be themed. To theme the 'building' node I have a separate "node-building.tpl.php" file in my theme directory.

While this works for theming nodes, the fields of the referenced and indirectly referenced nodes are not available in views :( I'm still missing a approach to make them available in views, too.

guardian’s picture

what's the status of this issue ?
does the formatters refactoring discussed here http://drupal.org/node/213279 help fixing this issue ?

joachim’s picture

I've implemented this as a formatter in a separate module: http://drupal.org/project/nodereference_views

I'm interested about the options in comment #27 though, specifically building the view object first. What my module does is just pass the nids as an argument to the view.

sirkitree’s picture

trying to do this as well - would go a long way into making a great photo gallery with just cck/views - willing to port to 6 if someone comes up with something here.

joachim’s picture

You'd be picking images on the gallery node rather than setting the gallery on the image, which is backwards to the usual way... but install the module I just linked to and you've got it.

aren cambre’s picture

Version: 5.x-1.5 » 6.x-2.x-dev
Status: Needs work » Active

This issue is unclear. Is it talking about the edit page, where one selects the referenced node(s), or is it talking about the final rendered node?

Regardless of answer, work on this issue is very stale. Moving back to active status and changing to current version. (Should it be 7.x instead?)

joachim’s picture

The issue is about the rendered node, hence "formatting". At least that's the original post and what my comments have been about :)

aren cambre’s picture