Question

Using the autocomplete field for a cck nodereference always displays the node id as a cryptic bracketed extension:

Page Title [nid:23]

I understand that this ensures that selections are unique in case nodes have the same title, but obviously this is a nasty thing to expose to the user.

Has anyone had any success in removing these brackets, or adding a different unique identifier?

Was it helpful?

Solution

Ultimately, you need to change the output of nodereference_autocomplete() in nodereference.module.

To do this properly, you want a custom module to cleanly override the function.

This function is defined as a menu callback, thus,

/**
 * Implementation of hook_menu_alter().
 */
function custom_module_menu_alter(&$items) {
  $items['nodereference/autocomplete']['page callback'] = 'custom_module_new_nodereference_autocomplete';
}

Then, copy the nodereference_autocomplete function into your custom module, changing it's name to match your callback. Then change this one line:

$matches[$row['title'] ." [nid:$id]"] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';

Dropping the nid reference.

$matches[$row['title']] = '<div class="reference-autocomplete">'. $row['rendered'] . '</div>';

I believe the identifier is purely cosmetic at this point, which means you could also change the text however you like. If it is not purely cosmetic, well, I haven't tested to see what will happen in the wrong conditions.

I always meant to identify how to do this. Thank you for motivating me with your question.

OTHER TIPS

What Grayside has posted will work... as long as you don't have two nodes with the same title. In other words, if you want to do as Grayside has proposed, you need to be aware that the nid is not entirely unimportant. The nodereference_autocomplete_validate() function does two things. It checks to see if there is a node that matches, and if so, it passes the nid on, setting it to the $form_state array. If it can't find a node, it will set an error. If the nid is present, it will be used to get the node, which also is faster, the code is here:

preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $value, $matches);
    if (!empty($matches)) {
        // Explicit [nid:n].
        list(, $title, $nid) = $matches;
        if (!empty($title) && ($n = node_load($nid)) && $title != $n->title) {
            form_error($element[$field_key], t('%name: title mismatch. Please check your selection.', array('%name' => t($field['widget']['label']))));
        }
    }

This just checks to see if there is a nid and checks if that node matches with the title, if so the nid is passed on.

The 2nd option is a bit slower, but it is here errors can happen. If you follow the execution, you will see, that if will try to find a node based on title alone, and will take the first node that matches. The result of this, is that if you have two nodes with the same title, one of them will always be used. This might not be a problem for you, but the thing is, that you will never find out if this happens. Everything will work just fine and the user will think that he selected the node he wanted to. This might be the case, but he might as well have chosen the wrong node.

So in short, you can get rid of the nid in the autocomplete callback, but it has 2 drawbacks:

  1. performance (little)
  2. uncertainty in selecting the correct node.

So you have to think about it, before going this route. Especially, since you most likely wont be able to find the problem of the selection of the wrong nodes, should it happen. Another thing to be aware of, is that the nid showing up, also brings some valuable info to the users, a quick way to lookup the node, should they be in doubt if it is the one they want, if several nodes have similar titles.

I got Grayside's answer to work, but I had to use MENU alter, instead of the FORM alter he posted. No biggy!

function custommodule_menu_alter(&$items) {
  $items['nodereference/autocomplete']['page callback'] = 'fp_tweaks_nodereference_autocomplete';
}

I've found an alternative solution is to change your widget type to select list and then use the chosen module to convert your list to an autocomplete field.

This handles nodes with the same title, and actually I think the UI is better than the one provided by the autocomplete widget.

To anyone coming across this (rather old) topic by way of a google search - for Drupal 7 please consider using entityreference module and "Entity Reference" field type if possible.

You can acheive a lot more in configuration with an "Entity Reference" field. It doesn't have this problem with the nid in square brackets.

Here is the full Drupal 7 version (References 7.x-2.1) of Grayside's answer. This goes in your custom module:

/**
 * Implementation of hook_menu_alter().
 */
function custom_menu_alter(&$items) {
  $items['node_reference/autocomplete/%/%/%']['page callback'] = 'custom_new_node_reference_autocomplete';
}

/**
 * Implementation of Menu callback for the autocomplete results.
 */
function custom_new_node_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
  $field = field_info_field($field_name);
  $instance = field_info_instance($entity_type, $field_name, $bundle);

  $options = array(
    'string' => $string,
    'match' => $instance['widget']['settings']['autocomplete_match'],
    'limit' => 10,
  );
  $references = node_reference_potential_references($field, $options);

  $matches = array();
  foreach ($references as $id => $row) {
    // Markup is fine in autocompletion results (might happen when rendered
    // through Views) but we want to remove hyperlinks.
    $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
    // Add a class wrapper for a few required CSS overrides.
    $matches[$row['title']] = '<div class="reference-autocomplete">' . $suggestion . '</div>'; // this is the line that was modified to remove the "[nid:XX]" disambiguator
  }

  drupal_json_output($matches);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top