|
Table of Contents
Goals and BackgroundThis documents how to extend CiviCRM to meet your needs. We are extending CiviCRM in a very similar manner to Drupal, primarily because based on our experience with Drupal's extension architecture, we think it is clean and non-intrusive, yet incredibly powerful. For a simple example module check civitest module See Drupal hook documentation for a description of how hooks are implemented. See the section on Joomla within this article for a description of how to implement hooks in Joomla. See CRM/Utils/Hook.php for CiviCRM for the source code that invokes these hooks. Procedures for implementing hooks (for Drupal)All your hook implementations should be collected within one or more modules, so to begin create a module:
name = PTSA Module description = Implement CiviCRM and Drupal hooks for PTSA dependencies[] = civicrm package = CiviCRM core = 6.x version = 2.2 Procedures for implementing hooks (for Joomla)
Note on setting and getting custom field values in hooksFor setting and getting custom field values in hooks, you need to know the field ID of the custom field(s) you want to work with. The easiest place to find these IDs is in the civicrm_custom_field table in the database. You'll then access these fields as "custom_ID". So if you have a field holding a custom value whose ID in the civicrm_custom_field table is 34, you'll use "custom_34" to access it. Once you have the ID(s), you'll want to use the setValues and getValues functions in the CRM/Core/BAO/CustomValueTable.php file. Here are a couple of examples of their use: Setting values (on a Contribution object's custom fields): $custom_fields = array('foo' => 'custom_1', 'bar' => 'custom_2');
function modulename_civicrm_pre ($op, objectName, $objectId, &$objectRef) {
if ($objectName != 'Contribution' || ($op != 'edit' && $op != 'create')) {
return;
}
$contribution_id = $objectId;
require_once 'CRM/Core/BAO/CustomValueTable.php';
$my_foo = 'blah';
$my_bar = 'baz';
$set_params = array('entityID' => $contribution_id,
$custom_fields['foo'] => $my_foo, $custom_fields['bar'] => $my_bar);
CRM_Core_BAO_CustomValueTable::setValues($set_params);
}
Getting values (from a Contribution's associated Contact object): $custom_fields = array('contact_foo' => 'custom_3', 'contact_bar' => 'custom_4');
function modulename_civicrm_pre ($op, objectName, $objectId, &$objectRef) {
if ($objectName != 'Contribution' || ($op != 'edit' && $op != 'create')) {
return;
}
// set the field names to 1 that we want to get back
$get_params = array('entityID' => $objectRef['contact_id'],
$custom_fields['contact_foo'] => 1, $custom_fields['contact_bar'] => 1);
require_once 'CRM/Core/BAO/CustomValueTable.php';
$values = CRM_Core_BAO_CustomValueTable::getValues($get_params);
$my_cfoo = $values[$custom_fields['contact_foo']];
$my_cbar = $values[$custom_fields['contact_bar']];
}
hook_civicrm_preDescriptionThis hook is called before a db write on some core objects. This hook does not allow the abort of the operation, use a form hook instead. We suspect the pre hook will be useful for developers building more complex applications and need to perform operations before CiviCRM takes action. This is very applicable when you need to maintain foreign key constraints etc (when deleting an object, the child objects have to be deleted first). Another good use for the pre hook is to see what is changing between the old and new data. Definitionhook_civicrm_pre( $op, $objectName, $objectId, &$objectRef ) Parameters
Returns
Examplehook_civicrm_postDescriptionThis hook is called after a db write on some core objects. pre and post hooks are useful for developers building more complex applications and need to perform operations before CiviCRM takes action. This is very applicable when you need to maintain foreign key constraints etc (when deleting an object, the child objects have to be deleted first). Definitionhook_civicrm_post( $op, $objectName, $objectId, &$objectRef ) Parameters
Returns
ExampleHere is a simple example that will send you an email whenever an INDIVIDUAL Contact is either Added, Updated or Deleted: Create a new folder called example_sendEmailOnIndividual in this directory /drupal_install_dir/sites/all/modules/civicrm/drupal/modules/ and then put the following two files in that directory (change the email addresses to yours). FILE #1 /drupal_install_dir/sites/all/modules/civicrm/drupal/modules/example_sendEmailOnIndividual/example_sendEmailOnIndividual.info name = Example Send Email On Individual
description = Example that will send an email when an Individual Contact is Added, Updated or Deleted.
dependencies[] = civicrm
package = CiviCRM
core = 6.x
version = 1.0
FILE #2 /drupal_install_dir/sites/all/modules/civicrm/drupal/modules/example_sendEmailOnIndividual/example_sendEmailOnIndividual.module <?php
function exampleSendEmailOnIndividual_civicrm_post($op, $objectName, $objectId, &$objectRef) {
/**************************************************************
* Send an email when Individual Contact is CREATED or EDITED or DELETED
*/
$send_an_email = false; //Set to TRUE for DEBUG only
$email_to = 'me@mydomain.com'; //TO email address
$email_from = 'me@mydomain.com'; //FROM email address
$email_sbj = 'CiviCRM exampleSendEmailOnIndividual';
$email_msg = "CiviCRM exampleSendEmailOnIndividual was called.\n".$op." ".$objectName."\n".$objectId." ";
if ($op == 'create' && $objectName == 'Individual') {
$email_sbj .= "- ADDED NEW contact";
$email_msg .= $objectRef->display_name."\n";
$send_an_email = true;
} else if ($op == 'edit' && $objectName == 'Individual') {
$email_sbj .= "- EDITED contact";
$email_msg .= $objectRef->display_name."\n";
$send_an_email = true;
} else if ($op == 'delete' && $objectName == 'Individual') {
$email_sbj .= "- DELETED contact";
$email_msg .= $objectRef->display_name."\n";
$email_msg .= 'Phone: '.$objectRef->phone."\n";
$email_msg .= 'Email: '.$objectRef->email."\n";
$send_an_email = true;
}
if ($send_an_email) {
mail($email_to, $email_sbj, $email_msg, "From: ".$email_from);
}
}//end FUNCTION
?>
Once the files are in the directory, you need to login to Drupal admin, go to Modules and enable our new module and click Save. Now go and edit a contact and you should get an email! hook_civicrm_linksDescriptionThese hooks are used to inject UI into CiviCRM pages such as the Contact Summary page. They are first implemented in CiviCRM version 1.5. Note: remember to use the string & url processing functions of your host framework ( url() and t() for Drupal ). Definitionhook_civicrm_links( $op, $objectName, $objectId ) Parameters
ReturnsExample/** * This hook retrieves links from other modules and injects it into * CiviCRM forms * * @param string $op the type of operation being performed * @param string $objectName the name of the object * @param int $objectId the unique identifier for the object * * @return array|null an array of arrays, each element is a tuple consisting of url, img, title * * @access public */ function MODULENAME_civicrm_links( $op, $objectName, $objectId ) { $links = array(); switch ($objectName) { case 'Contact': switch ($op) { case 'view.contact.activity': // Adds a link to the main tab. $links[] = array( 'id' => 'Mymoduleactions', 'title' => 'My Module Actions', 'url' => 'mymodule/civicrm/actions/'. $objectId, 'weight' => 10, ); break; } } return $links; } hook_civicrm_validateDescriptionValidation of forms Definitionhook_civicrm_validate( $formName, &$fields, &$files, &$form ) Parameters
Returnstrue if form validates successfully, otherwise array with error message strings Examplefunction MODULENAME_civicrm_validate( $formName, &$fields, &$files, &$form ) {
// sample implementation
$errors = array( );
if ( $formName == 'CRM_Contact_Form_Contact' ) {
// ensure that external identifier is present and valid
$externalID = CRM_Utils_Array::value( 'external_identifier', $fields );
if ( ! $externalID ) {
$errors['external_identifier'] = ts( 'External Identifier is a required field' );
} else if ( ! myCustomValidatorFunction( $externalID ) ) {
$errors['external_identifier'] = ts( 'External Identifier is not valid' );
}
}
return empty( $errors ) ? true : $errors;
}
function MYMODULE_civicrm_validate( $formName, &$fields, &$files, &$form ) {
$errors = array();
if ($formName == 'CRM_Contact_Form_Contact') {
foreach ($fields['address'] as $key => $address) {
//if country is set to UK or is empty, check for UK postcode formatting
if (empty($address['country_id']) || $address['country_id'] == 1226) {
$postcode = str_replace(' ', '', strtoupper($address['postal_code']));
$preg = "/^([A-PR-UWYZ]([0-9]([0-9]|[A-HJKSTUW])?|[A-HK-Y][0-9]([0-9]|[ABEHMNPRVWXY])?)[0-9][ABD-HJLNP-UW-Z]{2}|GIR0AA)$/";
$match = preg_match($preg, $postcode) ? true : false;
if (!$match) {
$errors['address[' . $key . '][postal_code]'] = ts('Postcode is not a valid UK postcode');
}
}
}
}
return empty($errors) ? true : $errors;
}
Beginning in CiviCRM 3.2, from within this hook, you can also manipulate validation errors set by CiviCRM. For example, to unset a validation error triggered by CiviCRM: $form->setElementError('some_field_name', NULL);
hook_civicrm_buildFormDescriptionThis hook is invoked when building a CiviCRM form. This hook should also Definitionhook_civicrm_buildForm( $formName, &$form ) ParametersExample/** * Set a default value for an event price set field. */ example_civicrm_buildForm($formName, &form) { if ($formName == 'CRM_Event_Form_Registration_Register') { $defaults['price_3'] = '710'; $form->setDefaults($defaults); } } hook_civicrm_postProcessDescriptionThis hook is invoked when a CiviCRM form is submitted. If the module has injected Definitionhook_civicrm_postProcess( $formName, &$form ) Parameters
Returns
Example<?php // drupalptsav2.module // Store last modified timestamp when user clicks SAVE button on a profile form. // Add a field called, e.g., "Last modified", to your profile form, and code it as // HTML "Date"; make it view only. I put mine at the end of the form, and // added a help field indictating that the field was set bv the program. function drupalptsav2_help( ) { switch ($section) { case 'admin/modules#description': // Put your module info here return t('Implements hooks for CiviCRM to customize the PTSA site'); default : return; } } function drupalptsav2_civicrm_postProcess( $formName, &$form ) { if ( is_a( $form, 'CRM_Profile_Form_Contact' ) ) { $gid = $form->getVar( '_gid' ); // Get your profile id from Administer CiviCRM >> Profile; I'm using 3 and 4 if ( $gid == 3 ) { // Need your profile # in the call to the edit routine, too! drupalptsav2_civicrm_postProcess_CRM_Profile_Form_Edit_3( $formName, $form, $gid ); return; } elseif ( $gid == 4 ) { // Need your profile # in the call to the edit routine, too! drupalptsav2_civicrm_postProcess_CRM_Profile_Form_Edit_4( $formName, $form, $gid ); return; } } } function drupalptsav2_civicrm_postProcess_CRM_Profile_Form_Edit_3( $formName, &$form, $gid ) { $userID = $form->getVar( '_id' ); // directory_info_fields_2 is the actual name of the sql record that holds my profile form // info. Go into phpMyAdmin or however you browse your sql database to get the name // (look at the civicrm_value schema). // You can do the same thing to get the field name (mine is last_modified_47). If you // have multiple fields named something similar, you can determine which field you're looking // for by viewing the source code of the Web page that displays your form. $query = " UPDATE civicrm_value_directory_info_fields_2 SET last_modified_47 = %1 WHERE entity_id = %2 "; $params = array( 1 => array( CRM_Utils_Date::getToday( null, 'YmdHis' ), 'Timestamp' ), 2 => array( $userID, 'Integer' )); CRM_Core_DAO::executeQuery( $query, $params ); } function drupalptsav2_civicrm_postProcess_CRM_Profile_Form_Edit_4( $formName, &$form, $gid ) { $userID = $form->getVar( '_id' ); $query = " UPDATE civicrm_value_volunteer_info_3 SET last_modified_65 = %1 WHERE entity_id = %2 "; $params = array( 1 => array( CRM_Utils_Date::getToday( null, 'YmdHis' ), 'Timestamp' ), 2 => array( $userID, 'Integer' )); CRM_Core_DAO::executeQuery( $query, $params ); } hook_civicrm_customDescriptionThis hook is called AFTER the db write on a custom table Definitionhook_civicrm_custom( $op, $groupID, $entityID, &$params ) Parameters
Returns
Example/**
* This example generates a custom contact ID (year + number, ex: 20080000001)
*/
function MODULENAME_civicrm_custom( $op, $groupID, $entityID, &$params ) {
if ( $op != 'create' && $op != 'edit' ) {
return;
}
if ($groupID == 1) {
$needs_update = false;
$tableName = CRM_Core_DAO::getFieldValue( 'CRM_Core_DAO_CustomGroup',
$groupID,
'table_name' );
$sql = "SELECT member_id_4 FROM $tableName WHERE entity_id = $entityID";
$dao = CRM_Core_DAO::executeQuery( $sql, CRM_Core_DAO::$_nullArray );
if (! $dao->fetch()) {
$needs_update = true;
}
// Value may also be empty. i.e. delete the value in the interface to reset the field.
if (! $dao->member_id_4) {
$needs_update = true;
}
if ($needs_update) {
$member_id = date('Y') . sprintf('%07d', $entityID);
$sql = "UPDATE $tableName SET member_id_4 = $member_id WHERE entity_id = $entityID";
CRM_Core_DAO::executeQuery( $sql, CRM_Core_DAO::$_nullArray );
}
}
}
hook_civicrm_aclWhereClauseDescriptionThis hook is called when composing the ACL where clause to restrict visibility of contacts to the logged in user. NB: This function will not be called at all if the logged in user has access to the "edit all contacts" permission. Definitionhook_civicrm_aclWhereClause( $type, &$tables, &$whereTables, &$contactID, &$where ) Parameters
Returns
Examplefunction civitest_civicrm_aclWhereClause( $type, &$tables, &$whereTables, &$contactID, &$where ) {
if ( ! $contactID ) {
return;
}
$permissionTable = 'civicrm_value_permission';
$regionTable = 'civicrm_value_region';
$fields = array( 'electorate' => 'Integer',
'province' => 'Integer',
'branch' => 'Integer' );
// get all the values from the permission table for this contact
$keys = implode( ', ', array_keys( $fields ) );
$sql = "
SELECT $keys
FROM {$permissionTable}
WHERE entity_id = $contactID
";
$dao = CRM_Core_DAO::executeQuery( $sql,
CRM_Core_DAO::$_nullArray );
if ( ! $dao->fetch( ) ) {
return;
}
$tables[$regionTable] = $whereTables[$regionTable] =
"LEFT JOIN {$regionTable} regionTable ON contact_a.id = regionTable.entity_id";
$clauses = array( );
foreach( $fields as $field => $fieldType ) {
if ( ! empty( $dao->$field ) ) {
if ( strpos( CRM_Core_DAO::VALUE_SEPARATOR, $dao->$field ) !== false ) {
$value = substr( $dao->$field, 1, -1 );
$values = explode( CRM_Core_DAO::VALUE_SEPARATOR, $value );
foreach ( $values as $v ) {
$clauses[] = "regionTable.{$field} = $v";
}
} else {
if ( $fieldType == 'String' ) {
$clauses[] = "regionTable.{$field} = '{$dao->$field}'";
} else {
$clauses[] = "regionTable.{$field} = {$dao->$field}";
}
}
}
}
if ( ! empty( $clauses ) ) {
$where .= ' AND (' . implode( ' OR ', $clauses ) . ')';
}
}
hook_civicrm_aclGroupDescriptionThis hook is called when composing the ACL to restrict access to civicrm entities (civicrm groups, profiles and events). NOTE: In order to use this hook you must uncheck "View All Contacts" AND "Edit All Contacts" in Drupal Permissions for the user role you want to limit. You can then go into CiviCRM and grant permission to Edit or View "All Contacts" or "Certain Groups". See the Forum Topic at: http://forum.civicrm.org/index.php/topic,14595.0.html for more information. Definitionhook_civicrm_aclGroup( $type, $contactID, $tableName, &$allGroups, &$currentGroups ) Parameters
Returns
ExampleCheck HRD Module hook_civicrm_dashboardDescriptionThis hook is called when rendering the dashboard page. This hook can be used to add content to the dashboard page. Definitionhook_civicrm_dashboard( $contactID, &$contentPlacement = self::DASHBOARD_BELOW ) Parameters
Returns
Examplefunction civitest_civicrm_dashboard( $contactID, &$contentPlacement ) {
// REPLACE Activity Listing with custom content
$contentPlacement = 3;
return array( 'Custom Content' => "Here is some custom content: $contactID",
'Custom Table' => "
<table>
<tr><th>Contact Name</th><th>Date</th></tr>
<tr><td>Foo</td><td>Bar</td></tr>
<tr><td>Goo</td><td>Tar</td></tr>
</table>
",
);
}
Also check Civitest Sample Module hook_civicrm_xmlMenuDescriptionThis hook is called when building CiviCRM's menu structure. You will need to visit <your_site>/civicrm/menu/rebuild&reset=1 to pick up your additions. Definitionhook_civicrm_xmlMenu( &$files ) Parameters
Returns
ExampleHere's how you can override an existing menu item. First create an XML file like this, and place it in the same folder as your hook implementation: <?xml version="1.0" encoding="iso-8859-1" ?> <menu> <item> <path>civicrm/ajax/contactlist</path> <page_callback>CRM_Contact_Page_AJAX::getContactList</page_callback> <access_arguments>my custom permission</access_arguments> </item> </menu> <?xml version="1.0" encoding="iso-8859-1" ?> function EXAMPLE_civicrm_xmlMenu( &$files ) {
$files[] = dirname(__FILE__)."/my_file_name_above.xml";
}
hook_civicrm_alterPaymentProcessorParamsDescriptionThis hook is called during the processing of a contribution after the payment processor has control, but just before the CiviCRM processor specific code starts a transaction with the back-end payments server (e.g., PayPal, Authorized.net, or Moneris). It allows you to modify the parameters passed to the back end so that you can pass custom parameters, or use features of your back-end that CiviCRM does not "know" about. Definitionhook_civicrm_alterPaymentProcessorParams( $paymentObj,&$rawParams, &$cookedParams ); Parameters
ReturnsExample/** * Hook implementation for altering payment parameters before talking to a payment processor back end. * * @param string $paymentObj * instance of payment class of the payment processor invoked (e.g., 'CRM_Core_Payment_Dummy') * @param array &$rawParams * array of params as passed to to the processor * @params array &$cookedParams * params after the processor code has translated them into its own key/value pairs * @return void */ function civitest_civicrm_alterPaymentProcessorParams( $paymentObj, &$rawParams, &$cookedParams ) { $mode = $paymentObj->getVar('_mode'); $type = $paymentObj->getVar('_paymentProcessor'); $processorType = $type['payment_processor_type']; if ( $paymentObj instanceof CRM_Core_Payment_Dummy ) { $employer = empty($rawParams['custom_1']) ? '' : $rawParams['custom_1']; $occupation = empty($rawParams['custom_2']) ? '' : $rawParams['custom_2']; $cookedParams['custom'] = "$employer|$occupation"; } else if ( $paymentObj instanceof CRM_Contribute_Payment_AuthorizeNet ) { //Actual translation for one application: //Employer > Ship to Country (x_ship_to_country) //Occupation > Company (x_company) //Solicitor > Ship-to First Name (x_ship_to_first_name) //Event > Ship-to Last Name (x_ship_to_last_name) //Other > Ship-to Company (x_ship_to_company) $cookedParams['x_ship_to_country'] = $rawParams['custom_1']; $cookedParams['x_company'] = $rawParams['custom_2']; $cookedParams['x_ship_to_last_name'] = $rawParams['accountingCode']; //for now $country_info = da_core_fetch_country_data_by_crm_id($rawParams['country-1']); $cookedParams['x_ship_to_company'] = $country_info['iso_code']; } else if( $paymentObj instanceof CRM_Core_Payment_PayPalImpl && $processorType == 'PayPal' ) { // Website Pro Checkout $obj = $paymentObj->getVar('_paymentForm'); $value = $obj->getVar('_values'); $id = $value['id']; if ( $value['event']['id'] ) { $id = $value['event']['id']; } $cookedParams['desc'] = $rawParams['description']; $cookedParams['custom'] = $id; } elseif ( $paymentObj instanceof CRM_Core_Payment_PayPalImpl && $processorType == 'PayPal_Express' ) { // Express Checkout $cookedParams['desc'] = $rawParams['eventName']; $cookedParams['custom'] = $rawParams['eventId']; } } hook_civicrm_pageRunDescriptionThis hook is called before a CiviCRM page is rendered Definitionhook_civicrm_pageRun( &$page ) Parameters
Returns
hook_civicrm_copyDescriptionThis hook is called after a CiviCRM object (Event, ContributionPage, Profile) has been copied Definitionhook_civicrm_copy( $objectName, &$object ) Parameters
Returns
hook_civicrm_tokensDescriptionThis hook is called to get all the tokens that can be used Definitionhook_civicrm_tokens( &$tokens ) Parameters
Returns
hook_civicrm_tokenValuesDescriptionThis hook is called to get all the values for the tokens registered Definitionhook_civicrm_tokenValues( &$details, &$contactIDs ) Parameters
Returns
hook_civicrm_customFieldOptionsDescriptionThis hook is called when CiviCRM needs to edit/display a custom field with options (select, radio, checkbox, adv multiselect) Definitionhook_civicrm_customFieldOptions( $fieldID, &$options, $detailedFormat = false )
Parameters
Returns
Examplefunction civitest_civicrm_customFieldOptions($fieldID, &$options, $detailedFormat = false ) { if ( $fieldID == 1 || $fieldID == 2 ) { if ( $detailedFormat ) { $options['fake_id_1'] = array( 'id' => 'fake_id_1', 'value' => 'XXX', 'label' => 'XXX' ); $options['fake_id_2'] = array( 'id' => 'fake_id_2', 'value' => 'YYY', 'label' => 'YYY' ); } else { $options['XXX'] = 'XXX'; $options['YYY'] = 'YYY'; } } } This syntax may be more convenient if you are a managing differing sets of options for different fields: function EXAMPLE_civicrm_customFieldOptions($fieldID, &$options, $detailedFormat = false ) { switch ($fieldID) { case 1: case 2: $options['fake_id_1'] = array( 'id' => 'fake_id_1', 'value' => 'Xvalue', 'label' => 'Xlabel' ); $options['fake_id_2'] = array( 'id' => 'fake_id_2', 'value' => 'Yvalue', 'label' => 'Ylabel' ); $changed = TRUE; break; case 3: $options['fake_id_1'] = array( 'id' => 'fake_id_1', 'value' => 'Avalue', 'label' => 'Alabel' ); $options['fake_id_2'] = array( 'id' => 'fake_id_2', 'value' => 'Bvalue', 'label' => 'Blabel' ); $changed = TRUE; break; } if ($changed && !$detailedFormat ) { foreach ($options AS $choice) { $options[$choice['value']] = $choice['label']; } } } hook_civicrm_searchTasksDescriptionThis hook is called to display the list of actions allowed after doing a contact search. This allows the module developer to inject additional actions. Definitionhook_civicrm_searchTasks( $objectType, &$tasks ) Parameters
Returns
hook_civicrm_buildAmountDescriptionThis hook is called when building the amount structure for a Contribution or Event Page. It allows you to modify the set of radio buttons representing amounts for contribution levels and event registration fees. Definitionhook_civicrm_buildAmount( $pageType, &$form, &$amount ) Parameters
Returns
Examplefunction civitest_civicrm_buildAmount( $pageType,
&$form,
&$amount ) {
// only modify the contributon page with id = 1
if ( $pageType != 'contribution' ||
$form->_id != 1 ) {
return;
}
// lets add an arbitrary amount here, just to show folks
// the power of a hook :)
$amount[1000] = array( 'value' => 400,
'label' => 'Hook',
'amount_id' => 1000 );
// now lets get a bit more ambitious
// *GOAL*: lets plan to give 20% discount to students
$membershipType = 'Student';
$discountPercent = 20;
// get the membership-type-id for the membership-type
$membershipTypeId = CRM_Core_DAO::getFieldValue( 'CRM_Member_DAO_MembershipType',
$membershipType,
'id',
'name' );
// get the logged in user id
$session =& CRM_Core_Session::singleton();
$userID = $session->get( 'userID' );
if ( $userID ) {
// check if logged in user has 'Student' membership
require_once 'CRM/Member/BAO/Membership.php';
$membership = CRM_Member_BAO_Membership::getContactMembership( $userID, $membershipTypeId, null );
// If logged in contact is a member as on today, modify the amount
// to reflect the discount.
if ( CRM_Utils_Array::value( 'is_current_member', $membership ) ) {
foreach ( $amount as $amountId => $amountInfo ) {
$amount[$amountId]['value'] = $amount[$amountId]['value'] -
ceil($amount[$amountId]['value'] * $discountPercent / 100);
$amount[$amountId]['label'] = $amount[$amountId]['label'] .
"\t - with {$discountPercent}% discount (for $membershipType)";
}
}
}
}
hook_civicrm_tabsDescriptionThis hook is called when composing the tabs to display when viewing a contact Definitionhook_civicrm_tabs( &$tabs, $contactID ) Parameters
Returns
Examplefunction civitest_civicrm_tabs( &$tabs, $contactID ) {
// unset the contribition tab, i.e. remove it from the page
unset( $tabs[1] );
// let's add a new "contribution" tab with a different name and put it last
// this is just a demo, in the real world, you would create a url which would
// return an html snippet etc.
$url = CRM_Utils_System::url( 'civicrm/contact/view/contribution',
"reset=1&snippet=1&force=1&cid=$contactID" );
$tabs[] = array( 'id' => 'mySupercoolTab',
'url' => $url,
'title' => 'Contribution Tab Renamed',
'weight' => 300 );
}
hook_civicrm_mailingGroupsDescriptionThis hook is called when composing a mailing. You can include / exclude other groups as needed. Definitionhook_civicrm_mailingGroups( &$form, &$groups, &$mailings ) Parameters
Returns
Examplefunction civitest_civicrm_mailingGroups( &$form, &$groups, &$mailings ) {
// unset group id 4
unset( $groups[4] );
// add a fictitious mailing
$mailings[1] = 'This mailing does not exist';
}
hook_civicrm_shortcutsDescriptionThis hook is called when shortcuts select is build, so that you can add your own custom urls / commonly used actions. Definitionhook_civicrm_shortcuts( &$options ) Examplefunction civitest_civicrm_shortcuts( &$options ) {
// add link to create new profile
$options[] = array( 'url' => '/civicrm/admin/uf/group?action=add&reset=1',
'title' => ts('New Profile'),
'ref' => 'new-profile');
}
hook_civicrm_summaryDescriptionThis hook is called when contact summary is rendered and you can add on top, below or replace summary with your own html content. Definitionhook_civicrm_summary( $contactID, &$content, &$contentPlacement = CRM_Utils_Hook::SUMMARY_BELOW ) Parameters
Examplefunction civitest_civicrm_summary( $contactID, &$content, &$contentPlacement ) {
// REPLACE default Contact Summary with your customized content
$contentPlacement = 3;
$content = "
<table>
<tr><th>Hook Data</th></tr>
<tr><td>Data 1</td></tr>
<tr><td>Data 2</td></tr>
</table>
";
}
hook_civicrm_contactListQueryDescriptionUse this hook to populate the list of contacts returned by Contact Reference custom fields. By default, Contact Reference fields will search on and return all CiviCRM contacts. If you want to limit the contacts returned to a specific group, or some other criteria - you can override that behavior by providing a SQL query that returns some subset of your contacts. The hook is called when the query is executed to get the list of contacts to display. Definitionhook_civicrm_contactListQuery( &$query, $name, $context, $id ) Parameters
ExampleThis example limits contacts in my contact reference field lookup (custom field id=4) to a specific group (group id=5) // Connect the hook to your Contact Reference custom field using the field ID (field id=4 in this case) if ( $context == 'customfield' && $id == 4 ) { // Now construct the query to select only the contacts we want // The query must return two columns - contact data, and contact id $query = " SELECT c.sort_name as data, c.id FROM civicrm_contact c, civicrm_group_contact cg WHERE c.sort_name LIKE '$name%' AND cg.group_id IN ( 5 ) AND cg.contact_id = c.id AND cg.status = 'Added' ORDER BY c.sort_name "; } } hook_civicrm_membershipTypeValuesDescriptionThis hook is called when composing the array of membershipTypes and their cost during a membership registration (new or renewal). Note the hook is called on initial page load and also reloaded after submit (PRG pattern). You can use it to alter the membership types when first loaded, or after submission (for example if you want to gather data in the form and use it to alter the fees). Definitionhook_civicrm_membershipTypeValues( &$form, &$membershipTypeValues ) {
Parameters
ExamplesGive a 50% discount to some memberships in the sample data function civitest_civicrm_membershipTypeValues( &$form, &$membershipTypeValues ) {
$membershipTypeValues[1]['name'] = 'General (50% discount)';
$membershipTypeValues[1]['minimum_fee'] = '50.00';
$membershipTypeValues[2]['name'] = 'Student (50% discount)';
$membershipTypeValues[2]['minimum_fee'] = '25.00';
}
Modify specific fee values function mymodule_civicrm_membershipTypeValues( &$form, &$membershipTypeValues ) {
foreach ( $membershipTypeValues as &$values) {
if ( $values['name'] == 'General') {
$values['minimum_fee'] = "5.55";
}
if ( $values['name'] == 'Student') {
$values['minimum_fee'] = "2.22";
}
}
}
hook_civicrm_alterMailParamsDescriptionThis hook is called when an email is about to be sent by CiviCRM. Definitionhook_civicrm_alterMailParams( &$params ) Parameters
Details
hook_civicrm_caseSummaryDescriptionThis hook is called when the manage case screen is displayed. It allows the injection of label/value pairs which are rendered inside divs underneath the existing summary table. Definitionhook_civicrm_caseSummary( $caseID ) Parameters
Returns
Example <?php
function myModule_civicrm_caseSummary($caseID) {
/* Quick way to test what some results look like.
return array('some_unique_id' => array( 'label' => ts('Some Date'),
'value' => '2009-02-11',
),
'some_other_id' => array( 'label' => ts('Some String'),
'value' => ts('Coconuts'),
),
);
*/
// More realistic example, but will return nothing unless you have these activities in your database.
// TIP: Put these queries into methods in a custom class. You will likely want to re-use them elsewhere, such as in a CiviReport.
// This query finds the earliest date of return to modified duties in a workplace disability case.
$params = array( 1 => array( $caseID, 'Integer' ) );
$sql = "SELECT min(activity_date_time) as mindate
FROM civicrm_activity a
INNER JOIN civicrm_case_activity ca on a.id=ca.activity_id
LEFT OUTER JOIN civicrm_option_group og on og.name='activity_type'
LEFT OUTER JOIN civicrm_option_value ov on
(og.id=ov.option_group_id AND ov.name='Return to modified duties')
WHERE ca.case_id=%1
AND ov.value=a.activity_type_id
LIMIT 1";
$modrtw = CRM_Core_DAO::singleValueQuery( $sql, $params );
// This query returns the current status of the medical consent as determined by
// the presence or absence of related activities.
$sql = "SELECT CASE WHEN count(received.case_id) > 0 THEN 'Received'
WHEN count(sent.case_id) > 0 AND DATEDIFF(CURRENT_TIMESTAMP, sent.activity_date_time) > 14 THEN 'Overdue'
WHEN count(sent.case_id) > 0 THEN 'Sent'
ELSE 'Not Sent'
END
FROM
(SELECT ca.case_id, a1.activity_date_time FROM civicrm_activity a1
INNER JOIN civicrm_case_activity ca on a1.id=ca.activity_id
LEFT OUTER JOIN civicrm_option_group og on og.name='activity_type'
LEFT OUTER JOIN civicrm_option_value ov on
(og.id=ov.option_group_id AND ov.name='Send Consent Letter')
WHERE ca.case_id=%1
AND ov.value=a1.activity_type_id
LIMIT 1
) AS sent
LEFT OUTER JOIN
(SELECT ca2.case_id FROM civicrm_activity a2
INNER JOIN civicrm_case_activity ca2 on a2.id=ca2.activity_id
LEFT OUTER JOIN civicrm_option_group og2 on og2.name='activity_type'
LEFT OUTER JOIN civicrm_option_value ov2 on
(og2.id=ov2.option_group_id AND ov2.name='File Received Consent')
WHERE ca2.case_id=%1
AND ov2.value=a2.activity_type_id
LIMIT 1
) AS received
ON received.case_id=sent.case_id";
$mcstat = CRM_Core_DAO::singleValueQuery( $sql, $params );
return array('modrtw' => array( 'label' => ts('Mod RTW:'),
'value' => $modrtw,
),
'mcstat' => array( 'label' => ts('Consent Status:'),
'value' => ts($mcstat),
),
);
Put this in css/extras.css:
#caseSummary {display: table;}
#modrtw {display: table-row; border: 1px solid #999999; width: 200px;}
#mcstat {display: table-row; border: 1px solid #999999; border-left: 0; width: 200px;}
#caseSummary label {display: table-cell;}
#caseSummary div {display: table-cell; padding-left: 5px; padding-right: 5px;}
hook_civicrm_configDescriptionThis hook is called soon after the CRM_Core_Config object has ben initialized. You can use this hook to modify the config object and hence behavior of CiviCRM dynamically. Definitionhook_civicrm_config( &$config ) Parameters
Examplefunction civitest_civicrm_config( &$config ) {
$civitestRoot = dirname( __FILE__ ) . DIRECTORY_SEPARATOR;
// fix php include path
$include_path = $civitestRoot . PATH_SEPARATOR . get_include_path( );
set_include_path( $include_path );
// fix template path
$templateDir = $civitestRoot . 'templates' . DIRECTORY_SEPARATOR;
$template =& CRM_Core_Smarty::singleton( );
if ( is_array( $template->template_dir ) ) {
$template->template_dir = array( $templateDir ) + $template->template_dir;
} else {
$template->template_dir = array( $templateDir, $template->template_dir );
}
}
hook_civicrm_navigationMenuDescriptionThis hook is called after the menus are rebuild. You can use this hook to add new menu, add children to new menu and get the list of menu items for any parent. Definitionhook_civicrm_navigationMenu( &$params ) Parameters
Attributes of the menu : 1. label : Navigation Title 2. Name : Internal Name 3. url : url in case of custom navigation link 4. permission : comma separated Permissions for menu item 5. operator : Permission Operator ( AND/OR) 6. seperator : If separator needs to be added after this menu item. 7. parentID : Parent navigation item, used for grouping 8. navID : ID of the menu 9. active : is active ? Examplefunction civicrm_civicrm_navigationMenu( &$params ) {
// Get the maximum key of $params
$maxKey = ( max( array_keys($params) ) );
$params[$maxKey+1] = array (
'attributes' => array (
'label' => 'Custom Menu Entry',
'name' => 'Custom Menu Entry',
'url' => null,
'permission' => null,
'operator' => null,
'separator' => null,
'parentID' => null,
'navID' => $maxKey+1,
'active' => 1
),
'child' => array (
'1' => array (
'attributes' => array (
'label' => 'Custom Child Menu',
'name' => 'Custom Child Menu',
'url' => 'http://www.testlink.com',
'permission' => 'access CiviContribute',
'operator' => null,
'separator' => 1,
'parentID' => $maxKey+1,
'navID' => 1,
'active' => 1
),
'child' => null
) ) );
}
hook_civicrm_mergeDescriptionThis hook allows modification of the data used to perform merging of duplicates. This can be useful if your custom module has added its own tables related to CiviCRM contacts. AvailabilityThis hook was first available in CiviCRM 3.2.3. Definitionhook_civicrm_merge ( $type, &$data, $mainId = NULL, $otherId = NULL, $tables = NULL ) Parameters
DetailsThe contents of $data will vary based on the $type of data being passed:
Example/* In this example we assume our module has created its own tables to store extra data on CiviCRM contacts: * Table civitest_foo stores a relationship between two contacts, and contains the two relevant columns: * civitest_foo.contact_id and civitest_foo.foo_id, both of which are foreign keys to civicrm_contact.id * Table civitest_bar stores extra properties for contacts, and contains one relevant column: * civitest_bar.contact_id is a foreign key to civicrm_contact.id * * This hook ensures that data in these two tables is included in CiviCRM merge operations. */ function civitest_civicrm_merge ( $type, &$data, $mainId = NULL, $otherId = NULL, $tables = NULL ) { switch ($type) { case 'relTables': // Allow user to decide whether or not to merge records in `civitest_foo` table $data['rel_table_foo'] = array( 'title' => ts('Foos'), // Title as shown to user for this type of data 'tables' => array('civitest_foo'), // Name of database table holding these records 'url' => CRM_Utils_System::url('civicrm/civitest/foo', 'action=browse&cid=$cid'), // URL to view this data for this contact, // in this case using CiviCRM's native URL utility // NOTE: '$cid' will be replaced with correct // CiviCRM contact ID. ); break; case 'cidRefs': // Add references to civitest_foo.contact_id, and civitest_foo.foo_id, both of which // are foreign keys to civicrm_contact.id. By adding this to $data, records in this // table will be automatically included in the merge. $data['civitest_foo'] = array('contact_id', 'foo_id'); break; case 'eidRefs': // Add references to civitest_bar table, which is keyed to civicrm_contact.id // using `bar_entity_id` column, when `entity_table` is equal to 'civicrm_contact'. By // adding this to $data, records in this table will be automatically included in // the merge. $data['civitest_bar'] = array('entity_table' => 'bar_entity_id'); break; case 'sqls': // Note that this hook can be called twice with $type = 'sqls': once with $tables // and once without. In our case, SQL statements related to table `civicrm_foo` // will be listed in $data when $tables is set; SQL statements related to table // `civicrm_bar` will be listed in $data when $tables is NOT set. The deciding // factor here is that `civicrm_foo` was referenced above as part of the 'relTables' // data, whereas `civicrm_bar` was not. if ($tables) { // Nothing to do in our case. In some cases, you might want to find and // modify existing SQL statements in $data. } else { // Nothing to do in our case. In some cases, you might want to find and // modify existing SQL statements in $data. } break; } } |
