We have a post hook that sends some data to an external api when a participant is created or edited.

function kavo_civicrm_post($op, $objectName, $objectId, &$objectRef) { if (($op == 'create' || $op == 'edit') && $objectName == 'Participant') {

Based on the response of that api a custom field on the response of that API a couple of custom fields on the participant should be set. This is done using the php api, but results in a loop with the post hook being called, even when following the add_callback instructions in the post hook documentation.

try { civicrm_api3('Kavo', 'createparticipant', ['participant_id' => $objectId]); $successState = CRM_Kavo_Status::KAVO_ATTENDED(); CRM_Core_Transaction::addCallback(CRM_Core_Transaction::PHASE_POST_COMMIT, 'set_kavo_state', [$objectId, $successState]); } catch (CiviCRM_API3_Exception $ex) { $contact = $worker->getContact($participant); CRM_Core_Session::setStatus($ex->getMessage(), ts("Failed sending participant %1 to KAVO.", [1 => $contact['display_name']]), 'error'); $failedState = CRM_Kavo_Status::KAVO_FAILED(); CRM_Core_Transaction::addCallback(CRM_Core_Transaction::PHASE_POST_COMMIT, 'set_kavo_state', [$objectId, $failedState, $ex->getMessage()]); }

function set_kavo_state($participant_id, $state, $message='success'){ $kavo_status_field = CRM_Kavo_Field::KAVO_PARTICIPANT_STATUS(); $kavo_message_field = CRM_Kavo_Field::KAVO_PARTICIPANT_MESSAGE(); civicrm_api3('Participant', 'create', array( 'id' => $participant_id, $kavo_status_field => $state, $kavo_message_field => $message )); }

The kavo create_participant call does our call to the external api Is there another way to edit the participant being edited in a post hook?

  • I am not clear on what you are asking, can you give a little more detail? I think I understand (and know the problem) but I am not sure..... Sep 21, 2017 at 11:35
  • In a post hook we send a request to an external api. This post hook is limited to working on particapants on edit or create. Depending on the succes of the api call I want to set a costum field on the participant. I will edit some code in the original question to clarify.
    – joost
    Sep 21, 2017 at 11:47

3 Answers 3


The participant create in set_kavo_state() triggers your post hook again which then calls set_kavo_state() etc. You need to determine whether the post hook is being called just to update the $kavo_status_field and $kavo_message_field fields - and therefore not set up another callback to set_kavo_state().

Do you actually need to call your external API for participant edits? If you could limit the post hook to only trigger on 'create' you would avoid the loop.

  • The external api needs to be called when participants are edited, and their kavo fields need to be set based on the api response. I know the call to set the kavo fiels is the reason for getting in the loop, I was wondering wether there was a way to set them without getting back in the post hook.
    – joost
    Sep 22, 2017 at 8:48
  • I think that if you check your request in the post hook you can determine if you are coming in from the API or not? Apr 20, 2018 at 12:16

You have two choices:

  • Use hook_civicrm_pre instead of hook_civirm_post. This isn't ideal because it's synchronous and will slow down your writes.
  • Since you're updating custom fields only, continue to use hook_civicrm_post, but instead of calling Participant.create, call CustomValue.create, which won't trigger the post hook a second time.

If you are using Drupal, you can use the Drupal static cache infrastructure to break the cycle. In this particular example, the static cache is only available for one page load / http request. You can set a database cache as well, see References below for detailed explanation and instructions

function set_kavo_state($participant_id, $state, $message='success'){
  $stop = &drupal_static(__FUNCTION__);
  // could use more logic in this conditional if need be ... but at least you will know if you've come back a second time...
  if (!isset($stop)) {
    $kavo_status_field = CRM_Kavo_Field::KAVO_PARTICIPANT_STATUS();
    $kavo_message_field = CRM_Kavo_Field::KAVO_PARTICIPANT_MESSAGE();
    civicrm_api3('Participant', 'create', array(
      'id' => $participant_id,
      $kavo_status_field => $state,
      $kavo_message_field => $message
    $stop = 1;

References: Drupal API documentation A Beginner's Guide to Caching Data in Drupal 7

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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