I've added a custom field set to the Participant entity, but I need to it allow for multiple values. I've noticed that the Contact entity has no problem with this, but is there a reason why it doesn't give you this option for other entities?

I've found the cause in this function in the templates/CRM/Custom/Form/Group.tpl file:

   * Check if this is a contact-related set and show/hide other options accordingly
  function showHideStyle() {
      extend = $(this).val(),
      contactTypes = {/literal}{$contactTypes}{literal},
      showStyle = "{/literal}{$showStyle}{literal}",
      showMultiple = "{/literal}{$showMultiple}{literal}",
      showMaxMultiple = "{/literal}{$showMaxMultiple}{literal}",
      isContact = ($.inArray(extend, contactTypes) >= 0);

    if (isContact) {
      $("tr#style_row, tr#is_multiple_row").show();
      if ($('#is_multiple :checked').length) {
    else {
      $("tr#style_row, tr#is_multiple_row, tr#multiple_row").hide();

    if (showStyle) {

    if (showMultiple) {
      $("tr#style_row, tr#is_multiple_row").show();

    if (!showMaxMultiple) {
    else if ($('#is_multiple').prop('checked')) {
  • It would be useful to elaborate on the use case - what are the multiple values, for what kinds of fields? Commented Nov 12, 2019 at 22:07
  • I need participants to be able to add multiple files. Each of which have titles, descriptions and other fields. Commented Nov 13, 2019 at 10:01

2 Answers 2


The documentation says they are only possible for contact records. See https://docs.civicrm.org/user/en/latest/organising-your-data/creating-custom-fields/#multiple-record-fieldsets. I expect the reason for this is that it would have been a lot more effort to add it for all for other entities. There are some built in ones for contacts so I guess it was easier to extend for contacts. It wasn't there from the start

  • 1
    I forgot to reply here, thanks for the explanation! I've done a little investigating and done some work and got something to work. I've posted it as answer! I hope to revisit it and see if I can make a patch for it to work on all entities (hopefully). Commented Nov 21, 2019 at 12:31

I found a way to get the Participant entity to accept multiple values.

To recap, I needed a custom field set that contained single value text, note and file fields, but needed to be able to add multiple instances of the set itself to a Participant.

I added the following code to the top of theCRM_Event_Form_Participant::postProcess method, underneath the line $params = $this->controller->exportValues($this->_name);.

// Get CiviCRM's configuration
$config = CRM_Core_Config::singleton();
$uploadDirectory = $config->uploadDir;

// Filter keys that are in the form of custom_[number]_-[number over 1]
$custom_field_keys = preg_grep('/custom_[0-9]+_-[2-9]+/', array_keys($this->_submitValues));
foreach ($custom_field_keys as $key) {

  // Save these additional values in the $params array
  $params[$key] = $this->_submitValues[$key];

// Filter out keys that are in the form of custom_[number]_-[number over 1]
$custom_file_keys = preg_grep('/custom_[0-9]+_-[2-9]+/', array_keys($this->_submitFiles));

foreach ($custom_file_keys as $key) {

  // rename the uploaded file with a unique number at the end
  $file = $this->_submitFiles[$key];

  $element = new HTML_QuickForm_file($key);
  $element->_value = $file;

  $newName = CRM_Utils_File::makeFileName($file['name']);
  $status = $element->moveUploadedFile($uploadDirectory, $newName);
  if (!$status) {
    CRM_Core_Error::statusBounce(ts('We could not move the uploaded file %1 to the upload directory %2. Please verify that the \'Temporary Files\' setting points to a valid path which is writable by your web server.', [
      1 => $value['name'],
      2 => $uploadDirectory,
  if (!empty($data['values'][$pageName][$uploadName]['name'])) {
    @unlink($uploadDirectory . $data['values'][$pageName][$uploadName]);

  $value = [
    'name' => $uploadDirectory . $newName,
    'type' => $element->_value['type'],
  //CRM-19460 handle brackets if present in $uploadName, similar things we do it for all other inputs.
  $value = $element->_prepareValue($value, TRUE);
  $params = HTML_QuickForm::arrayMerge($params, $value);

It begins by first getting the upload directory path from configuration and then finding all keys in the _submitValues property that are the second value onwards. Adding these values directly to the $params array appears to work with no additional work.

For files, the same beginning is needed where we find file field keys that are the second onwards, then we must create a new file field instance with HTML_QuickForm_file for each one, so we may utilise the HTML_QuickForm_file::moveUploadedFile() method. If the file is moved successfully, we prepare the new file values and merge them into the $params array.

  • is this a potential patch for core or released as an extension so others can benefit from your work
    – petednz - fuzion
    Commented Nov 20, 2019 at 18:23
  • 1
    It could potentially be a patch, I think I've identified to point where multiple value field sets fail though, which I'd like to share and work on. Ultimately, it's because when you add a new instance of a custom field set on the form, it just returns the markup to do so, it doesn't actually add it to the _elements or _elementsIndex array properties of the form. I think if this happened, it might just work. The contact entity works, so I might start there. Commented Nov 21, 2019 at 12:28

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.