array( 'label' => t('Autocomplete text field with create'), 'description' => t('Display the list of referenceable nodes as a textfield with autocomplete behaviour, if the node doesn´t exist, create it.'), 'field types' => array('node_reference'), 'settings' => array( 'autocomplete_match' => 'contains', 'size' => 60, 'autocomplete_path' => 'node_reference/autocomplete', ), ), ); } /** * Implements of hook_field_widget_settings_form */ function noderefcreate_field_widget_settings_form($field, $instance) { $widget = $instance['widget']; $defaults = field_info_widget_settings($widget['type']); $settings = array_merge($defaults, $widget['settings']); if ($widget['type'] == 'noderefcreate_autocomplete') { $form['autocomplete_match'] = array( '#type' => 'select', '#title' => t('Autocomplete matching'), '#default_value' => $settings['autocomplete_match'], '#options' => array( 'starts_with' => t('Starts with'), 'contains' => t('Contains'), ), '#description' => t('Select the method used to collect autocomplete suggestions. Note that Contains can cause performance issues on sites with thousands of nodes.'), ); $form['size'] = array( '#type' => 'textfield', '#title' => t('Size of textfield'), '#default_value' => $settings['size'], '#element_validate' => array('_element_validate_integer_positive'), '#required' => TRUE, ); } return $form; } /** * Implements hook_field_widget_form(). */ function noderefcreate_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) { switch ($instance['widget']['type']) { case 'noderefcreate_autocomplete': $element += array( '#type' => 'textfield', '#default_value' => isset($items[$delta]['nid']) ? $items[$delta]['nid'] : NULL, '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'], '#size' => $instance['widget']['settings']['size'], '#element_validate' => array('noderefcreate_autocomplete_validate'), '#value_callback' => 'node_reference_autocomplete_value', '#maxlength' => NULL, ); break; } return array('nid' => $element); } /** * Validation callback for a noderefcreate autocomplete element. * * This is mostly a copy of node_reference validate function, * and we just create new node in case no node with provided title exists. */ function noderefcreate_autocomplete_validate($element, &$form_state, $form) { $field = field_widget_field($element, $form_state); $instance = field_widget_instance($element, $form_state); $value = $element['#value']; $nid = NULL; if (strlen(trim($value)) > 0) { // Check whether we have an explicit "[nid:n]" input. preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $value, $matches); if (!empty($matches)) { // Explicit nid. Check that the 'title' part matches the actual title for // the nid. list(, $title, $nid) = $matches; if (!empty($title)) { $real_title = db_select('node', 'n') ->fields('n', array('title')) ->condition('n.nid', $nid) ->execute() ->fetchField(); if (trim($title) != trim($real_title)) { form_error($element, t('%name: title mismatch. Please check your selection.', array('%name' => $instance['label']))); } } } else { // No explicit nid (the submitted value was not populated by autocomplete // selection). Get the nid of a referencable node from the entered title. $options = array( 'string' => $value, 'match' => 'equals', 'ids' => NULL, 'limit' => 1, ); $reference = node_reference_potential_references($field, $options); if ($reference) { // @todo The best thing would be to present the user with an // additional form, allowing the user to choose between valid // candidates with the same title. ATM, we pick the first // matching candidate... $nid = key($reference); } else { $newnode = NULL; if (is_array($field['settings']['referenceable_types'])) { foreach (array_filter($field['settings']['referenceable_types']) as $related_type) { $newnode->type = $related_type; } } global $user; node_object_prepare($newnode); $newnode->uid = $user->uid; $newnode->name = $user->name; $newnode->title = $value; $newnode->language = $element['#language']; if (module_exists('comment')) { $newnode->comment = variable_get("comment_$newnode->type", COMMENT_NODE_OPEN); } // Honor publishing options from referenced content type $newnode->status = 0; $newnode->promote = 0; $newnode->sticky = 0; $newnode->revision = 0; // get the array of node options for this type $node_options = variable_get('node_options_' . $newnode->type, array('status')); // loop through node options setting the type's defaults foreach($node_options as $key=>$value){ $newnode->$value = 1; } drupal_alter('noderefcreate', $newnode, $element, $form_state); node_save($newnode); $nid = $newnode->nid; } } } else { if (strlen($value) > 0) { // if we got here then the user filled the name with spaces form_error($element, t('%name: title is empty. Please check your input.', array('%name' => $instance['label']))); } } // Set the element's value as the node id that was extracted from the entered // input. form_set_value($element, $nid, $form_state); } /** * Implements hook_field_widget_error(). */ function noderefcreate_field_widget_error($element, $error, $form, &$form_state) { form_error($element['nid'], $error['message']); }