I have a group of CiviCRM users who are restricted by ACL to only be allowed to view and edit contacts in a certain geographic region (those contacts in a group called "Northern Region"). They also have view and edit permission on another group.

The problem is that the Manage Groups page only shows these two groups. If they add a new group it immediately dissapears!

Is this by design? It seems excessively limiting. I'd expect people to be able to see pretty much all groups, but only be able to see contacts within those groups that intersect with the contacts they're allowed by ACL.

Is there a work around?

Perhaps such staff are expected to create new groups as child groups of one of their ACL groups, but this is problematic because (a) it means that they can't make a group combining contacts from two+ groups and (b) it currently breaks access because of Bug #430

CiviCRM 5.10.3 / Drupal 7

1 Answer 1


The core issue is that CiviCRM's in-built ACLs don't distinguish between access to view a group and access to view the group's contacts.

However, extension-based ACLs CAN distinguish. So my solution is to give folks access to "View All Groups" as a web-based ACL, then restrict permissions by extension.

Note that this doesn't work unless you've applied the patch for core#580. This will be part of CiviCRM 5.12+.

UPDATE: Here's an example where I limit the viewing of anonymous donors (as flagged by a custom field) to members of a group called "Confidential Staff":

function tweaks_civicrm_aclWhereClause($type, &$tables, &$whereTables, &$contactID, &$where) {
  // If the person is not in the "Confidential Staff" group, don't show them the contacts in the "Anonymous Donors" group.
  if (!$contactID) {
  $confidentialStaff = civicrm_api3('GroupContact', 'get', [
    'group_id' => "Confidential_Staff_14",
    'contact_id' => $contactID,
  // If this person is not confidential staff;
  if ($confidentialStaff['count'] === 0) {
    // Find a list of anonymous donors.
    $result = civicrm_api3('Contact', 'get', [
      'return' => ["id"],
      'custom_12' => 1,
    $anonDonors = array_keys($result['values']);
    $anonDonors = implode(",", $anonDonors);
    $where .= ($where ? ' AND ' : '') . " contact_a.id NOT IN ($anonDonors)";

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.