I'm working with a direct mail company on a donation campaign. They plan on including the contact ID on the top of the donation tear off. Then when we manually enter the donation we're be able to search by contact ID, avoiding possible duplicates. This is the way they always do it for efficiency.

There's several you can already add under "Search Preferences" but not the contact ID.

Is it possible to just manually add it to the database?



I needed to do something similar. There were two things to work on: getting the Contact ID in the search suggestion in the quick search and getting CiviCRM to search the Contact Id by default when placing a number in the quick/regular search and hitting enter.

Note: I just adapted my code to work with contact ID, didn't test it.

I used a CiviCRM extension with the queryObjects hook:


// Get the Contact ID to display in the suggestions
function extname_civicrm_apiWrappers(&$wrappers, $apiRequest) {
   if ($apiRequest['entity'] == 'Contact') {
      if ($apiRequest['action'] == 'getquick') {
          $wrappers[] = new CRM_Extname_APIWrapper_GetQuick();

function emulate_civicrm_api3_contact_getList($params) {

    $res = civicrm_api3('Contact','get', $params);

    // reformat the output to look like getquick
    foreach ($res['values'] as $idx => &$value) {
        $value['data'] = $value['id'].' :: '.$value['sort_name'] . ( empty($value['nick_name']) ? '' : ' ('.$value['nick_name'].')' );
        foreach (['street_address','city','state_province_name','postal_code','phone','email'] as $col) {
            if (!empty($value[$col])) $value['data'] .= ' :: '.$value[$col];

    return $res;

// Get the id to be part of the default search
function extname_civicrm_queryObjects (&$queryObjects, $type = 'Contact') {
    if ($type == 'Contact') {
        $queryObjects[] = new CRM_Extname_BAO_Query();

[myext]/CRM/Extname/APIWrapper/GetQuick.php clas

s CRM_Extname_APIWrapper_GetQuick implements API_Wrapper {

  public function fromApiInput($apiRequest) {

        if (!empty($apiRequest['params']['field_name'])) return $apiRequest;

        $apiRequest['entity'] = 'Contact';
        $apiRequest['action'] = 'getlist';
        $apiRequest['function'] = 'emulate_civicrm_api3_contact_getList';

        $apiRequest['params']['sequential'] = '1';
        $apiRequest['params']['nick_name'] = $apiRequest['params']['id'] = $apiRequest['params']['name'];


        return $apiRequest;

  // this never seems called
  public function toApiOutput($apiRequest, $result) {

      return $result;



class CRM_Extname_BAO_Query extends CRM_Contact_BAO_Query_Interface {

    function &getFields() {
        return ['id'];

    function from($name, $mode, $side) {
        return '';

    function where(&$query) {

        $grouping = NULL;
        foreach (array_keys($query->_params) as $id) {
            if (empty($query->_params[$id][0])) {

            $this->whereClauseSingle($query->_params[$id], $query);         


    function whereClauseSingle(&$values, &$query) {
        list($name, $op, $value, $grouping, $wildcard) = $values;

        $fields = $this->getFields();
        if (!empty($value) && !is_array($value)) {
          $quoteValue = "\"$value\"";

        // Look in CRM_Contact_BAO_Query:2025 for how this is all gatherered into or's and ands

        switch ($name) {
          case 'sort_name': 
            // the default search is grouping=0; this is pretty hard coded into CRM_Contact_BAO_Query
            if ($grouping==0) {
                foreach ($query->_where[$grouping] as $key => $val) {
                    if (strpos($query->_where[$grouping][$key],'sort_name')===false) continue;
                    // search id if numeric
                    if (is_numeric($value)) {
                        $query->_qill[$grouping][$key] .= ' Or '.($value ? ts('Contact ID is '.$quoteValue) : ts('Contact ID is not '.$quoteValue));
                        $query->_where[$grouping][$key] .= ' OR '.CRM_Contact_BAO_Query::buildClause("contact_a.id", "=", (int)$value, "Int");


    public function getPanesMapper(&$panes) {

        return $panes;

  • David, i don't follow "getting the Contact ID in the search suggestion in the quick search" since civi already provides this. guess i am misunderstanding something in your answer that a tweak might help – petednz - fuzion Apr 11 '17 at 6:35
  • I didn't see contact id on the search preference. Is there another location to turn it on to display on the quick search suggestions? – David Hayes Apr 11 '17 at 17:08
  • what version civi you on? – petednz - fuzion Apr 11 '17 at 21:20
  • You should be seeing what is in screenshot here docs.civicrm.org/user/en/4.6/the-user-interface/searching – petednz - fuzion Apr 11 '17 at 21:22
  • 1
    4.7.x The code above would put the contact id in the quick search box suggestions here: imgur.com/a/tOWmz The other part makes it search the contact id by default when adding the contact ID to that box. – David Hayes Apr 11 '17 at 22:11

It helps if you mention the version you are on. In the Quick Search you should be able to see a setting when you click in there, to use Internal ID, then you can just enter the ID.

Personally I would make it even simpler if you have been sent a spreadsheet, or can get their data in a spreadsheet, and use the CONCATENATE function in your spreadsheet so you have a link from there to go directly to a link this this civicrm/contact/view/contribution?reset=1&action=add&cid=XXX&context=contribution where XXX is the Internal ID


You can add the contributions using Contact ID via the Import interface. Create a csv file with the contribution info and import it.

But for the long term, I think this would be a brilliant addition to the New Contribution > Select Contact or Batch Entry > Select Contact search parameters. When people mail a check, our paper receipts have a tear off portion at that bottom that they can use with their next contribution. We could have it print their Contact ID in that lower section and use it when doing the data entry just as Doug described and it should save on selecting the wrong donor with a similar name (or we have some with the same name).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.