Groups filter hack for smaller groups listings
authorAndrew Engelbrecht <andrew@fsf.org>
Fri, 15 Sep 2017 20:15:10 +0000 (16:15 -0400)
committerMichael McMahon <michael@fsf.org>
Thu, 20 Aug 2020 14:00:13 +0000 (10:00 -0400)
This change is a dirty hack that lets site admins filter the "Contacts
Group(s)" field output in select profiles. This reduces overwhem for
users when they are making a donation or filling out a form with the
Groups signup field. This is preferable to using a custom field with
smart groups because the Groups field provides double opt-in, while
custom fields do not.

The filter is controlled via a json string stored in a drupal variable
that can be set with drush like so:

drush vset --format=string groups_field_filters "{...}"

See the documentation marked with "sudoman hack" in
CRM/Contact/Form/Edit/TagsAndGroups.php for an example.

CRM/Contact/Form/Edit/TagsAndGroups.php
CRM/Contribute/Form/Contribution/Confirm.php
CRM/Event/Form/Registration/Confirm.php
CRM/Profile/Form.php

index c7d26927153d85cfc8fcd67ed6e781367edfe2a4..e06321a0d3ce0b01f224d2dac06e98eff46b4e6d 100644 (file)
@@ -90,10 +90,72 @@ class CRM_Contact_Form_Edit_TagsAndGroups {
       if ($groupID || !empty($group)) {
         $groups = CRM_Contact_BAO_Group::getGroupsHierarchy($ids);
 
+        // sudoman hack begins
+        //
+        // This hack allows us to filter Groups listings so users aren't
+        // overwhelmed with choices.  The advantage of this over smart groups
+        // is that normal groups use double opt-in.
+        //
+        // To set the variable, use the following method:
+        //
+        // $ drush vset --format=string groups_field_filters "{'profile': {'468': [25, 41]}, 'contribution': {'14': [25, 41]}, 'event': {'49': [25, 41]}}"
+        //
+        // The "string" format must be used and not the "json" format.
+        // Otherwise the json will be converted to a PHP array, which will not
+        // work with this code.
+        //
+        // The string contains json text, with the first level referring to
+        // page type, then the page number, then the list of ids of groups to
+        // display on that page.
+        //
+        // 'profile' is for standalone profiles. If the profile is embedded in
+        // a contrib or event page, then the id of the contrib or event page
+        // must be added to the string.
+
+        // Find the list of groups that we want to let pass through a filter on
+        // a given profile or page. If there is no filter for that page, then
+        // all groups are displayed.
+
+        $groups_field_filters = json_decode(variable_get('groups_field_filters', NULL), $assoc = TRUE);
+
+        $form_class_name = get_class($form);
+
+        // this commented line is useful for printing class names for future use in the switch statement below:
+        //watchdog("hacking", "foo message (form class): " . $form_class_name, NULL, WATCHDOG_ALERT);
+
+        switch ($form_class_name) {
+
+          case 'CRM_Profile_Form_Edit':
+            $page_id = $form->get('gid'); // gid, not id
+            $filter = $groups_field_filters['profile'][strval($page_id)];
+            break;
+
+          case 'CRM_Contribute_Form_Contribution_Main':
+          case 'CRM_Contribute_Form_Contribution_Confirm':
+          case 'CRM_Contribute_Form_Contribution_ThankYou':
+            $page_id = $form->get('id'); // id, not gid
+            $filter = $groups_field_filters['contribution'][strval($page_id)];
+            break;
+
+          case 'CRM_Event_Form_Registration_Register':
+            $page_id = $form->get('id'); // id, not gid
+            $filter = $groups_field_filters['event'][strval($page_id)];
+            break;
+        }
+        // sudoman hack continues further below
+
         $attributes['skiplabel'] = TRUE;
         $elements = [];
         $groupsOptions = [];
         foreach ($groups as $id => $group) {
+
+          // sudoman hack continues
+          // filter groups if a filter is set
+          if (isset($filter) and !in_array($id, $filter)) {
+            continue;
+          }
+          // sudoman hack continues with calls to CRM_Contact_Form_Edit_TagsAndGroups::reInsertFilteredGroupMemberships
+
           // make sure that this group has public visibility
           if ($visibility &&
             $group['visibility'] == 'User and User Admin Only'
@@ -216,4 +278,45 @@ class CRM_Contact_Form_Edit_TagsAndGroups {
     }
   }
 
+  /** re-add groups selectively filtered by sudoman's hack
+   *
+   * the sudoman hack continues from above and from calls to this function.
+   *
+   * re-add any filtered-out groups if the contact is already in those groups
+   * so createProfileContact() doesn't remove group memberships.
+   *
+   * @param int     $page_id (page number)
+   * @param string  $page_type ('profile', 'contribution' or 'event')
+   * @param int     $contactID (id of contact)
+   * @param bool    $ignorePermission (passed to getContactGroup, often TRUE)
+   * @param array   $params (for parameters)
+   *
+   * @return array  $params (modified parameters: active groups that were filtered are inserted)
+   */
+  public static function reInsertFilteredGroupMemberships($page_id, $page_type,
+      $contactID, $ignorePermission, $params) {
+
+    $groups_field_filters = json_decode(variable_get('groups_field_filters', NULL), $assoc = TRUE);
+    $filter = $groups_field_filters[$page_type][strval($page_id)];
+
+    if ($contactID !== NULL) {
+
+      $contactGroupList = &CRM_Contact_BAO_GroupContact::getContactGroup($contactID, 'Added',
+        NULL, FALSE, $ignorePermission
+      );
+
+      foreach ($contactGroupList as $value) {
+
+        $groupId = $value['group_id'];
+        if (!empty($filter) && !in_array($groupId, $filter)) {
+
+          $params['group'][strval($groupId)] = 1;
+        }
+      }
+    }
+
+    return $params;
+  }
+  // sudoman hack ends
+
 }
index f478e80e708e3530ca2b2fee3962e677c4077719..e369cb396ddfc0464fd076da2dc1ead39b65079c 100644 (file)
@@ -2191,6 +2191,10 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     else {
       $contactType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactID, 'contact_type');
     }
+
+    // sudoman hack: re-insert filtered group memberships
+    $params = CRM_Contact_Form_Edit_TagsAndGroups::reInsertFilteredGroupMemberships($this->_id, 'contribution', $contactID, TRUE, $params);
+
     $contactID = CRM_Contact_BAO_Contact::createProfileContact(
       $params,
       $fields,
index 14afb06fe5ba23bdd9b3f502c2eddab132cd7b3e..538b5014a786183d4a34b8f3ab577dce29e12fd8 100644 (file)
@@ -1104,6 +1104,9 @@ class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration {
         unset($params['contact_id']);
       }
 
+      // sudoman hack: re-insert filtered group memberships
+      $params = CRM_Contact_Form_Edit_TagsAndGroups::reInsertFilteredGroupMemberships($form->get('id'), 'event', $contactID, TRUE, $params);
+
       $contactID = CRM_Contact_BAO_Contact::createProfileContact(
         $params,
         $fields,
index 31fe2d96bd9e91e17ac37301154ad6b16e947947..01e3123b30efefc1aaf1b04f1d2b3674490aec0e 100644 (file)
@@ -1271,6 +1271,9 @@ class CRM_Profile_Form extends CRM_Core_Form {
       $params['customRecordValues'][$this->_recordId] = array_keys($this->_multiRecordFields);
     }
 
+    // sudoman hack: re-insert filtered group memberships
+    $params = CRM_Contact_Form_Edit_TagsAndGroups::reInsertFilteredGroupMemberships($this->_gid, 'profile', $this->_id, TRUE, $params);
+
     $this->_id = CRM_Contact_BAO_Contact::createProfileContact(
       $params,
       $profileFields,