I'm using entityreference and have an issue I've fixed in an improper way. I was hoping you could take a look at the fix and offer a better solution.

Statement of Problem

Using entityreference autocomplete widget, I was seeing results that were sorted in alphabetical order. However, a lot of my node have the same word in the title, so I could not find the node I was looking for.

Example: I would type _code_ looking for the node titled _Code_, but would not see it in my autocomplete results. This is because more than 10 node titles contained the word _code_ in them and were alphabetically before list because I more than 10 nodes the contained the word _code_ in them, but came before _Code_. See the list below for an illustration of what was being displayed.

* A Backwards Look at Coding Practices
* A Code to Get you through the door
* A Sample of Ruby Code to fix the down days
* Be the Coda Coder
* By using Code you can do amazing things
* Coda Coder Tips Part 1
* Coda Coder Tips Part 2
* Coda Coder Tips Part 3
* Coda Coder Tips Part 4
* Coda Coder Tips Part 5

Notice that the node titled _Code_ does not appear in the list, since alphabetically it comes after everything else in the list.

Improper Fix

To fix this I removed the limit when getting $entity_labels,
moved labels that start with the search term ($tag_last) to the top of the list,
grabbed the first 10 from the resort array of labels.

diff --git a/dev.gaspy.com/sites/all/modules/entityreference/entityreference.module b/dev.gaspy.com/sites/all/modules/entityreference/entityreference.module
index 170ac8c..9c04369 100644
--- a/dev.gaspy.com/sites/all/modules/entityreference/entityreference.module
+++ b/dev.gaspy.com/sites/all/modules/entityreference/entityreference.module
@@ -820,8 +820,22 @@ function entityreference_autocomplete_callback($type, $field_name, $entity_type,
 
   if (!empty($tag_last)) {
     // Get an array of matching entities.
-    $entity_labels = $handler->getReferencableEntities($tag_last, $instance['widget']['settings']['match_operator'], 10);
-
+    $entity_labels = $handler->getReferencableEntities($tag_last, $instance['widget']['settings']['match_operator']);
+    $sorted_labels = array();
+    
+    foreach($entity_labels as $entity_id => $label) {
+      if(stripos(preg_replace('/\s\s+/', ' ', $label), $tag_last) === 0) {
+        $sorted_labels[$entity_id] = $label;
+      }
+    }
+    
+    foreach($entity_labels as $entity_id => $label) {
+      if(stripos(preg_replace('/\s\s+/', ' ', $label), $tag_last) > 0) {
+        $sorted_labels[$entity_id] = $label;
+      }
+    }
+    $entity_labels = array_slice($sorted_labels, 0, 10, true);
+    
     // Loop through the products and convert them into autocomplete output.
     foreach ($entity_labels as $entity_id => $label) {
       $key = "$label ($entity_id)";

Comments

mstrelan’s picture

Without hacking entityreference I'm sorting by:

  1. Position of search term in node title
  2. Length of title (ie. relevance of search term to the overall title)
  3. Title (alphabetical)

To do this you must use Views to perform the lookup. Then in a custom module for sorting add the following code.

<?php
/**
 * Implements hook_views_pre_execute().
 */
function MYMODULE_views_pre_execute(&$view) {
  if ($view->name == 'MYVIEW') {
    $query = $view->build_info['query'];

    $orderBy = &$query->getOrderBy();
    $arguments =& $query->getArguments();
    $orderBy = array();

    // Order first by position of term in the title.
    $term = trim($arguments[':db_condition_placeholder_0'], '%');
    $query->addExpression('LOCATE(:term, node.title)', 'node_title_locate', array(':term' => $term));
    $query->orderBy('node_title_locate');

    // Order second by length of the title (eg. Research vs Calling all research students).
    $query->addExpression('LENGTH(node.title)', 'node_title_length');
    $query->orderBy('node_title_length');

    // Finally order by node title.
    $query->orderBy('node_title');
  }
}
?>