/**
  * Get activity items, as specified by parameters.
  *
  * @since 1.2.0
  * @since 2.4.0 Introduced the `$fields` parameter.
  *
  * @see BP_Activity_Activity::get_filter_sql() for a description of the
  *      'filter' parameter.
  * @see WP_Meta_Query::queries for a description of the 'meta_query'
  *      parameter format.
  *
  * @param array $args {
  *     An array of arguments. All items are optional.
  *     @type int          $page              Which page of results to fetch. Using page=1 without per_page will result
  *                                           in no pagination. Default: 1.
  *     @type int|bool     $per_page          Number of results per page. Default: 25.
  *     @type int|bool     $max               Maximum number of results to return. Default: false (unlimited).
  *     @type string       $fields            Activity fields to return. Pass 'ids' to get only the activity IDs.
  *                                           'all' returns full activity objects.
  *     @type string       $sort              ASC or DESC. Default: 'DESC'.
  *     @type array        $exclude           Array of activity IDs to exclude. Default: false.
  *     @type array        $in                Array of ids to limit query by (IN). Default: false.
  *     @type array        $meta_query        Array of meta_query conditions. See WP_Meta_Query::queries.
  *     @type array        $date_query        Array of date_query conditions. See first parameter of
  *                                           WP_Date_Query::__construct().
  *     @type array        $filter_query      Array of advanced query conditions. See BP_Activity_Query::__construct().
  *     @type string|array $scope             Pre-determined set of activity arguments.
  *     @type array        $filter            See BP_Activity_Activity::get_filter_sql().
  *     @type string       $search_terms      Limit results by a search term. Default: false.
  *     @type bool         $display_comments  Whether to include activity comments. Default: false.
  *     @type bool         $show_hidden       Whether to show items marked hide_sitewide. Default: false.
  *     @type string       $spam              Spam status. Default: 'ham_only'.
  *     @type bool         $update_meta_cache Whether to pre-fetch metadata for queried activity items. Default: true.
  *     @type string|bool  $count_total       If true, an additional DB query is run to count the total activity items
  *                                           for the query. Default: false.
  * }
  * @return array The array returned has two keys:
  *               - 'total' is the count of located activities
  *               - 'activities' is an array of the located activities
  */
 public static function get($args = array())
 {
     global $wpdb;
     // Backward compatibility with old method of passing arguments.
     if (!is_array($args) || func_num_args() > 1) {
         _deprecated_argument(__METHOD__, '1.6', sprintf(__('Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress'), __METHOD__, __FILE__));
         $old_args_keys = array(0 => 'max', 1 => 'page', 2 => 'per_page', 3 => 'sort', 4 => 'search_terms', 5 => 'filter', 6 => 'display_comments', 7 => 'show_hidden', 8 => 'exclude', 9 => 'in', 10 => 'spam');
         $func_args = func_get_args();
         $args = bp_core_parse_args_array($old_args_keys, $func_args);
     }
     $bp = buddypress();
     $r = wp_parse_args($args, array('page' => 1, 'per_page' => 25, 'max' => false, 'fields' => 'all', 'sort' => 'DESC', 'exclude' => false, 'in' => false, 'meta_query' => false, 'date_query' => false, 'filter_query' => false, 'filter' => false, 'scope' => false, 'search_terms' => false, 'display_comments' => false, 'show_hidden' => false, 'spam' => 'ham_only', 'update_meta_cache' => true, 'count_total' => false));
     // Select conditions.
     $select_sql = "SELECT DISTINCT a.id";
     $from_sql = " FROM {$bp->activity->table_name} a";
     $join_sql = '';
     // Where conditions.
     $where_conditions = array();
     // Excluded types.
     $excluded_types = array();
     // Scope takes precedence.
     if (!empty($r['scope'])) {
         $scope_query = self::get_scope_query_sql($r['scope'], $r);
         // Add our SQL conditions if matches were found.
         if (!empty($scope_query['sql'])) {
             $where_conditions['scope_query_sql'] = $scope_query['sql'];
         }
         // Override some arguments if needed.
         if (!empty($scope_query['override'])) {
             $r = self::array_replace_recursive($r, $scope_query['override']);
         }
         // Advanced filtering.
     } elseif (!empty($r['filter_query'])) {
         $filter_query = new BP_Activity_Query($r['filter_query']);
         $sql = $filter_query->get_sql();
         if (!empty($sql)) {
             $where_conditions['filter_query_sql'] = $sql;
         }
     }
     // Regular filtering.
     if ($r['filter'] && ($filter_sql = BP_Activity_Activity::get_filter_sql($r['filter']))) {
         $where_conditions['filter_sql'] = $filter_sql;
     }
     // Spam.
     if ('ham_only' == $r['spam']) {
         $where_conditions['spam_sql'] = 'a.is_spam = 0';
     } elseif ('spam_only' == $r['spam']) {
         $where_conditions['spam_sql'] = 'a.is_spam = 1';
     }
     // Searching.
     if ($r['search_terms']) {
         $search_terms_like = '%' . bp_esc_like($r['search_terms']) . '%';
         $where_conditions['search_sql'] = $wpdb->prepare('a.content LIKE %s', $search_terms_like);
     }
     // Sorting.
     $sort = $r['sort'];
     if ($sort != 'ASC' && $sort != 'DESC') {
         $sort = 'DESC';
     }
     // Hide Hidden Items?
     if (!$r['show_hidden']) {
         $where_conditions['hidden_sql'] = "a.hide_sitewide = 0";
     }
     // Exclude specified items.
     if (!empty($r['exclude'])) {
         $exclude = implode(',', wp_parse_id_list($r['exclude']));
         $where_conditions['exclude'] = "a.id NOT IN ({$exclude})";
     }
     // The specific ids to which you want to limit the query.
     if (!empty($r['in'])) {
         $in = implode(',', wp_parse_id_list($r['in']));
         $where_conditions['in'] = "a.id IN ({$in})";
     }
     // Process meta_query into SQL.
     $meta_query_sql = self::get_meta_query_sql($r['meta_query']);
     if (!empty($meta_query_sql['join'])) {
         $join_sql .= $meta_query_sql['join'];
     }
     if (!empty($meta_query_sql['where'])) {
         $where_conditions[] = $meta_query_sql['where'];
     }
     // Process date_query into SQL.
     $date_query_sql = self::get_date_query_sql($r['date_query']);
     if (!empty($date_query_sql)) {
         $where_conditions['date'] = $date_query_sql;
     }
     // Alter the query based on whether we want to show activity item
     // comments in the stream like normal comments or threaded below
     // the activity.
     if (false === $r['display_comments'] || 'threaded' === $r['display_comments']) {
         $excluded_types[] = 'activity_comment';
     }
     // Exclude 'last_activity' items unless the 'action' filter has
     // been explicitly set.
     if (empty($r['filter']['object'])) {
         $excluded_types[] = 'last_activity';
     }
     // Build the excluded type sql part.
     if (!empty($excluded_types)) {
         $not_in = "'" . implode("', '", esc_sql($excluded_types)) . "'";
         $where_conditions['excluded_types'] = "a.type NOT IN ({$not_in})";
     }
     /**
      * Filters the MySQL WHERE conditions for the Activity items get method.
      *
      * @since 1.9.0
      *
      * @param array  $where_conditions Current conditions for MySQL WHERE statement.
      * @param array  $r                Parsed arguments passed into method.
      * @param string $select_sql       Current SELECT MySQL statement at point of execution.
      * @param string $from_sql         Current FROM MySQL statement at point of execution.
      * @param string $join_sql         Current INNER JOIN MySQL statement at point of execution.
      */
     $where_conditions = apply_filters('bp_activity_get_where_conditions', $where_conditions, $r, $select_sql, $from_sql, $join_sql);
     // Join the where conditions together.
     $where_sql = 'WHERE ' . join(' AND ', $where_conditions);
     /**
      * Filter the MySQL JOIN clause for the main activity query.
      *
      * @since 2.5.0
      *
      * @param string $join_sql   JOIN clause.
      * @param array  $r          Method parameters.
      * @param string $select_sql Current SELECT MySQL statement.
      * @param string $from_sql   Current FROM MySQL statement.
      * @param string $where_sql  Current WHERE MySQL statement.
      */
     $join_sql = apply_filters('bp_activity_get_join_sql', $join_sql, $r, $select_sql, $from_sql, $where_sql);
     /**
      * Filters the preferred order of indexes for activity item.
      *
      * @since 1.6.0
      *
      * @param array $value Array of indexes in preferred order.
      */
     $indexes = apply_filters('bp_activity_preferred_index_order', array('user_id', 'item_id', 'secondary_item_id', 'date_recorded', 'component', 'type', 'hide_sitewide', 'is_spam'));
     foreach ($indexes as $key => $index) {
         if (false !== strpos($where_sql, $index)) {
             $the_index = $index;
             break;
             // Take the first one we find.
         }
     }
     if (!empty($the_index)) {
         $index_hint_sql = "USE INDEX ({$the_index})";
     } else {
         $index_hint_sql = '';
     }
     // Sanitize page and per_page parameters.
     $page = absint($r['page']);
     $per_page = absint($r['per_page']);
     $retval = array('activities' => null, 'total' => null, 'has_more_items' => null);
     /**
      * Filters if BuddyPress should use legacy query structure over current structure for version 2.0+.
      *
      * It is not recommended to use the legacy structure, but allowed to if needed.
      *
      * @since 2.0.0
      *
      * @param bool                 $value Whether to use legacy structure or not.
      * @param BP_Activity_Activity $value Current method being called.
      * @param array                $r     Parsed arguments passed into method.
      */
     if (apply_filters('bp_use_legacy_activity_query', false, __METHOD__, $r)) {
         // Legacy queries joined against the user table.
         $select_sql = "SELECT DISTINCT a.*, u.user_email, u.user_nicename, u.user_login, u.display_name";
         $from_sql = " FROM {$bp->activity->table_name} a LEFT JOIN {$wpdb->users} u ON a.user_id = u.ID";
         if (!empty($page) && !empty($per_page)) {
             $pag_sql = $wpdb->prepare("LIMIT %d, %d", absint(($page - 1) * $per_page), $per_page);
             /** This filter is documented in bp-activity/bp-activity-classes.php */
             $activities = $wpdb->get_results(apply_filters('bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}, a.id {$sort} {$pag_sql}", $select_sql, $from_sql, $where_sql, $sort, $pag_sql));
         } else {
             $pag_sql = '';
             /**
              * Filters the legacy MySQL query statement so plugins can alter before results are fetched.
              *
              * @since 1.5.0
              *
              * @param string $value      Concatenated MySQL statement pieces to be query results with for legacy query.
              * @param string $select_sql Final SELECT MySQL statement portion for legacy query.
              * @param string $from_sql   Final FROM MySQL statement portion for legacy query.
              * @param string $where_sql  Final WHERE MySQL statement portion for legacy query.
              * @param string $sort       Final sort direction for legacy query.
              */
             $activities = $wpdb->get_results(apply_filters('bp_activity_get_user_join_filter', "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}, a.id {$sort}", $select_sql, $from_sql, $where_sql, $sort, $pag_sql));
         }
         // Integer casting for legacy activity query.
         foreach ((array) $activities as $i => $ac) {
             $activities[$i]->id = (int) $ac->id;
             $activities[$i]->item_id = (int) $ac->item_id;
             $activities[$i]->secondary_item_id = (int) $ac->secondary_item_id;
             $activities[$i]->user_id = (int) $ac->user_id;
             $activities[$i]->hide_sitewide = (int) $ac->hide_sitewide;
             $activities[$i]->mptt_left = (int) $ac->mptt_left;
             $activities[$i]->mptt_right = (int) $ac->mptt_right;
             $activities[$i]->is_spam = (int) $ac->is_spam;
         }
     } else {
         // Query first for activity IDs.
         $activity_ids_sql = "{$select_sql} {$from_sql} {$join_sql} {$where_sql} ORDER BY a.date_recorded {$sort}, a.id {$sort}";
         if (!empty($per_page) && !empty($page)) {
             // We query for $per_page + 1 items in order to
             // populate the has_more_items flag.
             $activity_ids_sql .= $wpdb->prepare(" LIMIT %d, %d", absint(($page - 1) * $per_page), $per_page + 1);
         }
         /**
          * Filters the paged activities MySQL statement.
          *
          * @since 2.0.0
          *
          * @param string $activity_ids_sql MySQL statement used to query for Activity IDs.
          * @param array  $r                Array of arguments passed into method.
          */
         $activity_ids_sql = apply_filters('bp_activity_paged_activities_sql', $activity_ids_sql, $r);
         /*
          * Queries that include 'last_activity' are cached separately,
          * since they are generally much less long-lived.
          */
         if (preg_match('/a\\.type NOT IN \\([^\\)]*\'last_activity\'[^\\)]*\\)/', $activity_ids_sql)) {
             $cache_group = 'bp_activity';
         } else {
             $cache_group = 'bp_activity_with_last_activity';
         }
         $cached = bp_core_get_incremented_cache($activity_ids_sql, $cache_group);
         if (false === $cached) {
             $activity_ids = $wpdb->get_col($activity_ids_sql);
             bp_core_set_incremented_cache($activity_ids_sql, $cache_group, $activity_ids);
         } else {
             $activity_ids = $cached;
         }
         $retval['has_more_items'] = !empty($per_page) && count($activity_ids) > $per_page;
         // If we've fetched more than the $per_page value, we
         // can discard the extra now.
         if (!empty($per_page) && count($activity_ids) === $per_page + 1) {
             array_pop($activity_ids);
         }
         if ('ids' === $r['fields']) {
             $activities = array_map('intval', $activity_ids);
         } else {
             $activities = self::get_activity_data($activity_ids);
         }
     }
     if ('ids' !== $r['fields']) {
         // Get the fullnames of users so we don't have to query in the loop.
         $activities = self::append_user_fullnames($activities);
         // Get activity meta.
         $activity_ids = array();
         foreach ((array) $activities as $activity) {
             $activity_ids[] = $activity->id;
         }
         if (!empty($activity_ids) && $r['update_meta_cache']) {
             bp_activity_update_meta_cache($activity_ids);
         }
         if ($activities && $r['display_comments']) {
             $activities = BP_Activity_Activity::append_comments($activities, $r['spam']);
         }
         // Pre-fetch data associated with activity users and other objects.
         BP_Activity_Activity::prefetch_object_data($activities);
         // Generate action strings.
         $activities = BP_Activity_Activity::generate_action_strings($activities);
     }
     $retval['activities'] = $activities;
     // If $max is set, only return up to the max results.
     if (!empty($r['count_total'])) {
         /**
          * Filters the total activities MySQL statement.
          *
          * @since 1.5.0
          *
          * @param string $value     MySQL statement used to query for total activities.
          * @param string $where_sql MySQL WHERE statement portion.
          * @param string $sort      Sort direction for query.
          */
         $total_activities_sql = apply_filters('bp_activity_total_activities_sql', "SELECT count(DISTINCT a.id) FROM {$bp->activity->table_name} a {$join_sql} {$where_sql}", $where_sql, $sort);
         $cached = bp_core_get_incremented_cache($total_activities_sql, $cache_group);
         if (false === $cached) {
             $total_activities = $wpdb->get_var($total_activities_sql);
             bp_core_set_incremented_cache($total_activities_sql, $cache_group, $total_activities);
         } else {
             $total_activities = $cached;
         }
         if (!empty($r['max'])) {
             if ((int) $total_activities > (int) $r['max']) {
                 $total_activities = $r['max'];
             }
         }
         $retval['total'] = $total_activities;
     }
     return $retval;
 }
 /**
  * Query for groups.
  *
  * @see WP_Meta_Query::queries for a description of the 'meta_query'
  *      parameter format.
  *
  * @since 1.6.0
  * @since 2.6.0 Added `$group_type`, `$group_type__in`, and `$group_type__not_in` parameters.
  * @since 2.7.0 Added `$update_admin_cache` and `$parent_id` parameters.
  *
  * @param array $args {
  *     Array of parameters. All items are optional.
  *     @type string       $type               Optional. Shorthand for certain orderby/order combinations.
  *                                            'newest', 'active', 'popular', 'alphabetical', 'random'.
  *                                            When present, will override orderby and order params.
  *                                            Default: null.
  *     @type string       $orderby            Optional. Property to sort by. 'date_created', 'last_activity',
  *                                            'total_member_count', 'name', 'random'. Default: 'date_created'.
  *     @type string       $order              Optional. Sort order. 'ASC' or 'DESC'. Default: 'DESC'.
  *     @type int          $per_page           Optional. Number of items to return per page of results.
  *                                            Default: null (no limit).
  *     @type int          $page               Optional. Page offset of results to return.
  *                                            Default: null (no limit).
  *     @type int          $user_id            Optional. If provided, results will be limited to groups
  *                                            of which the specified user is a member. Default: null.
  *     @type string       $search_terms       Optional. If provided, only groups whose names or descriptions
  *                                            match the search terms will be returned. Default: false.
  *     @type array|string $group_type         Array or comma-separated list of group types to limit results to.
  *     @type array|string $group_type__in     Array or comma-separated list of group types to limit results to.
  *     @type array|string $group_type__not_in Array or comma-separated list of group types that will be
  *                                            excluded from results.
  *     @type array        $meta_query         Optional. An array of meta_query conditions.
  *                                            See {@link WP_Meta_Query::queries} for description.
  *     @type array|string $value              Optional. Array or comma-separated list of group IDs. Results
  *                                            will be limited to groups within the list. Default: false.
  *     @type array|string $parent_id          Optional. Array or comma-separated list of group IDs. Results
  *                                            will be limited to children of the specified groups. Default: null.
  *     @type array|string $exclude            Optional. Array or comma-separated list of group IDs.
  *                                            Results will exclude the listed groups. Default: false.
  *     @type bool         $update_meta_cache  Whether to pre-fetch groupmeta for the returned groups.
  *                                            Default: true.
  *     @type bool         $update_admin_cache Whether to pre-fetch administrator IDs for the returned
  *                                            groups. Default: false.
  *     @type bool         $show_hidden        Whether to include hidden groups in results. Default: false.
  * }
  * @return array {
  *     @type array $groups Array of group objects returned by the
  *                         paginated query.
  *     @type int   $total  Total count of all groups matching non-
  *                         paginated query params.
  * }
  */
 public static function get($args = array())
 {
     global $wpdb;
     // Backward compatibility with old method of passing arguments.
     if (!is_array($args) || func_num_args() > 1) {
         _deprecated_argument(__METHOD__, '1.7', sprintf(__('Arguments passed to %1$s should be in an associative array. See the inline documentation at %2$s for more details.', 'buddypress'), __METHOD__, __FILE__));
         $old_args_keys = array(0 => 'type', 1 => 'per_page', 2 => 'page', 3 => 'user_id', 4 => 'search_terms', 5 => 'include', 6 => 'populate_extras', 7 => 'exclude', 8 => 'show_hidden');
         $func_args = func_get_args();
         $args = bp_core_parse_args_array($old_args_keys, $func_args);
     }
     $defaults = array('type' => null, 'orderby' => 'date_created', 'order' => 'DESC', 'per_page' => null, 'page' => null, 'user_id' => 0, 'search_terms' => false, 'group_type' => '', 'group_type__in' => '', 'group_type__not_in' => '', 'meta_query' => false, 'include' => false, 'parent_id' => null, 'update_meta_cache' => true, 'update_admin_cache' => false, 'exclude' => false, 'show_hidden' => false);
     $r = wp_parse_args($args, $defaults);
     $bp = buddypress();
     $sql = array('select' => "SELECT DISTINCT g.id", 'from' => "{$bp->groups->table_name} g", 'where' => '', 'orderby' => '', 'pagination' => '');
     if (!empty($r['user_id'])) {
         $sql['from'] .= " JOIN {$bp->groups->table_name_members} m ON ( g.id = m.group_id )";
     }
     $where_conditions = array();
     if (empty($r['show_hidden'])) {
         $where_conditions['hidden'] = "g.status != 'hidden'";
     }
     if (!empty($r['search_terms'])) {
         $search_terms_like = '%' . bp_esc_like($r['search_terms']) . '%';
         $where_conditions['search'] = $wpdb->prepare("( g.name LIKE %s OR g.description LIKE %s )", $search_terms_like, $search_terms_like);
     }
     $meta_query_sql = self::get_meta_query_sql($r['meta_query']);
     if (!empty($meta_query_sql['join'])) {
         $sql['from'] .= $meta_query_sql['join'];
     }
     if (!empty($meta_query_sql['where'])) {
         $where_conditions['meta'] = $meta_query_sql['where'];
     }
     // Only use 'group_type__in', if 'group_type' is not set.
     if (empty($r['group_type']) && !empty($r['group_type__in'])) {
         $r['group_type'] = $r['group_type__in'];
     }
     // Group types to exclude. This has priority over inclusions.
     if (!empty($r['group_type__not_in'])) {
         $group_type_clause = self::get_sql_clause_for_group_types($r['group_type__not_in'], 'NOT IN');
         // Group types to include.
     } elseif (!empty($r['group_type'])) {
         $group_type_clause = self::get_sql_clause_for_group_types($r['group_type'], 'IN');
     }
     if (!empty($group_type_clause)) {
         $where_conditions['group_type'] = $group_type_clause;
     }
     if (!empty($r['user_id'])) {
         $where_conditions['user'] = $wpdb->prepare("m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0", $r['user_id']);
     }
     if (!empty($r['include'])) {
         $include = implode(',', wp_parse_id_list($r['include']));
         $where_conditions['include'] = "g.id IN ({$include})";
     }
     if (!is_null($r['parent_id'])) {
         // Note that `wp_parse_id_list()` converts `false` to 0.
         $parent_id = implode(',', wp_parse_id_list($r['parent_id']));
         $where_conditions['parent_id'] = "g.parent_id IN ({$parent_id})";
     }
     if (!empty($r['exclude'])) {
         $exclude = implode(',', wp_parse_id_list($r['exclude']));
         $where_conditions['exclude'] = "g.id NOT IN ({$exclude})";
     }
     /* Order/orderby ********************************************/
     $order = $r['order'];
     $orderby = $r['orderby'];
     // If a 'type' parameter was passed, parse it and overwrite
     // 'order' and 'orderby' params passed to the function.
     if (!empty($r['type'])) {
         /**
          * Filters the 'type' parameter used to overwrite 'order' and 'orderby' values.
          *
          * @since 2.1.0
          *
          * @param array  $value Converted 'type' value for order and orderby.
          * @param string $value Parsed 'type' value for the get method.
          */
         $order_orderby = apply_filters('bp_groups_get_orderby', self::convert_type_to_order_orderby($r['type']), $r['type']);
         // If an invalid type is passed, $order_orderby will be
         // an array with empty values. In this case, we stick
         // with the default values of $order and $orderby.
         if (!empty($order_orderby['order'])) {
             $order = $order_orderby['order'];
         }
         if (!empty($order_orderby['orderby'])) {
             $orderby = $order_orderby['orderby'];
         }
     }
     // 'total_member_count' and 'last_activity' sorts require additional table joins.
     if ('total_member_count' === $orderby) {
         $sql['from'] .= " JOIN {$bp->groups->table_name_groupmeta} gm_total_member_count ON ( g.id = gm_total_member_count.group_id )";
         $where_conditions['total_member_count'] = "gm_total_member_count.meta_key = 'total_member_count'";
     } elseif ('last_activity' === $orderby) {
         $sql['from'] .= " JOIN {$bp->groups->table_name_groupmeta} gm_last_activity on ( g.id = gm_last_activity.group_id )";
         $where_conditions['last_activity'] = "gm_last_activity.meta_key = 'last_activity'";
     }
     // Sanitize 'order'.
     $order = bp_esc_sql_order($order);
     /**
      * Filters the converted 'orderby' term.
      *
      * @since 2.1.0
      *
      * @param string $value   Converted 'orderby' term.
      * @param string $orderby Original orderby value.
      * @param string $value   Parsed 'type' value for the get method.
      */
     $orderby = apply_filters('bp_groups_get_orderby_converted_by_term', self::convert_orderby_to_order_by_term($orderby), $orderby, $r['type']);
     // Random order is a special case.
     if ('rand()' === $orderby) {
         $sql['orderby'] = "ORDER BY rand()";
     } else {
         $sql['orderby'] = "ORDER BY {$orderby} {$order}";
     }
     if (!empty($r['per_page']) && !empty($r['page']) && $r['per_page'] != -1) {
         $sql['pagination'] = $wpdb->prepare("LIMIT %d, %d", intval(($r['page'] - 1) * $r['per_page']), intval($r['per_page']));
     }
     $where = '';
     if (!empty($where_conditions)) {
         $sql['where'] = implode(' AND ', $where_conditions);
         $where = "WHERE {$sql['where']}";
     }
     $paged_groups_sql = "{$sql['select']} FROM {$sql['from']} {$where} {$sql['orderby']} {$sql['pagination']}";
     /**
      * Filters the pagination SQL statement.
      *
      * @since 1.5.0
      *
      * @param string $value Concatenated SQL statement.
      * @param array  $sql   Array of SQL parts before concatenation.
      * @param array  $r     Array of parsed arguments for the get method.
      */
     $paged_groups_sql = apply_filters('bp_groups_get_paged_groups_sql', $paged_groups_sql, $sql, $r);
     $cached = bp_core_get_incremented_cache($paged_groups_sql, 'bp_groups');
     if (false === $cached) {
         $paged_group_ids = $wpdb->get_col($paged_groups_sql);
         bp_core_set_incremented_cache($paged_groups_sql, 'bp_groups', $paged_group_ids);
     } else {
         $paged_group_ids = $cached;
     }
     $uncached_group_ids = bp_get_non_cached_ids($paged_group_ids, 'bp_groups');
     if ($uncached_group_ids) {
         $group_ids_sql = implode(',', array_map('intval', $uncached_group_ids));
         $group_data_objects = $wpdb->get_results("SELECT g.* FROM {$bp->groups->table_name} g WHERE g.id IN ({$group_ids_sql})");
         foreach ($group_data_objects as $group_data_object) {
             wp_cache_set($group_data_object->id, $group_data_object, 'bp_groups');
         }
     }
     $paged_groups = array();
     foreach ($paged_group_ids as $paged_group_id) {
         $paged_groups[] = new BP_Groups_Group($paged_group_id);
     }
     $total_groups_sql = "SELECT COUNT(DISTINCT g.id) FROM {$sql['from']} {$where}";
     /**
      * Filters the SQL used to retrieve total group results.
      *
      * @since 1.5.0
      *
      * @param string $t_sql     Concatenated SQL statement used for retrieving total group results.
      * @param array  $total_sql Array of SQL parts for the query.
      * @param array  $r         Array of parsed arguments for the get method.
      */
     $total_groups_sql = apply_filters('bp_groups_get_total_groups_sql', $total_groups_sql, $sql, $r);
     $cached = bp_core_get_incremented_cache($total_groups_sql, 'bp_groups');
     if (false === $cached) {
         $total_groups = (int) $wpdb->get_var($total_groups_sql);
         bp_core_set_incremented_cache($total_groups_sql, 'bp_groups', $total_groups);
     } else {
         $total_groups = (int) $cached;
     }
     $group_ids = array();
     foreach ((array) $paged_groups as $group) {
         $group_ids[] = $group->id;
     }
     // Grab all groupmeta.
     if (!empty($r['update_meta_cache'])) {
         bp_groups_update_meta_cache($group_ids);
     }
     // Prefetch all administrator IDs, if requested.
     if ($r['update_admin_cache']) {
         BP_Groups_Member::prime_group_admins_mods_cache($group_ids);
     }
     // Set up integer properties needing casting.
     $int_props = array('id', 'creator_id', 'enable_forum');
     // Integer casting.
     foreach ($paged_groups as $key => $g) {
         foreach ($int_props as $int_prop) {
             $paged_groups[$key]->{$int_prop} = (int) $paged_groups[$key]->{$int_prop};
         }
     }
     unset($sql, $total_sql);
     return array('groups' => $paged_groups, 'total' => $total_groups);
 }