Skip to content



Programmatically alter a list of links.

This hook is called from various screens that display lists of links, including:

  • Action links at the end of a search result row
  • Action links on a tabular admin screen
  • Action links on a tabular contact summary tab
  • The "Create New" dropdown
  • The Actions dropdown at the top of a contact record


Conversions impacting this hook

Many screens that display tabular results are in the process of being converted to SearchKit displays, including admin pages, dashboards, contact summary tabs, component searches, and reports. SearchKit displays do not call this hook as their links can be modified via the GUI. If you need to modify links on such a screen, consider replacing it with a SearchDisplay instead of using this hook, or try enabling the CiviCRM Admin UI extension which may already contain a replacement.


hook_civicrm_links(string $op, string $objectName, $objectID, array &$links, int &$mask, array &$values)


  • string $op - the context in which the links appear such as, survey.dashboard.row, pcp.user.actions or pdfFormat.manage.action. This should be lowercase but there are some inconsistencies in CiviCRM core (eg. In many cases $objectName is enough to filter on but you can filter on context as well.

  • string $objectName - the entity the links relate to (or NULL if $op is

  • int|string $objectID - the CiviCRM internal ID of the entity or string of the extension name for list of extensions. (or NULL if $op is

  • array $links - the links to modify in place

    each item in the array may have:

    • name: the link text

    • url: the link URL base path (like civicrm/contact/view, and fillable from $values)

    • qs: the link URL query parameters to be used by sprintf() with $values (like reset=1&cid=%%id%% when $values['id'] is the contact ID)

    • title (optional): the text that appears when hovering over the link

    • extra (optional): additional attributes for the <a> tag (fillable from $values)

    • bit (optional): a binary number that will be fitered by $mask (sending nothing as $links['bit'] means the link will always display)

    • ref (optional, recommended): a CSS class to apply to the <a> tag.

    • class (optional): Any other CSS classes to apply to the <a> tag (e.g. no-popup).

    • int weight (recommended): Weight is used to order the links. If not set 0 will be used but e-notices could occur. This was introduced in CiviCRM 5.63 so it will not have any impact on earlier versions of CiviCRM. There are some conventions for core weights: - CRM_Core_Action::VIEW -20 - CRM_Core_Action::UPDATE -10 - CRM_Core_Action::ENABLE 40 - CRM_Core_Action::DISABLE 40 - CRM_Core_Action::DELETE 100

    • int|null $mask - a bitmask that will filter $links

    • array $values - values to fill $links['url'], $links['qs'], and/or $links['extra'] using sprintf()-style percent signs

Link interactions with pop-ups

On many screens, links will open a pop-up when clicked. To prevent this, for example if the link initiates a file download, add class => 'no-popup'. Also note that inside pop-ups, many links are turned into buttons, and some attributes (including class) will be lost or transformed.


If you omit the qs parameter, Civi will interpret the url as a regular URL rather than as a Civi admin page. This is useful if you want to link to a non-Civi page. If needed, you can add query string parameters to the url by obtaining the needed values from &$values. (Works for Civi Profile search results.)


  • NULL


function MODULENAME_civicrm_links(string $op, ?string $objectName, $objectID, array &$links, ?int &$mask, array &$values): void {
  $myLinks = [];
  if ($objectName !== 'Contact') {

  switch ($op) {
    case '':
      // Adds a link to the main tab.
      $links[] = [
        'name' => E::ts('My Module Actions'),
        'url' => 'mymodule/civicrm/actions/%%myObjectID%%',
        'title' => 'New Thing',
        'class' => 'no-popup',
        'weight' => 25,
      $values['myObjectID'] = $objectID;

    case 'contact.selector.row':
      // Add a similar thing when a contact appears in a row
      $links[] = [
        'name' => E::ts('My Module'),
        'url' => 'mymodule/civicrm/actions/%%myObjectID%%',
        'title' => 'New Thing',
        'qs' => 'reset=1&tid=%%thingID%%',
        'class' => 'no-popup',
          'weight' => 30,
      $values['myObjectID'] = $objectID;
      $values['thingID'] = 'my_thing';

    case '':
      // add link to create new profile
      $links[] = [
        'url' => '/civicrm/admin/uf/group?action=add&reset=1',
        'name' => E::ts('New Profile'),
          'weight' => 45,
          // Old extensions using 'title' will still work.
    case '':
      // Disable copy & delete links.

Adding contextual links to the rows of a contact's Events tab and Find Participants search result

function mymodule_civicrm_links(string $op, string $objectName, ?int $objectID, array &$links, ?int &$mask, array &$values): void {
  // Create a Send Invoice link with the context of the participant's order ID (a custom participant field).
  if ($objectName !== 'Participant' || $op !== 'participant.selector.row') {

  $contactID = $values['cid'];
  $orderID = mymodule_myCustomFunction($objectID);

  //check if this participant is a student with a parent, for saving the email.
  //if not, fall back to current contact record
  $contactID = \Civi\Api4\Relationship::get(FALSE)
  ->addWhere('relationship_type_id', '=', 1)
  ->addWhere('contact_id_a', '=', $contactID)
  ->execute()->first()['contact_id_b'] ?: $contactID;

  $links[] = [
    'name' => E::ts('Send Invoice'),
    'title' => E::ts('Send Invoice'),
    'url' => 'civicrm/activity/email/add',
    'qs' => "action=add&reset=1&cid=$contactID&selectedChild=activity&atype=3&order_id=$orderID",
    'weight' => 25,