/** * @group bp_xprofile_update_meta_cache */ public function test_bp_xprofile_update_meta_cache() { $u = $this->factory->user->create(); $g = $this->factory->xprofile_group->create(); $f = $this->factory->xprofile_field->create(array('field_group_id' => $g)); $d = new BP_XProfile_ProfileData($f, $u); $d->user_id = $u; $d->field_id = $f; $d->value = 'foo'; $d->last_updated = bp_core_current_time(); $d->save(); bp_xprofile_add_meta($g, 'group', 'group_foo', 'group_bar'); bp_xprofile_add_meta($f, 'field', 'field_foo', 'field_bar'); bp_xprofile_add_meta($d->id, 'data', 'data_foo', 'data_bar'); // prime cache bp_xprofile_update_meta_cache(array('group' => array($g), 'field' => array($f), 'data' => array($d->id))); $g_expected = array('group_foo' => array('group_bar')); $this->assertSame($g_expected, wp_cache_get($g, 'xprofile_group_meta')); $f_expected = array('field_foo' => array('field_bar')); $this->assertSame($f_expected, wp_cache_get($f, 'xprofile_field_meta')); $d_expected = array('data_foo' => array('data_bar')); $this->assertSame($d_expected, wp_cache_get($d->id, 'xprofile_data_meta')); }
/** * get() * * Populates the BP_XProfile_Group object with profile field groups, fields, and field data * * @package BuddyPress XProfile * * @global $wpdb WordPress DB access object. * @global BuddyPress $bp The one true BuddyPress instance * * @param array $args Takes an array of parameters: * 'profile_group_id' - Limit results to a single profile group * 'user_id' - Required if you want to load a specific user's data * 'hide_empty_groups' - Hide groups without any fields * 'hide_empty_fields' - Hide fields where the user has not provided data * 'fetch_fields' - Load each group's fields * 'fetch_field_data' - Load each field's data. Requires a user_id * 'exclude_groups' - Comma-separated list of groups to exclude * 'exclude_fields' - Comma-separated list of fields to exclude * 'update_meta_cache' - Whether to pre-fetch xprofilemeta * for all retrieved groups, fields, and data * * @return array $groups */ public static function get($args = array()) { global $wpdb, $bp; $defaults = array('profile_group_id' => false, 'user_id' => bp_displayed_user_id(), 'hide_empty_groups' => false, 'hide_empty_fields' => false, 'fetch_fields' => false, 'fetch_field_data' => false, 'fetch_visibility_level' => false, 'exclude_groups' => false, 'exclude_fields' => false, 'update_meta_cache' => true); $r = wp_parse_args($args, $defaults); extract($r, EXTR_SKIP); // Keep track of object IDs for cache-priming $object_ids = array('group' => array(), 'field' => array(), 'data' => array()); $where_sql = ''; if (!empty($profile_group_id)) { $where_sql = $wpdb->prepare('WHERE g.id = %d', $profile_group_id); } elseif ($exclude_groups) { $where_sql = $wpdb->prepare("WHERE g.id NOT IN ({$exclude_groups})"); } if (!empty($hide_empty_groups)) { $group_ids = $wpdb->get_col("SELECT DISTINCT g.id FROM {$bp->profile->table_name_groups} g INNER JOIN {$bp->profile->table_name_fields} f ON g.id = f.group_id {$where_sql} ORDER BY g.group_order ASC"); } else { $group_ids = $wpdb->get_col("SELECT DISTINCT g.id FROM {$bp->profile->table_name_groups} g {$where_sql} ORDER BY g.group_order ASC"); } $groups = self::get_group_data($group_ids); if (empty($fetch_fields)) { return $groups; } // Get the group ids $group_ids = array(); foreach ((array) $groups as $group) { $group_ids[] = $group->id; } // Store for meta cache priming $object_ids['group'] = $group_ids; $group_ids = implode(',', (array) $group_ids); if (empty($group_ids)) { return $groups; } // Support arrays and comma-separated strings $exclude_fields_cs = wp_parse_id_list($exclude_fields); // Visibility - Handled here so as not to be overridden by sloppy use of the // exclude_fields parameter. See bp_xprofile_get_hidden_fields_for_user() $exclude_fields_cs = array_merge($exclude_fields_cs, bp_xprofile_get_hidden_fields_for_user($user_id)); $exclude_fields_cs = implode(',', $exclude_fields_cs); if (!empty($exclude_fields_cs)) { $exclude_fields_sql = "AND id NOT IN ({$exclude_fields_cs})"; } else { $exclude_fields_sql = ''; } // Fetch the fields $fields = $wpdb->get_results("SELECT id, name, description, type, group_id, is_required FROM {$bp->profile->table_name_fields} WHERE group_id IN ( {$group_ids} ) AND parent_id = 0 {$exclude_fields_sql} ORDER BY field_order"); // Store field IDs for meta cache priming $object_ids['field'] = wp_list_pluck($fields, 'id'); if (empty($fields)) { return $groups; } // Maybe fetch field data if (!empty($fetch_field_data)) { // Fetch the field data for the user. foreach ((array) $fields as $field) { $field_ids[] = $field->id; } $field_ids_sql = implode(',', (array) $field_ids); if (!empty($field_ids) && !empty($user_id)) { $field_data = BP_XProfile_ProfileData::get_data_for_user($user_id, $field_ids); } // Remove data-less fields, if necessary if (!empty($hide_empty_fields) && !empty($field_ids) && !empty($field_data)) { // Loop through the results and find the fields that have data. foreach ((array) $field_data as $data) { // Empty fields may contain a serialized empty array $maybe_value = maybe_unserialize($data->value); if (!empty($maybe_value) && false !== ($key = array_search($data->field_id, $field_ids))) { // Fields that have data get removed from the list unset($field_ids[$key]); } } // The remaining members of $field_ids are empty. Remove them. foreach ($fields as $field_key => $field) { if (in_array($field->id, $field_ids)) { unset($fields[$field_key]); } } // Reset indexes $fields = array_values($fields); } // Field data was found if (!empty($fields) && !empty($field_data) && !is_wp_error($field_data)) { // Loop through fields foreach ((array) $fields as $field_key => $field) { // Loop throught the data in each field foreach ((array) $field_data as $data) { // Assign correct data value to the field if ($field->id == $data->field_id) { $fields[$field_key]->data = new stdClass(); $fields[$field_key]->data->value = $data->value; $fields[$field_key]->data->id = $data->id; } // Store for meta cache priming $object_ids['data'][] = $data->id; } } } } // Prime the meta cache, if necessary if ($update_meta_cache) { bp_xprofile_update_meta_cache($object_ids); } // Maybe fetch visibility levels if (!empty($fetch_visibility_level)) { $fields = self::fetch_visibility_level($user_id, $fields); } // Merge the field array back in with the group array foreach ((array) $groups as $group) { // Indexes may have been shifted after previous deletions, so we get a // fresh one each time through the loop $index = array_search($group, $groups); foreach ((array) $fields as $field) { if ($group->id == $field->group_id) { $groups[$index]->fields[] = $field; } } // When we unset fields above, we may have created empty groups. // Remove them, if necessary. if (empty($group->fields) && $hide_empty_groups) { unset($groups[$index]); } // Reset indexes $groups = array_values($groups); } return $groups; }
/** * Populates the BP_XProfile_Group object with profile field groups, fields, * and field data * * @package BuddyPress XProfile * * @global object $wpdb WordPress DB access object. * * @param array $args { * Array of optional arguments: * @type int $profile_group_id Limit results to a single profile group. * @type int $user_id Required if you want to load a specific user's data. * Default: displayed user's ID. * @type array|string $member_type Limit fields by those restricted to a given member type, or array of * member types. If `$user_id` is provided, the value of `$member_type` * will be overridden by the member types of the provided user. The * special value of 'any' will return only those fields that are * unrestricted by member type - i.e., those applicable to any type. * @type bool $hide_empty_groups True to hide groups that don't have any fields. Default: false. * @type bool $hide_empty_fields True to hide fields where the user has not provided data. * Default: false. * @type bool $fetch_fields Whether to fetch each group's fields. Default: false. * @type bool $fetch_field_data Whether to fetch data for each field. Requires a $user_id. * Default: false. * @type array $exclude_groups Comma-separated list or array of group IDs to exclude. * @type array $exclude_fields Comma-separated list or array of field IDs to exclude. * @type bool $update_meta_cache Whether to pre-fetch xprofilemeta for all retrieved groups, fields, * and data. Default: true. * } * @return array $groups */ public static function get($args = array()) { global $wpdb; // Parse arguments. $r = wp_parse_args($args, array('profile_group_id' => false, 'user_id' => bp_displayed_user_id(), 'member_type' => false, 'hide_empty_groups' => false, 'hide_empty_fields' => false, 'fetch_fields' => false, 'fetch_field_data' => false, 'fetch_visibility_level' => false, 'exclude_groups' => false, 'exclude_fields' => false, 'update_meta_cache' => true)); // Keep track of object IDs for cache-priming. $object_ids = array('group' => array(), 'field' => array(), 'data' => array()); // WHERE. if (!empty($r['profile_group_id'])) { $where_sql = $wpdb->prepare('WHERE g.id = %d', $r['profile_group_id']); } elseif ($r['exclude_groups']) { $exclude = join(',', wp_parse_id_list($r['exclude_groups'])); $where_sql = "WHERE g.id NOT IN ({$exclude})"; } else { $where_sql = ''; } $bp = buddypress(); // Include or exclude empty groups. if (!empty($r['hide_empty_groups'])) { $group_ids = $wpdb->get_col("SELECT DISTINCT g.id FROM {$bp->profile->table_name_groups} g INNER JOIN {$bp->profile->table_name_fields} f ON g.id = f.group_id {$where_sql} ORDER BY g.group_order ASC"); } else { $group_ids = $wpdb->get_col("SELECT DISTINCT g.id FROM {$bp->profile->table_name_groups} g {$where_sql} ORDER BY g.group_order ASC"); } // Get all group data. $groups = self::get_group_data($group_ids); // Bail if not also getting fields. if (empty($r['fetch_fields'])) { return $groups; } // Get the group ids from the groups we found. $group_ids = wp_list_pluck($groups, 'id'); // Store for meta cache priming. $object_ids['group'] = $group_ids; // Bail if no groups found. if (empty($group_ids)) { return $groups; } // Setup IN query from group IDs. $group_ids_in = implode(',', (array) $group_ids); // Support arrays and comma-separated strings. $exclude_fields_cs = wp_parse_id_list($r['exclude_fields']); // Visibility - Handled here so as not to be overridden by sloppy use of the // exclude_fields parameter. See bp_xprofile_get_hidden_fields_for_user(). $hidden_user_fields = bp_xprofile_get_hidden_fields_for_user($r['user_id']); $exclude_fields_cs = array_merge($exclude_fields_cs, $hidden_user_fields); $exclude_fields_cs = implode(',', $exclude_fields_cs); // Set up NOT IN query for excluded field IDs. if (!empty($exclude_fields_cs)) { $exclude_fields_sql = "AND id NOT IN ({$exclude_fields_cs})"; } else { $exclude_fields_sql = ''; } // Set up IN query for included field IDs. $include_field_ids = array(); // Member-type restrictions. if (bp_get_member_types()) { if ($r['user_id'] || false !== $r['member_type']) { $member_types = $r['member_type']; if ($r['user_id']) { $member_types = bp_get_member_type($r['user_id'], false); if (empty($member_types)) { $member_types = array('null'); } } $member_types_fields = BP_XProfile_Field::get_fields_for_member_type($member_types); $include_field_ids += array_keys($member_types_fields); } } $in_sql = ''; if (!empty($include_field_ids)) { $include_field_ids_cs = implode(',', array_map('intval', $include_field_ids)); $in_sql = " AND id IN ({$include_field_ids_cs}) "; } // Fetch the fields. $field_ids = $wpdb->get_col("SELECT id FROM {$bp->profile->table_name_fields} WHERE group_id IN ( {$group_ids_in} ) AND parent_id = 0 {$exclude_fields_sql} {$in_sql} ORDER BY field_order"); // Bail if no fields. if (empty($field_ids)) { return $groups; } $field_ids = array_map('intval', $field_ids); // Prime the field cache. $uncached_field_ids = bp_get_non_cached_ids($field_ids, 'bp_xprofile_fields'); if (!empty($uncached_field_ids)) { $_uncached_field_ids = implode(',', array_map('intval', $uncached_field_ids)); $uncached_fields = $wpdb->get_results("SELECT * FROM {$bp->profile->table_name_fields} WHERE id IN ({$_uncached_field_ids})"); foreach ($uncached_fields as $uncached_field) { $fid = intval($uncached_field->id); wp_cache_set($fid, $uncached_field, 'bp_xprofile_fields'); } } // Pull field objects from the cache. $fields = array(); foreach ($field_ids as $field_id) { $fields[] = xprofile_get_field($field_id); } // Store field IDs for meta cache priming. $object_ids['field'] = $field_ids; // Maybe fetch field data. if (!empty($r['fetch_field_data'])) { // Get field data for user ID. if (!empty($field_ids) && !empty($r['user_id'])) { $field_data = BP_XProfile_ProfileData::get_data_for_user($r['user_id'], $field_ids); } // Remove data-less fields, if necessary. if (!empty($r['hide_empty_fields']) && !empty($field_ids) && !empty($field_data)) { // Loop through the results and find the fields that have data. foreach ((array) $field_data as $data) { // Empty fields may contain a serialized empty array. $maybe_value = maybe_unserialize($data->value); // Valid field values of 0 or '0' get caught by empty(), so we have an extra check for these. See #BP5731. if ((!empty($maybe_value) || '0' == $maybe_value) && false !== ($key = array_search($data->field_id, $field_ids))) { // Fields that have data get removed from the list. unset($field_ids[$key]); } } // The remaining members of $field_ids are empty. Remove them. foreach ($fields as $field_key => $field) { if (in_array($field->id, $field_ids)) { unset($fields[$field_key]); } } // Reset indexes. $fields = array_values($fields); } // Field data was found. if (!empty($fields) && !empty($field_data) && !is_wp_error($field_data)) { // Loop through fields. foreach ((array) $fields as $field_key => $field) { // Loop through the data in each field. foreach ((array) $field_data as $data) { // Assign correct data value to the field. if ($field->id == $data->field_id) { $fields[$field_key]->data = new stdClass(); $fields[$field_key]->data->value = $data->value; $fields[$field_key]->data->id = $data->id; } // Store for meta cache priming. $object_ids['data'][] = $data->id; } } } } // Prime the meta cache, if necessary. if (!empty($r['update_meta_cache'])) { bp_xprofile_update_meta_cache($object_ids); } // Maybe fetch visibility levels. if (!empty($r['fetch_visibility_level'])) { $fields = self::fetch_visibility_level($r['user_id'], $fields); } // Merge the field array back in with the group array. foreach ((array) $groups as $group) { // Indexes may have been shifted after previous deletions, so we get a // fresh one each time through the loop. $index = array_search($group, $groups); foreach ((array) $fields as $field) { if ($group->id === $field->group_id) { $groups[$index]->fields[] = $field; } } // When we unset fields above, we may have created empty groups. // Remove them, if necessary. if (empty($group->fields) && !empty($r['hide_empty_groups'])) { unset($groups[$index]); } // Reset indexes. $groups = array_values($groups); } return $groups; }