Note: Requires content.module.'); } } /** * Implementation of hook_menu(). */ function nodereference_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array('path' => 'nodereference/autocomplete', 'title' => t('node reference autocomplete'), 'callback' => 'nodereference_autocomplete', 'access' => user_access('access content'), 'type' => MENU_CALLBACK); } return $items; } /** * Implementation of hook_field_info(). */ function nodereference_field_info() { return array( 'nodereference' => array('label' => 'Node Reference'), ); } /** * Implementation of hook_field_settings(). */ function nodereference_field_settings($op, $field) { switch ($op) { case 'form': $form = array(); $form['referenceable_types'] = array( '#type' => 'checkboxes', '#title' => t('Content types that can be referenced'), '#multiple' => TRUE, '#default_value' => isset($field['referenceable_types']) ? $field['referenceable_types'] : array(), '#options' => node_get_types(), ); return $form; case 'save': return array('referenceable_types'); case 'database columns': $columns = array( 'nid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'), ); return $columns; } } /** * Implementation of hook_field(). */ function nodereference_field($op, &$node, $field, &$node_field, $teaser, $page) { switch ($op) { case 'view': foreach ($node_field as $delta => $item) { $node_field[$delta]['view'] = nodereference_field_view_item($field, $item, $node); } return theme('field', $node, $field, $node_field, $teaser, $page); } } /** * Implementation of hook_field_view_item(). */ function nodereference_field_view_item($field, $node_field_item) { if (!isset($node_field_item['nid'])) { return ''; } $referenced_node = node_load($node_field_item['nid']); if ($referenced_node) { return l($referenced_node->title, 'node/'. $referenced_node->nid); } } /** * Implementation of hook_widget_info(). */ function nodereference_widget_info() { return array( 'nodereference_select' => array( 'label' => 'Select List', 'field types' => array('nodereference'), ), 'nodereference_autocomplete' => array( 'label' => 'Autocomplete Text Field', 'field types' => array('nodereference'), ), ); } /** * Implementation of hook_widget(). */ function nodereference_widget($op, &$node, $field, &$node_field) { if ($field['widget']['type'] == 'nodereference_select') { switch ($op) { case 'prepare form values': $node_field_transposed = content_transpose_array_rows_cols($node_field); $node_field['default nids'] = $node_field_transposed['nid']; break; case 'form': $form = array(); $form[$field['field_name']] = array('#tree' => TRUE); $form[$field['field_name']]['nids'] = array( '#type' => 'select', '#title' => t($field['widget']['label']), '#default_value' => $node_field['default nids'], '#multiple' => $field['multiple'], '#options' => _nodereference_potential_references($field), '#required' => $field['required'], '#description' => $field['widget']['description'], ); return $form; case 'process form values': if ($field['multiple']) { $node_field = content_transpose_array_rows_cols(array('nid' => $node_field['nids'])); } else { $node_field[0]['nid'] = $node_field['nids']; } // Remove the widget's data representation so it isn't saved. unset($node_field['nids']); } } else { switch ($op) { case 'prepare form values': foreach ($node_field as $delta => $item) { $node_field[$delta]['default node_name'] = db_result(db_query(db_rewrite_sql('SELECT n.title FROM {node} n WHERE n.nid = %d'), $node_field[$delta]['nid'])); } break; case 'form': $form = array(); $form[$field['field_name']] = array('#tree' => TRUE); if ($field['multiple']) { $form[$field['field_name']]['#type'] = 'fieldset'; $form[$field['field_name']]['#title'] = t($field['widget']['label']); $form[$field['field_name']]['#description'] = $field['widget']['description']; $delta = 0; foreach ($node_field as $item) { if ($item['nid']) { $form[$field['field_name']][$delta]['node_name'] = array( '#type' => 'textfield', '#title' => '', '#autocomplete_path' => 'nodereference/autocomplete/'. $field['field_name'], '#default_value' => $item['default node_name'], '#required' => ($delta == 0) ? $field['required'] : FALSE, ); $delta++; } } foreach (range($delta, $delta + 2) as $delta) { $form[$field['field_name']][$delta]['node_name'] = array( '#type' => 'textfield', '#title' => '', '#autocomplete_path' => 'nodereference/autocomplete/'. $field['field_name'], '#default_value' => '', '#required' => ($delta == 0) ? $field['required'] : FALSE, ); } } else { $form[$field['field_name']][0]['node_name'] = array( '#type' => 'textfield', '#title' => t($field['widget']['label']), '#autocomplete_path' => 'nodereference/autocomplete/'. $field['field_name'], '#default_value' => $node_field[0]['default node_name'], '#required' => $field['required'], '#description' => $field['widget']['description'], ); } return $form; case 'validate': foreach ($node_field as $delta => $item) { if ($item['node_name'] && !in_array($item['node_name'], _nodereference_potential_references($field))) { form_set_error($field['field_name'], t('No post with that title exists.')); } } return; case 'process form values': foreach ($node_field as $delta => $item) { $nid = db_result(db_query(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.title = '%s'"), $node_field[$delta]['node_name'])); // Remove the widget's data representation so it isn't saved. unset($node_field[$delta]['node_name']); if ($nid) { $node_field[$delta]['nid'] = $nid; } else { unset($node_field[$delta]); } } } } } /** * Fetch an array of all candidate referenced nodes, for use in presenting the selection form to the user. */ function _nodereference_potential_references($field, $return_full_nodes = FALSE) { $related_types = array(); foreach ($field['referenceable_types'] as $related_type) { if ($related_type) { $related_types[] = " type = '". $related_type ."'"; } } $related_clause = implode(' OR ', $related_types); if (!count($related_types)) { return array(); } $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, n.type FROM {node} n WHERE ". $related_clause ." ORDER BY n.title, n.type")); if (db_num_rows($result) == 0) { return array(); } $rows = array(); while ($node = db_fetch_object($result)) { if ($return_full_nodes) { $rows[$node->nid] = $node; } else { $rows[$node->nid] = $node->title; } } return $rows; } function nodereference_referenced_by_list($nid, $content_type = '') { if ($content_type) { $result = db_query("SELECT n.* FROM {node_field_nodereference_data} node_ref INNER JOIN {node} n ON n.vid = node_ref.vid AND n.type = '%s' WHERE node_ref.field_nid = %d ORDER BY delta", $nid, $content_type); } else { $result = db_query("SELECT n.* FROM {node_field_nodereference_data} node_ref INNER JOIN {node} n ON n.vid = node_ref.vid WHERE node_ref.field_nid = %d ORDER BY delta", $nid); } $values = array(); while ($value = db_fetch_object($result)) { $values[] = $value; } return $values; } /** * Retrieve a pipe delimited string of autocomplete suggestions */ function nodereference_autocomplete($field_name, $string = '') { $fields = content_fields(); $field = $fields[$field_name]; $matches = array(); foreach (_nodereference_potential_references($field, TRUE) as $key => $value) { if (stristr($value->title, $string)) { $matches[$value->title] = check_plain('('. str_replace('content-', '', $value->type) .') '. $value->title); } } print drupal_to_js($matches); exit(); }