Skip to content

hook_civicrm_fieldOptions

Summary

Dynamically modify the option list for any field (including custom fields).

Definition

hook_civicrm_fieldOptions(string $entity, string $field, array &$options, array $params): void

Parameters

  • $entity (string): Entity name, e.g. 'Contact', 'Email', 'Contribution'
  • $field (string): Name of field e.g. 'phone_type_id' (core field), 'MyCustomGroup.MyCustomField' (custom field)
  • &$options (array[]): Array of option arrays to modify by-reference (format may be different on older versions, see legacy notes below).
  • $params (array): Array of contextual settings and values:
    • context (string): Always 'full' (except for older versions, see legacy notes below)
    • values (array): Array of entity values, e.g. ['contact_type' => 'Individual'] (warning: may contain raw user input)
    • include_disabled (bool): Whether disabled options should be returned
    • check_permissions (bool): Should permissions be enforced for option list
    • user_id (?int): Contact id of permissions to check (null indicates "current user")

Usage

The $options array will look something like this:

3 => [   
    'id' => 3,
    'name' => 'Major_Donor',
    'label' => 'Major Donor',
    'color' => '#aaaaaa',
    'description' => 'High-value supporter of our organization.',
],
1 => [
    'id' => 1,
    'name' => 'Non_profit',
    'label' => 'Non-profit',
    'color' => '#bbbbbb',
    'description' => 'Any not-for-profit organization.',
],
2 => [
    'id' => 2,
    'name' => 'Volunteer',
    'label' => 'Volunteer',
    'color' => '#cccccc',
    'description' => 'Active volunteers.',
]

And the $params array will look something like:

[
    'context' => 'full',
    'values' => ['entity_table' => 'civicrm_contact'],
    'include_disabled' => TRUE,  
    'check_permissions' => FALSE,
    'user_id' => NULL,
]

Note that the options array contains all attributes of each option, and is keyed by the option id.

  • The context will always be "full" in CiviCRM 5.79+, except for some legacy subsystems (see legacy notes below).
  • The values often contain useful contextual information, for example a list of states might include the currently selected 'country_id', or in this example we know the list of tags is filtered for only Contact tags (the inclusion of a parent_id might also tell us which tagset is being loaded).
  • In this example disabled options are being included, and user permissions are not being checked. This is typical when e.g. search results are being displayed and the label for each result is being fetched as a display value.

Example 1: Modify options of existing field

This function will check permissions if appropriate, and remove case types from the list if the user is not authorized to select them when opening a new case.

function example_civicrm_fieldOptions($entity, $field, &$options, $params) {
  if ($entity === 'Case' && $field === 'case_type_id' && $params['check_permissions']) {
    if (!CRM_Core_Permission::check('access all cases and activities'), $params['user_id']) {
      // Remove access to certain case types for non-authorized users
      // Array will be keyed by case_type id.
      unset($options[3], $options[5]);
    }
  }
}

Example 2: Provide options for custom field

Extensions that programmatically create custom fields can use this hook to provide dropdown options for them. In this example, the extension has a custom field group called "MyCustomGroup" with a Select field called "MyContactField". To populate the dropdown options, one could add an OptionGroup to the field, or use this hook to set them programmatically:

function example_civicrm_fieldOptions($entity, $field, &$options, $params) {
  if ($field === 'MyCustomGroup.MyContactField') {
    // The hook accepts 2 formats for $options:
    $options = [
      // Simple key/val options like this:
      1 => E::ts('One'),
      2 => E::ts('Two'),
      // Or full-format options like this:
      [
        'id' => 3,
        'label' => E::ts('Three'),
        'name' => 'three',
        'description' => E::ts('It comes after two, but before four'),
        'color' => '#333333',
        'icon' => 'fa-three',
      ],
    ],
  }
}

See Also

See Pseudoconstant (option list) Reference for more information about how option lists work.

Legacy Notes

Prior to CiviCRM 5.79, this hook had 3 notable differences:

  1. $field: in the case of custom fields, was given as "custom_123" instead of "GroupName.FieldName".

  2. $options: was a flat array of scalar values instead of an array of arrays. As of this writing (2024) there are still a few older code paths which will call the hook in the legacy manner, although they are in the process of being refactored out. If you need to support older versions of Civi, or legacy subsytems like CiviReport, check the context param and add extra handling for the various possible formats. The context could have been one of the following:

    • null: all enabled options are returned, labels are translated.
    • "get": all options are returned, even if they are disabled; labels are translated.
    • "create": options are filtered appropriately for the object being created/updated; labels are translated.
    • "search": searchable options are returned; labels are translated.
    • "validate": all options are returned, even if they are disabled; machine names are used in place of labels.
    • "abbreviate": enabled options are returned; labels are replaced with abbreviations.
    • "match": enabled options are returned using machine names as keys; labels are translated.
  3. $params: may have been different, or empty.

    • $params['context'] was always one of the above
    • $params['onlyActive'] was the alternate name for include_disabled (if missing infer it from context)
    • $params['check_permissions'] might be missing or null (in which case infer it from context)
    • $params['user_id'] was not included (always assumed current_user)
    • $params['values'] might be missing