Skip to content

hook_civicrm_permission

Summary

Allow custom permissions to be defined. These will appear along with core permissions in the UI and can be granted to user roles. They can be checked using CRM_Core_Permission::check().

Disambiguation

These two hooks appear similar, but serve different purposes:

  • hook_civicrm_permission: Defines new permissions. The permission will be fully available in configuration screens for CiviCRM/Drupal/WordPress/etc.
  • hook_civicrm_permissionList: Modifies the list of permissions presented in CiviCRM configuration. For example, this is used to import Drupal/WordPress permissions into CiviCRM configuration screens (without creating a funny loop).

Definition

hook_civicrm_permission(array &$permissions): void

Parameters

  • $permissions: reference to an associative array of custom permissions that are implemented by extensions, modules and other custom code. This will be an empty array unless another implementation of hook_civicrm_permission adds items to it. Items should use the following format:
    $permissions['permission name'] = [
      'label' => E::ts('Brief permission label'), // Required
      'description' => E::ts('Longer description of what the permission does'), // Optional but encouraged
      // Optional extras
      'disabled' => TRUE|FALSE // Boolean, defaults to FALSE if omitted
      'implies' => [...] // Array of permissions implied by this one (5.74+)
      'implied_by' => [...] // Array of permissions that imply this one (5.74+)
    ];
    

Legacy Formats

Older extensions may use non-associative arrays (item 0 will be interpreted as 'label' and 1 will be 'description'), or strings (interpreted as 'label'). These formats are deprecated as of 5.71. Extension authors should update to use the new format, which is compatible with all versions of CiviCRM 5.0.0 and up.

Implied Permissions

Starting in CiviCRM 5.74, the optional keys implies and implied_by are supported:

  • When one permission implies another, it creates a tree-like structure where granting the top-level permission automatically grants the sub-permissions as well.
  • You only need to declare one side of the implication: It is not necessary to set both implies and implied_by; do one or the other for each implication and CiviCRM will figure out the rest.
  • In the following example, a 3-tier permission tree is created.
    • Users with "view all cats" will automatically be granted "view my cats".
    • Users with the highest permission "edit all cats", will be automatically granted "view all cats" and its sub-permission "view my cats".
example_civicrm_permission(array &$permissions): void {
  $permissions['edit all cats'] = [
    'label' => E::ts('Edit all cats'),
    'description' => E::ts('View and edit every cat in the world'),
    'implies' => ['view all cats'],
  ];
  $permissions['view all cats'] = [
    'label' => E::ts('View all cats'),
    'description' => E::ts('View every cat in the world'),
    'implies' => ['view my cats'],
  ];
  $permissions['view my cats'] = [
    'label' => E::ts('View my cats'),
    'description' => E::ts('View my personal cats'),
  ];
}

Conventions and Tips

  • For edit permissions, it is conventional to use the plural, such as "edit my items"
  • It is normal to use the singular for create permissions, such as "create new item".
  • The convention for delete is "delete in extension name".
  • There is no automatic namespacing for permissions, so one should adopt unique permission names.

Example

The following example adds a permission access CiviMonitor:

function civimonitor_civicrm_permission(array &$permissions): void {
  $permissions['access CiviMonitor'] = [
    'label' => E::ts('Access CiviMonitor'),
    'description' => E::ts('Grants the necessary API permissions for a monitoring user without Administer CiviCRM'),
  ];
}