diff --git a/project.module b/project.module
index 72d30e5..51a3d5c 100644
--- a/project.module
+++ b/project.module
@@ -397,3 +397,83 @@ function project_maintainer_project_load($nid) {
 
   return $maintainers;
 }
+
+
+/**
+ * Returns an array of all projects on the system for use with select
+ * form elements. The keys are the project nid, and the values are
+ * the project names. The array will be sorted into the proper catagories
+ * with headers for each term, based the node types of the projects.
+ *
+ * @param $project_urls
+ *   Reference to be filled with an array of project uri => id mappings. This
+ *   array is used by the project_issue and project_release search form code.
+ * @param $issues
+ *   If TRUE, only projects with issue tracking  enabled are returned.
+ *   For this option to do much good, the project_issue module should be
+ *   enabled.
+ * @param $key_prefix
+ *   Prefix to prepend to all keys in the returned array. @TODO is this ever used ?
+ * @param string $include_sandbox
+ *   Should sandboxes be included in the listing? Can be either 'no_sandboxes'
+ *   (exclude sandboxes from the list, the default), 'include_sandboxes'
+ *   (include sandboxes) , 'only_sandboxes' (only show sandboxes).
+ */
+function project_projects_select_options(&$project_urls, $issues = TRUE, $key_prefix = NULL, $include_sandbox = 'no_sandboxes') {
+  $projects = array();
+
+  $project_entity_types = project_project_entity_bundles();
+  if ( empty($project_entity_types) ) {
+    // If there are no project entity types, just return the empty array here.
+    return $projects;
+  }
+
+  // @TODO Should this query pull from more tables than nodes ?  Should a project_issue
+  // be able to be attached to a user ?
+  $query = db_select('node','n')->fields('n',array('nid','title','type'));
+
+  $types = array();
+  foreach( $project_entity_types as $id => $project_entity_type ) {
+    $types[] = $project_entity_type;
+  }
+  $query->condition('type', $types, 'IN');
+
+  switch ($include_sandbox) {
+    case 'no_sandboxes':
+      $query->innerJoin('field_data_field_project_type', 'fdfpt', 'n.nid = fdfpt.entity_id');
+      $query->fields('fdfpt', array('field_project_type_value'));
+      $query->condition( 'fdfpt.field_project_type_value', 'full', '=' );
+      break;
+
+    case 'only_sandboxes':
+      $query->innerJoin('field_data_field_project_type', 'fdfpt', 'n.nid = fdfpt.entity_id');
+      $query->fields('fdfpt', array('field_project_type_value'));
+      $query->condition( 'fdfpt.field_project_type_value', 'sandbox', '=' );
+      break;
+
+    case 'include_sandboxes':
+    default:
+      // Otherwise, ignore sandboxes entirely.
+      break;
+  }
+
+  $query->orderBy('type','DESC');  // This is used to group the projects.
+
+  // Handle the $issues argument - check that "Enable issue tracker" is TRUE.
+  if ($issues && module_exists('project_issue')) {
+    $query->innerJoin('field_data_field_project_has_issue_queue', 'fdfphiq', 'n.nid = fdfphiq.entity_id');
+    $query->fields('fdfphiq', array('field_project_has_issue_queue_value'));
+    $query->condition( 'fdfphiq.field_project_has_issue_queue_value', '1', '=' );
+  }
+
+  $result = $query->execute();
+  foreach ($result as $project) {
+    $projects[$key_prefix . $project->nid] = $project->title;
+    if (is_array($project_urls)) {
+      $uri = drupal_lookup_path('alias','node/'.$project->nid);
+      $project_urls[$uri] = $project->nid;
+    }
+  }
+  return $projects;
+}
+
