? references-missing-views-945004-10.patch
? node_reference/includes
? user_reference/includes
Index: node_reference/node_reference.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/references/node_reference/node_reference.info,v
retrieving revision 1.1
diff -u -p -r1.1 node_reference.info
--- node_reference/node_reference.info	6 Dec 2010 21:28:17 -0000	1.1
+++ node_reference/node_reference.info	12 Dec 2010 05:10:09 -0000
@@ -2,5 +2,8 @@
 name = Node Reference
 description = Defines a field type for referencing one node from another.
 files[]=node_reference.module
+files[]=includes/node_reference.views.inc
+files[]=includes/node_reference_views_plugin_display.inc
+files[]=includes/node_reference_views_plugin_style.inc
 package = CCK
-core = 7.x
+core = 7.x
\ No newline at end of file
Index: node_reference/node_reference.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/references/node_reference/node_reference.module,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 node_reference.module
--- node_reference/node_reference.module	7 Dec 2010 15:40:59 -0000	1.1.2.1
+++ node_reference/node_reference.module	12 Dec 2010 05:10:10 -0000
@@ -26,17 +26,24 @@ function node_reference_menu() {
  * Implements hook_field_info().
  */
 function node_reference_field_info() {
-  return array(
+  $field_info = array(
     'node_reference' => array(
       'label'             => t('Node reference'),
       'description'       => t('This field stores the ID of a related node as an integer value.'),
-      'settings'          => array('referenceable_types' => array()),
-      // It probably make more sense to have the referenceable types be per-field than per-instance
-      // 'instance settings' => array('referenceable_types' => array()),
+      'settings'          => array(
+        'referenceable_types' => array(),
+      ),
       'default_widget'    => 'options_select', //  node_reference_autocomplete',
       'default_formatter' => 'node_reference_default',
     ),
   );
+  if (module_exists('views')) {
+    $field_info['node_reference']['settings']['views'] = array(
+      'view' => '',
+      'view_args' => '',
+    );
+  }
+  return $field_info;
 }
 
 /**
@@ -79,6 +86,62 @@ function node_reference_field_settings_f
     '#options'       => array_map('check_plain', node_type_get_names()),
     '#disabled'      => $has_data,
   );
+  if (module_exists('views')) {
+    $views = array('' => '<' . t('none') . '>');
+    $all_views = views_get_all_views();
+
+    foreach ($all_views as $view_name => $view) {
+      // Only 'node' views that have fields will work for our purpose.
+      if ($view->base_table == 'node') {
+        foreach ((array)$view->display as $display_key => $display) {
+          $id = $view_name . ':' . $display_key;
+          // Get display title.
+          $display_title = node_reference_views_display_title($view_name, $view, $display_key);
+          // Append $id to the title for disambiguation in lists.
+          $display_title .= ' ['. $id . ']';
+
+          if ($view->type == 'Default') {
+            $views[t('Default views')][$id] = $display_title;
+          }
+          else {
+            $views[t('Existing views')][$id] = $display_title;
+          }
+        }
+      }
+    }
+
+    $form['views'] = array(
+       '#type' => 'fieldset',
+       '#title' => t('Views - Nodes that can be referenced'),
+       '#collapsible' => TRUE,
+       '#collapsed' => !isset($settings['views']['view']) || $settings['views']['view'] == '',
+     );
+    if (count($views) > 1) {
+      $form['views']['view'] = array(
+        '#type' => 'select',
+        '#title' => t('View used to select the nodes'),
+        '#options' => $views,
+        '#default_value' => isset($settings['views']['view']) ? $settings['views']['view'] : '',
+        '#description' => t('<p>Choose the "Views module" view that selects the nodes that can be referenced.<br />Note:</p>') .
+          t('<ul><li>This will discard the "Content types" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate nodes on node creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate nodes will be displayed.</li></ul>'),
+        '#disabled' => $has_data,
+      );
+      $form['views']['view_args'] = array(
+        '#type' => 'textfield',
+        '#title' => t('View arguments'),
+        '#default_value' => isset($settings['views']['view_args']) ? $settings['views']['view_args'] : '',
+        '#required' => FALSE,
+        '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
+        '#disabled' => $has_data,
+      );
+    }
+    else {
+      $form['views']['no_view_help'] = array(
+        '#value' => t('<p>The list of nodes that can be referenced can be based on a "Views module" view but no appropriate views were found. <br />Note:</p>') .
+          t('<ul><li>This will discard the "Content types" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate nodes on node creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate nodes will be displayed.</li></ul>'),
+      );
+    }
+  }
   return $form;
 }
 
@@ -588,7 +651,14 @@ function _node_reference_potential_refer
     . ($string !== '' ? $string : implode('-', $ids))
     . ':' . $limit;
   if (!isset($results[$cid])) {
-    $references = _node_reference_potential_references_standard($field, $string, $match, $ids, $limit);
+    $references = FALSE;
+    if (module_exists('views') && !empty($field['settings']['views']['view'])) {
+      $references = _node_reference_potential_references_views($field, $string, $match, $ids, $limit);
+    }
+
+    if ($references === FALSE) {
+      $references = _node_reference_potential_references_standard($field, $string, $match, $ids, $limit);
+    }
 
     // Store the results.
     $results[$cid] = !empty($references) ? $references : array();
@@ -598,6 +668,92 @@ function _node_reference_potential_refer
 }
 
 /**
+ * Helper function for _nodereference_potential_references().
+ *
+ * Case of Views-defined referenceable nodes.
+ */
+function _node_reference_potential_references_views($field, $string = '', $match = 'contains', $ids = array(), $limit = NULL) {
+  $view_id = $field['settings']['views']['view'];
+  list($view_name, $view_display) = explode(':', $view_id);
+
+  if ($view = views_get_view($view_name)) {
+
+    // We add a display, and let it derive from the 'default' display.
+    $display = $view->add_display('node_reference_views_plugin_display');
+    $view->set_display($display);
+
+    // Get the options from the user supplied display.
+    if ($view_display != 'default' && isset($view->display[$view_display]->display_options)) {
+      $view->display[$display]->display_options = $view->display[$view_display]->display_options;
+    }
+
+    // TODO from merlinofchaos on IRC : arguments using summary view can defeat the style setting.
+    // We might also need to check if there's an argument, and set *its* style_plugin as well.
+    $view->display_handler->set_option('style_plugin', 'node_reference_views_plugin_style');
+    $view->display_handler->set_option('row_plugin', 'fields');
+    // Used in node_reference_style::render(), to get
+    // the 'field' to be used as title.
+    $view->display_handler->set_option('node_reference_title_field', 'title');
+
+    // Additional options to let node_reference_display::query()
+    // narrow the results.
+    $options = array(
+      'table' => 'node',
+      'field_string' => 'title',
+      'string' => $string,
+      'match' => $match,
+      'field_id' => 'nid',
+      'ids' => $ids,
+    );
+    $view->display_handler->set_option('node_reference_options', $options);
+
+    // TODO : for consistency, a fair amount of what's below
+    // should be moved to node_reference_display
+
+    // Limit result set size.
+    $limit = isset($limit) ? $limit : 0;
+    $view->display_handler->set_option('items_per_page', $limit);
+
+    // Get arguments for the view.
+    if (!empty($field['settings']['views']['view_args'])) {
+      // TODO: Support Tokens using token.module ?
+      $view_args = array_map('trim', explode(',', $field['settings']['views']['view_args']));
+    }
+    else {
+      $view_args = array();
+    }
+
+    // We do need title field, so add it if not present (unlikely, but...)
+    $fields = $view->get_items('field', $display);
+
+    if (!isset($fields['title'])) {
+      $view->add_item($display, 'field', 'node', 'title');
+    }
+
+    // If not set, make all fields inline and define a separator.
+    $options = $view->display_handler->get_option('row_options');
+    if (empty($options['inline'])) {
+      $options['inline'] = drupal_map_assoc(array_keys($view->get_items('field', $display)));
+    }
+    if (empty($options['separator'])) {
+      $options['separator'] = '-';
+    }
+    $view->display_handler->set_option('row_options', $options);
+
+    // Make sure the query is not cached
+    $view->is_cacheable = FALSE;
+
+    // Get the results.
+    $result = $view->execute_display($display, $view_args);
+  }
+  else {
+    $result = FALSE;
+  }
+
+  return $result;
+}
+
+/**
  * Helper function for _node_reference_potential_references().
  *
  * List of referenceable nodes defined by content types.
@@ -769,7 +925,7 @@ function node_reference_options_list($fi
   // @todo Support optgroups ? I think this was added in late CCK D6.
   $options = array();
   foreach ($references as $key => $value) {
-    $options[$key] = $value['title'];
+    $options[$key] = $value['rendered'];
   }
 
   return $options;
@@ -827,3 +983,32 @@ function node_reference_content_migrate_
       break;
   }
 }
+
+/**
+ * Create a display title for a view display.
+ */
+function node_reference_views_display_title($view_name, $view, $display) {
+  // Build the display title.
+  if (isset($view->display[$display]->display_options['title'])) {
+    // This view display has a nice title, let's use that.
+    return $view->display[$display]->display_options['title'];
+  }
+  elseif (isset($view->display['default']->display_options['title'])) {
+    // This view display inherits it's title from the default display.
+    return $view->display['default']->display_options['title'];
+  }
+  else {
+    // This view display does not have a title configured, we have to construct a title.
+    return ucfirst($view_name) . ' ' . strtolower($view->display[$display]->display_title);
+  }
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function node_reference_views_api() {
+  return array(
+    'api' => 3,
+    'path' => drupal_get_path('module', 'node_reference') . '/includes',
+  );
+}
\ No newline at end of file
Index: node_reference/includes/node_reference.views.inc
===================================================================
RCS file: node_reference/includes/node_reference.views.inc
diff -N node_reference/includes/node_reference.views.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ node_reference/includes/node_reference.views.inc	12 Dec 2010 05:10:10 -0000
@@ -0,0 +1,46 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Interface between node_reference.module and views.module.
+ */
+
+/**
+ * Implements hook_views_plugins().
+ *
+ * Defines some plugins used by the Views modes for
+ * node_reference.
+ */
+function node_reference_views_plugins() {
+  $plugins = array(
+    'module' => 'node_reference', // This just tells our themes are elsewhere.
+    'display' => array(
+      'node_reference_views_plugin_display' => array(
+        'path' => drupal_get_path('module', 'node_reference') . '/includes',
+        'title' => 'Node reference',
+        'help' => 'Destination-agnostic display. Mostly useful for programmatic views.',
+        'handler' => 'node_reference_views_plugin_display',
+        'no ui' => TRUE, // Programmatic use only.
+        'uses hook menu' => FALSE,
+        'use ajax' => FALSE,
+        'use pager' => FALSE,
+        'accept attachments' => FALSE,
+      ),
+    ),
+    'style' => array(
+      'node_reference_views_plugin_style' => array(
+        'path' => drupal_get_path('module', 'node_reference') . '/includes',
+        'title' => 'Results array (with title)',
+        'help' => 'Returns the view as a PHP array of names + rendered rows.',
+        'handler' => 'node_reference_views_plugin_style',
+        'no ui' => TRUE, // Programmatic use only.
+        'uses row plugin' => TRUE,
+        'uses fields' => TRUE,
+        'type' => 'normal',
+        'even empty' => TRUE,
+      ),
+    ),
+  );
+  return $plugins;
+}
\ No newline at end of file
Index: node_reference/includes/node_reference_views_plugin_display.inc
===================================================================
RCS file: node_reference/includes/node_reference_views_plugin_display.inc
diff -N node_reference/includes/node_reference_views_plugin_display.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ node_reference/includes/node_reference_views_plugin_display.inc	12 Dec 2010 05:10:10 -0000
@@ -0,0 +1,49 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Handler for node_reference_views_plugin_display.
+ */
+class node_reference_views_plugin_display extends views_plugin_display {
+  function execute() {
+    return $this->view->render($this->display->id);
+  }
+
+  function render() {
+    return !empty($this->view->result) || !empty($this->view->style_plugin->definition['even empty']) ? $this->view->style_plugin->render($this->view->result) : '';
+  }
+
+  function uses_exposed() {
+    return FALSE;
+  }
+
+  function query() {
+    $options = $this->get_option('node_reference_options');
+
+    if ($options['string'] !== '') {
+      $like = $GLOBALS["db_type"] == 'pgsql' ? "ILIKE" : "LIKE";
+      $match_clauses = array(
+        'contains' => array(
+          'operator' => $like,
+          'value' => '%' . $options['string'] . '%',
+        ),
+        'equals' => array(
+          'operator' => '=',
+          'value' => $options['string'],
+        ),
+        'starts_with' => array(
+          'operator' => $like,
+          'value' => $options['string'] . '%',
+        ),
+      );
+      $clause = isset($match_clauses[$options['match']]) ? $match_clauses[$options['match']] : $match_clauses['contains'];
+      $alias = $this->view->query->ensure_table($options['table']);
+      $this->view->query->add_where(NULL, "$alias.$options[field_string]", $clause['value'], $clause['operator']);
+    }
+    elseif ($options['ids']) {
+      $alias = $this->view->query->ensure_table($options['table']);
+      $this->view->query->add_where(NULL, "$alias.$options[field_id]", $options['ids'], 'IN');
+    }
+  }
+}
\ No newline at end of file
Index: node_reference/includes/node_reference_views_plugin_style.inc
===================================================================
RCS file: node_reference/includes/node_reference_views_plugin_style.inc
diff -N node_reference/includes/node_reference_views_plugin_style.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ node_reference/includes/node_reference_views_plugin_style.inc	12 Dec 2010 05:10:10 -0000
@@ -0,0 +1,34 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Handler for node_reference_views_plugin_style.
+ */
+class node_reference_views_plugin_style extends views_plugin_style {
+  function render() {
+    $results = array();
+
+    // Group the rows according to the grouping field, if specified.
+    $sets = $this->render_grouping($this->view->result, $this->options['grouping']);
+
+    $base_field = $this->view->base_field;
+    $title_field = $this->display->display_options['node_reference_title_field'];
+    $title_field_alias = $this->view->field[$title_field]->field_alias;
+
+    // TODO : We don't display grouping info for now.
+    // Could be useful for select widget, though.
+    $this->view->row_index = 0;
+    foreach ($sets as $title => $records) {
+      foreach ($records as $label => $row) {
+        $results[$row->{$base_field}] = array(
+          'title' => check_plain($row->{$title_field_alias}),
+          'rendered' => $this->row_plugin->render($row),
+        );
+        $this->view->row_index++;
+      }
+    }
+    unset($this->view->row_index);
+    return $results;
+  }
+}
Index: user_reference/user_reference.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/references/user_reference/user_reference.info,v
retrieving revision 1.1
diff -u -p -r1.1 user_reference.info
--- user_reference/user_reference.info	6 Dec 2010 21:28:17 -0000	1.1
+++ user_reference/user_reference.info	12 Dec 2010 05:10:10 -0000
@@ -2,5 +2,8 @@
 name = User Reference
 description = Defines a field type for referencing a user from a node.
 files[]=user_reference.module
+files[]=includes/user_reference.views.inc
+files[]=includes/user_reference_views_plugin_display.inc
+files[]=includes/user_reference_views_plugin_style.inc
 package = CCK
-core = 7.x
+core = 7.x
\ No newline at end of file
Index: user_reference/user_reference.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/references/user_reference/user_reference.module,v
retrieving revision 1.1
diff -u -p -r1.1 user_reference.module
--- user_reference/user_reference.module	6 Dec 2010 21:28:17 -0000	1.1
+++ user_reference/user_reference.module	12 Dec 2010 05:10:11 -0000
@@ -24,15 +24,25 @@ function user_reference_menu() {
  * Implements hook_field_info().
  */
 function user_reference_field_info() {
-  return array(
+  $field_info = array(
     'user_reference' => array(
       'label' => t('User reference'),
       'description' => t('This field stores the ID of a related user as an integer value.'),
-      'settings' => array('referenceable_roles' => array(), 'referenceable_status' => array()),
+      'settings' => array(
+        'referenceable_roles' => array(),
+        'referenceable_status' => array(),
+      ),
       'default_widget' => 'user_reference_autocomplete',
       'default_formatter' => 'user_reference_default',
     ),
   );
+  if (module_exists('views')) {
+    $field_info['user_reference']['settings']['views'] = array(
+      'view' => '',
+      'view_args' => '',
+    );
+  }
+  return $field_info;
 }
 
 /**
@@ -83,6 +93,62 @@ function user_reference_field_settings_f
     '#options' => array(1 => t('Active'), 0 => t('Blocked')),
     '#disabled' => $has_data,
   );
+  if (module_exists('views')) {
+    $views = array('' => '<' . t('none') . '>');
+    $all_views = views_get_all_views();
+
+    foreach ($all_views as $view_name => $view) {
+      // Only 'node' views that have fields will work for our purpose.
+      if ($view->base_table == 'users') {
+        foreach ((array)$view->display as $display_key => $display) {
+          $id = $view_name . ':' . $display_key;
+          // Get display title.
+          $display_title = user_reference_views_display_title($view_name, $view, $display_key);
+          // Append $id to the title for disambiguation in lists.
+          $display_title .= ' ['. $id . ']';
+
+          if ($view->type == 'Default') {
+            $views[t('Default views')][$id] = $display_title;
+          }
+          else {
+            $views[t('Existing views')][$id] = $display_title;
+          }
+        }
+      }
+    }
+
+    $form['views'] = array(
+       '#type' => 'fieldset',
+       '#title' => t('Views - Users that can be referenced'),
+       '#collapsible' => TRUE,
+       '#collapsed' => !isset($settings['views']['view']) || $settings['views']['view'] == '',
+     );
+    if (count($views) > 1) {
+      $form['views']['view'] = array(
+        '#type' => 'select',
+        '#title' => t('View used to select the users'),
+        '#options' => $views,
+        '#default_value' => isset($settings['views']['view']) ? $settings['views']['view'] : '',
+        '#description' =>  t('<p>Choose the "Views module" view that selects the users that can be referenced.<br />Note:</p>') .
+          t('<ul><li>This will discard the "Referenceable Roles" and "Referenceable Status" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate users on user creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate users will be displayed.</li></ul>'),
+        '#disabled' => $has_data,
+      );
+      $form['views']['view_args'] = array(
+        '#type' => 'textfield',
+        '#title' => t('View arguments'),
+        '#default_value' => isset($settings['views']['view_args']) ? $settings['views']['view_args'] : '',
+        '#required' => FALSE,
+        '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
+        '#disabled' => $has_data,
+      );
+    }
+    else {
+      $form['views']['no_view_help'] = array(
+        '#value' => t('<p>The list of user that can be referenced can be based on a "Views module" view but no appropriate views were found. <br />Note:</p>') .
+          t('<ul><li>This will discard the "Referenceable Roles" and "Referenceable Status" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate users on user creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate users will be displayed.</li></ul>'),
+      );
+    }
+  }
   return $form;
 }
 
@@ -420,7 +486,14 @@ function _user_reference_potential_refer
     . ($string !== '' ? $string : implode('-', $ids))
     . ':' . $limit;
   if (!isset($results[$cid])) {
-    $references = _user_reference_potential_references_standard($field, $string, $match, $ids, $limit);
+    $references = FALSE;
+    if (module_exists('views') && !empty($field['settings']['views']['view'])) {
+      $references = _user_reference_potential_references_views($field, $string, $match, $ids, $limit);
+    }
+
+    if ($references === FALSE) {
+      $references = _user_reference_potential_references_standard($field, $string, $match, $ids, $limit);
+    }
 
     // Store the results.
     $results[$cid] = !empty($references) ? $references : array();
@@ -432,6 +505,91 @@ function _user_reference_potential_refer
 /**
  * Helper function for _user_reference_potential_references().
  *
+ * Case of Views-defined referenceable users.
+ */
+function _user_reference_potential_references_views($field, $string = '', $match = 'contains', $ids = array(), $limit = NULL) {
+  $view_id = $field['settings']['views']['view'];
+  list($view_name, $view_display) = explode(':', $view_id);
+
+  if ($view = views_get_view($view_name)) {
+
+    // We add a display, and let it derive from the 'default' display.
+    $display = $view->add_display('user_reference_views_plugin_display');
+    $view->set_display($display);
+
+    // Get the options from the user supplied display.
+    if ($view_display != 'default' && isset($view->display[$view_display]->display_options)) {
+      $view->display[$display]->display_options = $view->display[$view_display]->display_options;
+    }
+
+    // TODO from merlinofchaos on IRC : arguments using summary view can defeat the style setting.
+    // We might also need to check if there's an argument, and set *its* style_plugin as well.
+    $view->display_handler->set_option('style_plugin', 'user_reference_views_plugin_style');
+    $view->display_handler->set_option('row_plugin', 'fields');
+    // Used in user_reference_views_plugin_style::render(), to get
+    // the 'field' to be used as title.
+    $view->display_handler->set_option('user_reference_title_field', 'name');
+
+    // Additional options to let user_reference_views_plugin_display::query()
+    // narrow the results.
+    $options = array(
+      'table' => 'users',
+      'field_string' => 'name',
+      'string' => $string,
+      'match' => $match,
+      'field_id' => 'uid',
+      'ids' => $ids,
+    );
+    $view->display_handler->set_option('user_reference_options', $options);
+
+    // TODO : for consistency, a fair amount of what's below
+    // should be moved to user_reference_views_plugin_display
+
+    // Limit result set size.
+    $limit = isset($limit) ? $limit : 0;
+    $view->display_handler->set_option('items_per_page', $limit);
+
+    // Get arguments for the view.
+    if (!empty($field['settings']['views']['view_args'])) {
+      // TODO: Support Tokens using token.module ?
+      $view_args = array_map('trim', explode(',', $field['settings']['views']['view_args']));
+    }
+    else {
+      $view_args = array();
+    }
+
+    // We do need name field, so add it if not present (unlikely, but...)
+    $fields = $view->get_items('field', $display);
+    if (!isset($fields['name'])) {
+      $view->add_item($display, 'field', 'users', 'name');
+    }
+
+    // If not set, make all fields inline and define a separator.
+    $options = $view->display_handler->get_option('row_options');
+    if (empty($options['inline'])) {
+      $options['inline'] = drupal_map_assoc(array_keys($view->get_items('field', $display)));
+    }
+    if (empty($options['separator'])) {
+      $options['separator'] = '-';
+    }
+    $view->display_handler->set_option('row_options', $options);
+
+    // Make sure the query is not cached
+    $view->is_cacheable = FALSE;
+
+    // Get the results.
+    $result = $view->execute_display($display, $view_args);
+  }
+  else {
+    $result = FALSE;
+  }
+
+  return $result;
+}
+
+/**
+ * Helper function for _user_reference_potential_references().
+ *
  * List of referenceable users defined by user role and status.
  */
 function _user_reference_potential_references_standard($field, $string = '', $match = 'contains', $ids = array(), $limit = NULL) {
@@ -525,7 +683,7 @@ function user_reference_options_list($fi
   // @todo Support optgroups ? I think this was added in late CCK D6.
   $options = array();
   foreach ($references as $key => $value) {
-    $options[$key] = $value['title'];
+    $options[$key] = $value['rendered'];
   }
 
   return $options;
@@ -662,4 +820,33 @@ function user_reference_content_migrate_
       }
       break;
   }
+}
+
+/**
+ * Create a display title for a view display.
+ */
+function user_reference_views_display_title($view_name, $view, $display) {
+  // Build the display title.
+  if (isset($view->display[$display]->display_options['title'])) {
+    // This view display has a nice title, let's use that.
+    return $view->display[$display]->display_options['title'];
+  }
+  elseif (isset($view->display['default']->display_options['title'])) {
+    // This view display inherits it's title from the default display.
+    return $view->display['default']->display_options['title'];
+  }
+  else {
+    // This view display does not have a title configured, we have to construct a title.
+    return ucfirst($view_name) . ' ' . strtolower($view->display[$display]->display_title);
+  }
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function user_reference_views_api() {
+  return array(
+    'api' => 3,
+    'path' => drupal_get_path('module', 'user_reference') . '/includes',
+  );
 }
\ No newline at end of file
Index: user_reference/includes/user_reference.views.inc
===================================================================
RCS file: user_reference/includes/user_reference.views.inc
diff -N user_reference/includes/user_reference.views.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ user_reference/includes/user_reference.views.inc	12 Dec 2010 05:10:11 -0000
@@ -0,0 +1,46 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Interface between user_reference.module and views.module.
+ */
+
+/**
+ * Implements hook_views_plugins().
+ *
+ * Defines some plugins used by the Views modes for
+ * user_reference.
+ */
+function user_reference_views_plugins() {
+  $plugins = array(
+    'module' => 'user_reference', // This just tells our themes are elsewhere.
+    'display' => array(
+      'user_reference_views_plugin_display' => array(
+        'path' => drupal_get_path('module', 'user_reference') . '/includes',
+        'title' => 'User reference',
+        'help' => 'Destination-agnostic display. Mostly useful for programmatic views.',
+        'handler' => 'user_reference_views_plugin_display',
+        'no ui' => TRUE, // Programmatic use only.
+        'uses hook menu' => FALSE,
+        'use ajax' => FALSE,
+        'use pager' => FALSE,
+        'accept attachments' => FALSE,
+      ),
+    ),
+    'style' => array(
+      'user_reference_views_plugin_style' => array(
+        'path' => drupal_get_path('module', 'user_reference') . '/includes',
+        'title' => 'Results array (with title)',
+        'help' => 'Returns the view as a PHP array of names + rendered rows.',
+        'handler' => 'user_reference_views_plugin_style',
+        'no ui' => TRUE, // Programmatic use only.
+        'uses row plugin' => TRUE,
+        'uses fields' => TRUE,
+        'type' => 'normal',
+        'even empty' => TRUE,
+      ),
+    ),
+  );
+  return $plugins;
+}
\ No newline at end of file
Index: user_reference/includes/user_reference_views_plugin_display.inc
===================================================================
RCS file: user_reference/includes/user_reference_views_plugin_display.inc
diff -N user_reference/includes/user_reference_views_plugin_display.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ user_reference/includes/user_reference_views_plugin_display.inc	12 Dec 2010 05:10:11 -0000
@@ -0,0 +1,49 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Handler for user_reference_views_plugin_display.
+ */
+class user_reference_views_plugin_display extends views_plugin_display {
+  function execute() {
+    return $this->view->render($this->display->id);
+  }
+
+  function render() {
+    return !empty($this->view->result) || !empty($this->view->style_plugin->definition['even empty']) ? $this->view->style_plugin->render($this->view->result) : '';
+  }
+
+  function uses_exposed() {
+    return FALSE;
+  }
+
+  function query() {
+    $options = $this->get_option('user_reference_options');
+
+    if ($options['string'] !== '') {
+      $like = $GLOBALS["db_type"] == 'pgsql' ? "ILIKE" : "LIKE";
+      $match_clauses = array(
+        'contains' => array(
+          'operator' => $like,
+          'value' => '%' . $options['string'] . '%',
+        ),
+        'equals' => array(
+          'operator' => '=',
+          'value' => $options['string'],
+        ),
+        'starts_with' => array(
+          'operator' => $like,
+          'value' => $options['string'] . '%',
+        ),
+      );
+      $clause = isset($match_clauses[$options['match']]) ? $match_clauses[$options['match']] : $match_clauses['contains'];
+      $alias = $this->view->query->ensure_table($options['table']);
+      $this->view->query->add_where(NULL, "$alias.$options[field_string]", $clause['value'], $clause['operator']);
+    }
+    elseif ($options['ids']) {
+      $alias = $this->view->query->ensure_table($options['table']);
+      $this->view->query->add_where(NULL, "$alias.$options[field_id]", $options['ids'], 'IN');
+    }
+  }
+}
\ No newline at end of file
Index: user_reference/includes/user_reference_views_plugin_style.inc
===================================================================
RCS file: user_reference/includes/user_reference_views_plugin_style.inc
diff -N user_reference/includes/user_reference_views_plugin_style.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ user_reference/includes/user_reference_views_plugin_style.inc	12 Dec 2010 05:10:11 -0000
@@ -0,0 +1,34 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Handler for user_reference_views_plugin_style.
+ */
+class user_reference_views_plugin_style extends views_plugin_style {
+  function render() {
+    $results = array();
+
+    // Group the rows according to the grouping field, if specified.
+    $sets = $this->render_grouping($this->view->result, $this->options['grouping']);
+
+    $base_field = $this->view->base_field;
+    $title_field = $this->display->display_options['user_reference_title_field'];
+    $title_field_alias = $this->view->field[$title_field]->field_alias;
+
+    // TODO : We don't display grouping info for now.
+    // Could be useful for select widget, though.
+    $this->view->row_index = 0;
+    foreach ($sets as $title => $records) {
+      foreach ($records as $label => $row) {
+        $results[$row->{$base_field}] = array(
+          'title' => $row->{$title_field_alias},
+          'rendered' => $this->row_plugin->render($row),
+        );
+        $this->view->row_index++;
+      }
+    }
+    unset($this->view->row_index);
+    return $results;
+  }
+}
