Skip to:
Content

BuddyPress.org

Ticket #4060: 4060.01.patch

File 4060.01.patch, 15.9 KB (added by boonebgorges, 13 years ago)
  • bp-core/bp-core-classes.php

    diff --git bp-core/bp-core-classes.php bp-core/bp-core-classes.php
    index 8214f2f..16ac5cf 100644
     
    22// Exit if accessed directly
    33if ( !defined( 'ABSPATH' ) ) exit;
    44
     5class BP_User_Query {
     6        var $query_vars = array();
     7
     8        /**
     9         * List of found user ids
     10         *
     11         * @since 3.1.0
     12         * @access private
     13         * @var array
     14         */
     15        var $results;
     16
     17        var $user_ids;
     18
     19        /**
     20         * Total number of found users for the current query
     21         *
     22         * @since 3.1.0
     23         * @access private
     24         * @var int
     25         */
     26        var $total_users = 0;
     27
     28        // SQL clauses for the user ID query
     29        var $uid_clauses;
     30
     31        /**
     32         * Constructor
     33         *
     34         * @since 1.7
     35         *
     36         * @param string|array $query The query variables
     37         */
     38        function __construct( $query = null ) {
     39                if ( !empty( $query ) ) {
     40                        $this->query_vars = wp_parse_args( $query, array(
     41                                'type'            => 'newest',
     42                                'per_page'        => 0,
     43                                'page'            => 1,
     44                                'user_id'         => 0,
     45                                'include'         => false,
     46                                'search_terms'    => false,
     47                                'populate_extras' => true,
     48                                'exclude'         => false,
     49                                'meta_key'        => false,
     50                                'meta_value'      => false,
     51                                'populate_extras' => true,
     52                                'count_total'     => 'count_query'
     53                        ) );
     54                }
     55
     56                // Get user ids
     57                $this->prepare_user_ids_query();
     58                $this->do_user_ids_query();
     59
     60                // If no users were found, we can stop here
     61                if ( empty( $this->user_ids ) ) {
     62                        return;
     63                }
     64
     65                // Fetch additional data. First, using WP_User_Query
     66                $this->do_wp_user_query();
     67
     68                // Then, get BP-specific data
     69                if ( $this->query_vars['populate_extras'] ) {
     70                        $this->populate_extras();
     71                }
     72        }
     73
     74        /**
     75         * Prepare the query for user_ids
     76         *
     77         * @since BuddyPress (1.7)
     78         */
     79        function prepare_user_ids_query() {
     80                global $wpdb, $bp;
     81
     82                extract( $this->query_vars );
     83
     84                $sql = array(
     85                        'select'  => '',
     86                        'where'   => array(),
     87                        'orderby' => '',
     88                        'order'   => '',
     89                        'limit'   => ''
     90                );
     91
     92                /** 'type'  ********************************************/
     93
     94                // 'type' - Determines the sort order, which means it also
     95                // determines where the user IDs are drawn from (the SELECT
     96                // and WHERE statements)
     97                if ( 'active' == $type || 'online' == $type || 'newest' == $type || 'popular' == $type ) {
     98
     99                        $this->uid_name = 'user_id';
     100                        $sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$wpdb->usermeta} u";
     101                        $sql['where'][] = "u.meta_key = 'last_activity'";
     102                        if ( 'newest' == $type ) {
     103                                $sql['orderby'] = "ORDER BY u.user_id";
     104                        } else {
     105                                $sql['orderby'] = "ORDER BY u.meta_value";
     106                        }
     107
     108                        $sql['order']   = "DESC";
     109
     110                } else if ( 1==0 && 'alphabetical' == $type && ( ! bp_disable_profile_sync() || ! bp_is_active( 'xprofile' ) ) ) {
     111                        // We prefer to do alphabetical sorts against the
     112                        // display_name field of wp_users, because the table
     113                        // is smaller and better indexed. We can do so if
     114                        // WP-BP profile sync is enabled, or if BP xprofile is
     115                        // disabled altogether
     116
     117                        // @todo BP_Core_User::get_users() does *not* limit
     118                        // this query to those users with last_activity set.
     119                        // I think this is a bug, but I've reproduced it here
     120                        $this->uid_name = 'ID';
     121                        $sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$wpdb->users} u";
     122                        //$sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$wpdb->users} u JOIN {$wpdb->usermeta} um ON (u.{$this->uid_name} = um.user_id)";
     123                        //$sql['where'][] = $wpdb->prepare( "um.meta_key = %s", bp_get_user_meta_key( 'last_activity' ) );
     124                        $sql['orderby'] = "ORDER BY u.display_name";
     125                        $sql['order']   = "ASC";
     126
     127                } else if ( 'alphabetical' == $type ) {
     128                        // When profile sync is disabled, alphabetical sorts
     129                        // must happen against the xprofile table
     130
     131                        // @todo BP_Core_User::get_users() does *not* limit
     132                        // this query to those users with last_activity set.
     133                        // I think this is a bug, but I've reproduced it here
     134                        $this->uid_name = 'user_id';
     135                        $sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$bp->profile->table_name_data} u";
     136                        //$sql['select']  = "SELECT DISTINCT u.{$this->uid_name} as id FROM {$bp->profile->table_name_data} u JOIN {$wpdb->usermeta} um ON (u.{$this->uid_name} = um.user_id)";
     137                        //$sql['where'][] = $wpdb->prepare( "um.meta_key = %s", bp_get_user_meta_key( 'last_activity' ) );
     138                        $sql['where'][] = "u.field_id = 1"; // @todo Is this safe to assume?
     139                        $sql['orderby'] = "ORDER BY u.value";
     140                        $sql['order']   = "ASC";
     141                }
     142
     143                /** WHERE clauses ********************************************/
     144
     145                // 'include' - User ids to include in the results
     146                if ( false !== $include ) {
     147                        $include        = wp_parse_id_list( $include );
     148                        $include_ids    = $wpdb->escape( implode( ',', (array) $include ) );
     149                        $sql['where'][] = "u.{$this->uid_name} IN ({$include_ids})";
     150                }
     151
     152                // 'exclude' - User ids to exclude from the results
     153                if ( false !== $exclude ) {
     154                        $exclude        = wp_parse_id_list( $exclude );
     155                        $exclude_ids    = $wpdb->escape( implode( ',', (array) $exclude ) );
     156                        $sql['where'][] = "u.{$this->uid_name} NOT IN ({$exclude_ids})";
     157                }
     158
     159                // 'user_id' - When a user id is passed, limit to the friends of the user
     160                if ( !empty( $user_id ) && bp_is_active( 'friends' ) ) {
     161                        $friend_ids = friends_get_friend_user_ids( $user_id );
     162                        $friend_ids = $wpdb->escape( implode( ',', (array) $friend_ids ) );
     163
     164                        if ( !empty( $friend_ids ) ) {
     165                                $sql['where'][] = "u.{$this->uid_name} NOT IN ({$friend_ids})";
     166                        } else {
     167                                // If the user has no friends, make sure the query returns null
     168                                $sql['where'][] = "0 = 1";
     169                        }
     170                }
     171
     172                // 'search_terms' - To avoid global joins, do a separate query
     173                if ( false !== $search_terms && bp_is_active( 'xprofile' ) ) {
     174                        $found_user_ids = $wpdb->get_row( $wpdb->prepare( "SELECT user_id FROM {$bp->profile->table_name_data} WHERE value LIKE %s", '%%' . like_escape( $search_terms ) . '%%' ), ARRAY_N );
     175
     176                        if ( ! empty( $found_user_ids ) ) {
     177                                $sql['where'][] = "u.{$this->uid_name} IN (" . implode( ',', wp_parse_id_list( $found_user_ids ) ) . ")";
     178                        }
     179                }
     180
     181                // 'meta_key', 'meta_value' - join against usermeta
     182                // @todo Use WP_User_Query to get IDs for an IN clause?
     183                if ( false !== $meta_key ) {
     184                        $sql['select'] .= " LEFT JOIN {$wpdb->usermeta} um ON (um.user_id = u.{$this->uid_name})";
     185
     186                        $sql['where'][] = $wpdb->prepare( "um.meta_key = %s", $meta_key );
     187
     188                        // If a meta value is provided, match it
     189                        if ( false !== $meta_value ) {
     190                                $sql['where'][] = $wpdb->prepare( "um.meta_value = %s", $meta_value );
     191                        }
     192                }
     193
     194                // 'per_page', 'page' - handles LIMIT
     195                if ( !empty( $per_page ) && !empty( $page ) ) {
     196                        $sql['limit'] = $wpdb->prepare( "LIMIT %d, %d", intval( ( $page - 1 ) * $per_page ), intval( $per_page ) );
     197                } else {
     198                        $sql['limit'] = '';
     199                }
     200
     201                // Assemble the query chunks
     202                $this->uid_clauses['select']  = $sql['select'];
     203                $this->uid_clauses['where']   = ! empty( $sql['where'] ) ? 'WHERE ' . implode( ' AND ', $sql['where'] ) : '';
     204                $this->uid_clauses['orderby'] = $sql['orderby'];
     205                $this->uid_clauses['order']   = $sql['order'];
     206                $this->uid_clauses['limit']   = $sql['limit'];
     207
     208                do_action_ref_array( 'bp_pre_user_query', array( &$this ) );
     209        }
     210
     211        /**
     212         * Execute the user id query
     213         */
     214        protected function do_user_ids_query() {
     215                global $wpdb;
     216
     217                // If counting using SQL_CALC_FOUND_ROWS, set it up here
     218                if ( 'sql_calc_found_rows' == $this->query_vars['count_total'] ) {
     219                        $this->uid_clauses['select'] = str_replace( 'SELECT', 'SELECT SQL_CALC_FOUND_ROWS', $this->uid_clauses['select'] );
     220                }
     221
     222                // Get the specific user ids
     223                $this->user_ids = $wpdb->get_col( $wpdb->prepare( "{$this->uid_clauses['select']} {$this->uid_clauses['where']} {$this->uid_clauses['orderby']} {$this->uid_clauses['order']} {$this->uid_clauses['limit']}" ) );
     224
     225                // Get the total user count
     226                if ( 'sql_calc_found_rows' == $this->query_vars['count_total'] ) {
     227                        $this->total_users = $wpdb->get_var( apply_filters( 'bp_found_user_query', "SELECT FOUND_ROWS()", $this ) );
     228                } else if ( 'count_query' == $this->query_vars['count_total'] ) {
     229                        $count_select = preg_replace( '/^SELECT.*?FROM (\S+) u/', "SELECT COUNT(DISTINCT u.{$this->uid_name}) FROM $1 u", $this->uid_clauses['select'] );
     230                        $this->total_users = $wpdb->get_var( apply_filters( 'bp_found_user_query', "{$count_select} {$this->uid_clauses['where']}", $this ) );
     231                }
     232        }
     233
     234        protected function do_wp_user_query() {
     235                $wp_user_query = new WP_User_Query( apply_filters( 'bp_wp_user_query_args', array(
     236                        'blog_id'     => 0, // BP does not require blog roles
     237                        'fields'      => array( 'ID', 'user_registered', 'user_login', 'user_nicename', 'display_name', 'user_email' ),
     238                        'count_total' => false, // We already have a count
     239                        'include'     => $this->user_ids
     240                ), $this ) );
     241
     242                // Reindex for easier matching
     243                $r = array();
     244                foreach ( $wp_user_query->results as $u ) {
     245                        $r[ $u->ID ] = $u;
     246                }
     247
     248                // Match up to the user ids from the main query
     249                foreach ( $this->user_ids as $uid ) {
     250                        if ( isset( $r[ $uid ] ) ) {
     251                                $this->results[ $uid ] = $r[ $uid ];
     252
     253                                // The BP template functions expect an 'id'
     254                                // (as opposed to 'ID') property
     255                                $this->results[ $uid ]->id = $uid;
     256                        }
     257                }
     258        }
     259
     260        protected function populate_extras() {
     261                global $bp, $wpdb;
     262
     263                if ( empty( $this->results ) ) {
     264                        return;
     265                }
     266
     267                $user_ids_sql = implode( ',', wp_parse_id_list( $this->user_ids ) );
     268
     269                // Fetch the users' full names
     270                if ( bp_is_active( 'xprofile' ) && 'alphabetical' != $this->query_vars['type'] ) {
     271                        // @todo - Why not just assume field id 1?
     272                        $fullname_field_id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$bp->profile->table_name_fields} WHERE name = %s", bp_xprofile_fullname_field_name() ) );
     273
     274                        $names = $wpdb->get_results( $wpdb->prepare( "SELECT user_id, value as fullname FROM {$bp->profile->table_name_data} WHERE user_id IN ({$user_ids_sql})" ) );
     275
     276                        foreach ( $names as $name ) {
     277                                if ( isset( $this->results[ $name->user_id ] ) ) {
     278                                        $this->results[ $name->user_id ]->fullname = $name->fullname;
     279                                }
     280                        }
     281                }
     282
     283                // Fetch whether or not the user is a friend
     284                if ( bp_is_active( 'friends' ) ) {
     285                        $friend_status = $wpdb->get_results( $wpdb->prepare( "SELECT initiator_user_id, friend_user_id, is_confirmed FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d AND friend_user_id IN ( {$user_ids_sql} ) ) OR (initiator_user_id IN ( {$user_ids_sql} ) AND friend_user_id = %d )", bp_loggedin_user_id(), bp_loggedin_user_id() ) );
     286
     287                        foreach ( $friend_status as $fs ) {
     288                                // The "friend" is the user id in the pair who
     289                                // is *not* the logged in user
     290                                $friend_id = bp_loggedin_user_id() == $fs->initiator_user_id ? $fs->friend_user_id : $fs->initiator_user_id;
     291
     292                                if ( isset( $this->results[ $friend_id ] ) ) {
     293                                        $this->results[ $friend_id ]->is_friend = $fs->is_confirmed;
     294                                }
     295                        }
     296                }
     297
     298                // Fetch usermeta data
     299                // We want the three following pieces of info from usermeta:
     300                // - friend count
     301                // - last activity
     302                // - latest update
     303                $total_friend_count_key = bp_get_user_meta_key( 'total_friend_count' );
     304                $last_activity_key      = bp_get_user_meta_key( 'last_activity' );
     305                $bp_latest_update_key   = bp_get_user_meta_key( 'bp_latest_update' );
     306
     307                $umetas = $wpdb->get_results( $wpdb->prepare( "SELECT user_id, meta_key, meta_value FROM {$wpdb->usermeta} WHERE meta_key IN (%s,%s,%s) AND user_id IN ({$user_ids_sql})", $total_friend_count_key, $last_activity_key, $bp_latest_update_key ) );
     308
     309                foreach ( $umetas as $umeta ) {
     310                        // The members_template global expects the index key to
     311                        // be different from the meta_key in some cases
     312                        switch ( $umeta->meta_key ) {
     313                                case $total_friend_count_key :
     314                                        $key = 'total_friend_count';
     315                                        break;
     316
     317                                case $last_activity_key :
     318                                        $key = 'last_activity';
     319                                        break;
     320
     321                                case $bp_latest_update_key :
     322                                        $key = 'latest_update';
     323                                        break;
     324                        }
     325
     326                        if ( isset( $this->results[ $umeta->user_id ] ) ) {
     327                                $this->results[ $umeta->user_id ]->{$key} = $umeta->meta_value;
     328                        }
     329                }
     330        }
     331}
     332
    5333/**
    6334 * BP_Core_User class can be used by any component. It will fetch useful
    7335 * details for any user when provided with a user_id.
    class BP_Core_User { 
    201529        function get_users( $type, $limit = 0, $page = 1, $user_id = 0, $include = false, $search_terms = false, $populate_extras = true, $exclude = false, $meta_key = false, $meta_value = false ) {
    202530                global $wpdb, $bp;
    203531
     532                _deprecated_function( __METHOD__, '1.7', 'BP_User_Query' );
     533
    204534                $sql = array();
    205535
    206536                $sql['select_main'] = "SELECT DISTINCT u.ID as id, u.user_registered, u.user_nicename, u.user_login, u.display_name, u.user_email";
  • bp-members/bp-members-functions.php

    diff --git bp-members/bp-members-functions.php bp-members/bp-members-functions.php
    index 2a9e12a..a05eae2 100644
    add_action( 'bp_setup_globals', 'bp_core_define_slugs', 11 ); 
    7171/**
    7272 * Return an array of users IDs based on the parameters passed.
    7373 *
     74 * Since BuddyPress 1.7, bp_core_get_users() has used BP_User_Query. If you
     75 * need backward compatibility with BP_Core_User::get_users(), filter the
     76 * bp_use_legacy_user_query value, returning true.
     77 *
    7478 * @package BuddyPress Core
    7579 */
    7680function bp_core_get_users( $args = '' ) {
    function bp_core_get_users( $args = '' ) { 
    8791                'per_page'        => 20,       // The number of results to return per page
    8892                'page'            => 1,        // The page to return if limiting per page
    8993                'populate_extras' => true,     // Fetch the last active, where the user is a friend, total friend count, latest update
     94                'count_total'     => 'count_query' // What kind of total user count to do, if any. 'count_query', 'sql_calc_found_rows', or false
    9095        );
    9196
    9297        $params = wp_parse_args( $args, $defaults );
    9398        extract( $params, EXTR_SKIP );
    9499
    95         return apply_filters( 'bp_core_get_users', BP_Core_User::get_users( $type, $per_page, $page, $user_id, $include, $search_terms, $populate_extras, $exclude, $meta_key, $meta_value ), $params );
     100        // For legacy users. Note that use of BP_Core_User::get_users() is
     101        // deprecated and not recommended
     102        if ( false !== apply_filters( 'bp_use_legacy_user_query', false, __FUNCTION__, $params ) ) {
     103                return apply_filters( 'bp_core_get_users', BP_Core_User::get_users( $type, $per_page, $page, $user_id, $include, $search_terms, $populate_extras, $exclude, $meta_key, $meta_value ), $params );
     104        }
     105
     106        $users = new BP_User_Query( array(
     107                'type'            => $type,
     108                'user_id'         => $user_id,
     109                'exclude'         => $exclude,
     110                'search_terms'    => $search_terms,
     111                'meta_key'        => $meta_key,
     112                'meta_value'      => $meta_value,
     113                'include'         => $include,
     114                'per_page'        => $per_page,
     115                'page'            => $page,
     116                'populate_extras' => $populate_extras,
     117                'count_total'     => $count_total
     118        ) );
     119
     120        // Reformat the BP_User_Query data
     121        $retval = array(
     122                'users' => array_values( $users->results ),
     123                'total' => $users->total_users
     124        );
     125
     126        return $retval;
     127
    96128}
    97129
    98130/**