I'm trying to customise the top-left quicksearch box so that it recognises some of our internal codes without selecting a specific option in the dropdown.

I used to adapt xavier's great Quick Contact Autocomplete extension, but this uses the crmAutocomplete action which I think went away in 4.5.

Is there a particular recommended way of doing this in 4.5+?

  • What are your internal codes? Custom fields? External identifier core field? Or... ? – Coleman Jul 17 '15 at 14:30
  • External identifier, plus a custom field that's always in a specific format. I taught xavier's extension to recognise the format and fall back to a regular search if not - just trying to replicate that really. Just wanted to save our admin team a couple of clicks on each search. – Andrew West Jul 17 '15 at 14:34

For customizing the list of options, see this question.

To override the quicksearch behavior, you could try hook_civicrm_apiWrappers to modify the output of the contact.getquick api.


I found it quite hard to replace the customization done with hook_civicrm_contactListQuery (CiviCRM <= 4.4) with the new hook_civicrm_apiWrappers (CiviCRM >= 4.5).

So I am sharing my results here.

My goal is to have a way to search quickly either by contact name, or by a custom field that stores a member identifier (different from internal identifier and external identifier).

My old code looked like this :

function myext_civicrm_contactListQuery( &$query, $name, $context, $id ) {
  if ($context == 'navigation') {
    // if not name / email search, just keep the standard behavior
    if (!isset($_GET['tableName']) || $_GET['tableName'] != 'cc') return;

    // if the search is a number, try to look for the custom member id
    if (is_numeric($name)) {
      $query = "SELECT cc.id as id, CONCAT_WS( ' :: ', CONCAT(sort_name, ' (', im.num_ro_de_membre_37, ')') ) as data, sort_name
                FROM civicrm_contact cc
                LEFT JOIN civicrm_value_r_sum_de_membre_6 im ON ( cc.id = im.entity_id ) 
                WHERE im.num_ro_de_membre_37 = '$name'
                AND cc.is_deleted = 0
                LIMIT 5";

    } elseif (strlen($name) < 2) {
      $query = "";


And now :

function myext_civicrm_apiWrappers(&$wrappers, $apiRequest) {
  if ($apiRequest['entity'] == 'Contact' && $apiRequest['action'] == 'getquick') {

    // search by member id if the search is a numeric value
    if (is_numeric($apiRequest['params']['name'])) {
      $wrappers[] = new CRM_Myext_APIWrapper();

// i need to do this because there is no function civicrm_api3_contact_getlist
function emulate_civicrm_api3_contact_getList($params) {

  // not loaded by default
  include_once "api/v3/Generic/Getlist.php";
  include_once "api/v3/utils.php";

  $apiRequest = array(
    'entity' => 'Contact',
    'action' => 'getlist',
    'params' => $params,
  $res = civicrm_api3_generic_getList($apiRequest);

  // reformat the output to look like getquick
  foreach ($res['values'] as $idx => $value) {
    $res['values'][$idx]['data'] = $value['extra']['sort_name'] . " ({$value['extra']['custom_37']})";

  return $res;

And a new APIWrapper class in a dir CRM/Myext/APIWrapper.php :

class CRM_Myext_APIWrapper implements API_Wrapper {

  public function fromApiInput($apiRequest) {

    // change api call - getquick is deprecated and doesn't work with custom field
    $apiRequest['entity'] = 'Contact';
    $apiRequest['action'] = 'getlist';
    $apiRequest['function'] = 'emulate_civicrm_api3_contact_getList';

    // change name param to field custom_37 and remove useless params
    $apiRequest['params']['params']['custom_37'] = $apiRequest['params']['name'];

    // restrict return data (getlist doesn't use return param)
    $apiRequest['params']['extra'] = array('sort_name','custom_37');

    return $apiRequest;


Based on @samuelsov answer and samples I've developed an extension that could customize the quicksearch fields

More info here: https://civicrm.org/extensions/quicksearch

Your Answer

