Skip to:
Content

BuddyPress.org

Ticket #7597: bp-members-functions.php

File bp-members-functions.php, 84.2 KB (added by antonioeatgoat, 7 years ago)
Line 
1<?php
2/**
3 * BuddyPress Member Functions.
4 *
5 * Functions specific to the members component.
6 *
7 * @package BuddyPress
8 * @subpackage MembersFunctions
9 * @since 1.5.0
10 */
11
12// Exit if accessed directly.
13defined( 'ABSPATH' ) || exit;
14
15/**
16 * Check for the existence of a Members directory page.
17 *
18 * @since 1.5.0
19 *
20 * @return bool True if found, otherwise false.
21 */
22function bp_members_has_directory() {
23        $bp = buddypress();
24
25        return (bool) !empty( $bp->pages->members->id );
26}
27
28/**
29 * Define the slug constants for the Members component.
30 *
31 * Handles the three slug constants used in the Members component -
32 * BP_MEMBERS_SLUG, BP_REGISTER_SLUG, and BP_ACTIVATION_SLUG. If these
33 * constants are not overridden in wp-config.php or bp-custom.php, they are
34 * defined here to match the slug of the corresponding WP pages.
35 *
36 * In general, fallback values are only used during initial BP page creation,
37 * when no slugs have been explicitly defined.
38 *
39 * @since 1.5.0
40 */
41function bp_core_define_slugs() {
42        $bp = buddypress();
43
44        // No custom members slug.
45        if ( !defined( 'BP_MEMBERS_SLUG' ) ) {
46                if ( !empty( $bp->pages->members ) ) {
47                        define( 'BP_MEMBERS_SLUG', $bp->pages->members->slug );
48                } else {
49                        define( 'BP_MEMBERS_SLUG', 'members' );
50                }
51        }
52
53        // No custom registration slug.
54        if ( !defined( 'BP_REGISTER_SLUG' ) ) {
55                if ( !empty( $bp->pages->register ) ) {
56                        define( 'BP_REGISTER_SLUG', $bp->pages->register->slug );
57                } else {
58                        define( 'BP_REGISTER_SLUG', 'register' );
59                }
60        }
61
62        // No custom activation slug.
63        if ( !defined( 'BP_ACTIVATION_SLUG' ) ) {
64                if ( !empty( $bp->pages->activate ) ) {
65                        define( 'BP_ACTIVATION_SLUG', $bp->pages->activate->slug );
66                } else {
67                        define( 'BP_ACTIVATION_SLUG', 'activate' );
68                }
69        }
70}
71add_action( 'bp_setup_globals', 'bp_core_define_slugs', 11 );
72
73/**
74 * Fetch an array of users based on the parameters passed.
75 *
76 * Since BuddyPress 1.7, bp_core_get_users() uses BP_User_Query. If you
77 * need backward compatibility with BP_Core_User::get_users(), filter the
78 * bp_use_legacy_user_query value, returning true.
79 *
80 * @since 1.2.0
81 *
82 * @param array|string $args {
83 *     Array of arguments. All are optional. See {@link BP_User_Query} for
84 *     a more complete description of arguments.
85 *     @type string       $type                Sort order. Default: 'active'.
86 *     @type int          $user_id             Limit results to friends of a user. Default: false.
87 *     @type mixed        $exclude             IDs to exclude from results. Default: false.
88 *     @type string       $search_terms        Limit to users matching search terms. Default: false.
89 *     @type string       $meta_key            Limit to users with a meta_key. Default: false.
90 *     @type string       $meta_value          Limit to users with a meta_value (with meta_key). Default: false.
91 *     @type array|string $member_type         Array or comma-separated string of member types.
92 *     @type array|string $member_type__in     Array or comma-separated string of member types.
93 *                                             `$member_type` takes precedence over this parameter.
94 *     @type array|string $member_type__not_in Array or comma-separated string of member types to be excluded.
95 *     @type mixed        $include             Limit results by user IDs. Default: false.
96 *     @type int          $per_page            Results per page. Default: 20.
97 *     @type int          $page                Page of results. Default: 1.
98 *     @type bool         $populate_extras     Fetch optional extras. Default: true.
99 *     @type string|bool  $count_total         How to do total user count. Default: 'count_query'.
100 * }
101 * @return array
102 */
103function bp_core_get_users( $args = '' ) {
104
105        // Parse the user query arguments.
106        $r = bp_parse_args( $args, array(
107                'type'                => 'active',     // Active, newest, alphabetical, random or popular.
108                'user_id'             => false,        // Pass a user_id to limit to only friend connections for this user.
109                'exclude'             => false,        // Users to exclude from results.
110                'search_terms'        => false,        // Limit to users that match these search terms.
111                'meta_key'            => false,        // Limit to users who have this piece of usermeta.
112                'meta_value'          => false,        // With meta_key, limit to users where usermeta matches this value.
113                'member_type'         => '',
114                'member_type__in'     => '',
115                'member_type__not_in' => '',
116                'include'             => false,        // Pass comma separated list of user_ids to limit to only these users.
117                'per_page'            => 20,           // The number of results to return per page.
118                'page'                => 1,            // The page to return if limiting per page.
119                'populate_extras'     => true,         // Fetch the last active, where the user is a friend, total friend count, latest update.
120                'count_total'         => 'count_query' // What kind of total user count to do, if any. 'count_query', 'sql_calc_found_rows', or false.
121        ), 'core_get_users' );
122
123        // For legacy users. Use of BP_Core_User::get_users() is deprecated.
124        if ( apply_filters( 'bp_use_legacy_user_query', false, __FUNCTION__, $r ) ) {
125                $retval = BP_Core_User::get_users(
126                        $r['type'],
127                        $r['per_page'],
128                        $r['page'],
129                        $r['user_id'],
130                        $r['include'],
131                        $r['search_terms'],
132                        $r['populate_extras'],
133                        $r['exclude'],
134                        $r['meta_key'],
135                        $r['meta_value']
136                );
137
138        // Default behavior as of BuddyPress 1.7.0.
139        } else {
140
141                // Get users like we were asked to do...
142                $users = new BP_User_Query( $r );
143
144                // ...but reformat the results to match bp_core_get_users() behavior.
145                $retval = array(
146                        'users' => array_values( $users->results ),
147                        'total' => $users->total_users
148                );
149        }
150
151        /**
152         * Filters the results of the user query.
153         *
154         * @since 1.2.0
155         *
156         * @param array $retval Array of users for the current query.
157         * @param array $r      Array of parsed query arguments.
158         */
159        return apply_filters( 'bp_core_get_users', $retval, $r );
160}
161
162/**
163 * Return the domain for the passed user: e.g. http://example.com/members/andy/.
164 *
165 * @since 1.0.0
166 *
167 * @param int         $user_id       The ID of the user.
168 * @param string|bool $user_nicename Optional. user_nicename of the user.
169 * @param string|bool $user_login    Optional. user_login of the user.
170 * @return string
171 */
172function bp_core_get_user_domain( $user_id = 0, $user_nicename = false, $user_login = false ) {
173
174        if ( empty( $user_id ) ) {
175                return;
176        }
177
178        $username = bp_core_get_username( $user_id, $user_nicename, $user_login );
179
180        if ( bp_is_username_compatibility_mode() ) {
181                $username = rawurlencode( $username );
182        }
183
184        $after_domain = bp_core_enable_root_profiles() ? $username : bp_get_members_root_slug() . '/' . $username;
185        $domain       = trailingslashit( bp_get_root_domain() . '/' . $after_domain );
186
187        // Don't use this filter.  Subject to removal in a future release.
188        // Use the 'bp_core_get_user_domain' filter instead.
189        $domain       = apply_filters( 'bp_core_get_user_domain_pre_cache', $domain, $user_id, $user_nicename, $user_login );
190
191        /**
192         * Filters the domain for the passed user.
193         *
194         * @since 1.0.1
195         *
196         * @param string $domain        Domain for the passed user.
197         * @param int    $user_id       ID of the passed user.
198         * @param string $user_nicename User nicename of the passed user.
199         * @param string $user_login    User login of the passed user.
200         */
201        return apply_filters( 'bp_core_get_user_domain', $domain, $user_id, $user_nicename, $user_login );
202}
203
204/**
205 * Fetch everything in the wp_users table for a user, without any usermeta.
206 *
207 * @since 1.2.0
208 *
209 * @param  int $user_id The ID of the user.
210 * @return array|bool Array of data on success, boolean false on failure.
211 */
212function bp_core_get_core_userdata( $user_id = 0 ) {
213        if ( empty( $user_id ) ) {
214                return false;
215        }
216
217        $userdata = wp_cache_get( 'bp_core_userdata_' . $user_id, 'bp' );
218
219        // No cache.
220        if ( false === $userdata ) {
221                $userdata = BP_Core_User::get_core_userdata( $user_id );
222
223                // Cache data; no-result is cached as integer 0.
224                wp_cache_set( 'bp_core_userdata_' . $user_id, false === $userdata ? 0 : $userdata, 'bp' );
225
226        // Cached no-result, so set return value as false as expected.
227        } elseif ( 0 === $userdata ) {
228                $userdata = false;
229        }
230
231        /**
232         * Filters the userdata for a passed user.
233         *
234         * @since 1.2.0
235         *
236         * @param array|bool $userdata Array of user data for a passed user on success, boolean false on failure.
237         */
238        return apply_filters( 'bp_core_get_core_userdata', $userdata );
239}
240
241/**
242 * Return the ID of a user, based on user_login.
243 *
244 * No longer used.
245 *
246 * @todo Deprecate.
247 *
248 * @param string $user_login user_login of the user being queried.
249 * @return int
250 */
251function bp_core_get_displayed_userid( $user_login ) {
252        return apply_filters( 'bp_core_get_displayed_userid', bp_core_get_userid( $user_login ) );
253}
254
255/**
256 * Return the user ID based on a user's user_login.
257 *
258 * @since 1.0.0
259 *
260 * @param string $username user_login to check.
261 * @return int|null The ID of the matched user on success, null on failure.
262 */
263function bp_core_get_userid( $username = '' ) {
264        if ( empty( $username ) ) {
265                return false;
266        }
267
268        $user = get_user_by( 'login', $username );
269
270        /**
271         * Filters the ID of a user, based on user_login.
272         *
273         * @since 1.0.1
274         *
275         * @param int|null $value    ID of the user or null.
276         * @param string   $username User login to check.
277         */
278        return apply_filters( 'bp_core_get_userid', ! empty( $user->ID ) ? $user->ID : NULL, $username );
279}
280
281/**
282 * Return the user ID based on a user's user_nicename.
283 *
284 * @since 1.2.3
285 *
286 * @param string $user_nicename user_nicename to check.
287 * @return int|null The ID of the matched user on success, null on failure.
288 */
289function bp_core_get_userid_from_nicename( $user_nicename = '' ) {
290        if ( empty( $user_nicename ) ) {
291                return false;
292        }
293
294        $user = get_user_by( 'slug', $user_nicename );
295
296        /**
297         * Filters the user ID based on user_nicename.
298         *
299         * @since 1.2.3
300         *
301         * @param int|null $value         ID of the user or null.
302         * @param string   $user_nicename User nicename to check.
303         */
304        return apply_filters( 'bp_core_get_userid_from_nicename', ! empty( $user->ID ) ? $user->ID : NULL, $user_nicename );
305}
306
307/**
308 * Return the username for a user based on their user id.
309 *
310 * This function is sensitive to the BP_ENABLE_USERNAME_COMPATIBILITY_MODE,
311 * so it will return the user_login or user_nicename as appropriate.
312 *
313 * @since 1.0.0
314 *
315 * @param int         $user_id       User ID to check.
316 * @param string|bool $user_nicename Optional. user_nicename of user being checked.
317 * @param string|bool $user_login    Optional. user_login of user being checked.
318 * @return string|bool The username of the matched user, or false.
319 */
320function bp_core_get_username( $user_id = 0, $user_nicename = false, $user_login = false ) {
321        $bp = buddypress();
322
323        // Check cache for user nicename.
324        $username = wp_cache_get( 'bp_user_username_' . $user_id, 'bp' );
325        if ( false === $username ) {
326
327                // Cache not found so prepare to update it.
328                $update_cache = true;
329
330                // Nicename and login were not passed.
331                if ( empty( $user_nicename ) && empty( $user_login ) ) {
332
333                        // User ID matches logged in user.
334                        if ( bp_loggedin_user_id() == $user_id ) {
335                                $userdata = &$bp->loggedin_user->userdata;
336
337                        // User ID matches displayed in user.
338                        } elseif ( bp_displayed_user_id() == $user_id ) {
339                                $userdata = &$bp->displayed_user->userdata;
340
341                        // No user ID match.
342                        } else {
343                                $userdata = false;
344                        }
345
346                        // No match so go dig.
347                        if ( empty( $userdata ) ) {
348
349                                // User not found so return false.
350                                if ( !$userdata = bp_core_get_core_userdata( $user_id ) ) {
351                                        return false;
352                                }
353                        }
354
355                        // Update the $user_id for later.
356                        $user_id       = $userdata->ID;
357
358                        // Two possible options.
359                        $user_nicename = $userdata->user_nicename;
360                        $user_login    = $userdata->user_login;
361                }
362
363                // Pull an audible and maybe use the login over the nicename.
364                $username = bp_is_username_compatibility_mode() ? $user_login : $user_nicename;
365
366        // Username found in cache so don't update it again.
367        } else {
368                $update_cache = false;
369        }
370
371        // Add this to cache.
372        if ( ( true === $update_cache ) && !empty( $username ) ) {
373                wp_cache_set( 'bp_user_username_' . $user_id, $username, 'bp' );
374
375        // @todo bust this cache if no $username found?
376        // } else {
377        // wp_cache_delete( 'bp_user_username_' . $user_id );
378        }
379
380        /**
381         * Filters the username based on originally provided user ID.
382         *
383         * @since 1.0.1
384         *
385         * @param string $username Username determined by user ID.
386         */
387        return apply_filters( 'bp_core_get_username', $username );
388}
389
390/**
391 * Return the user_nicename for a user based on their user_id.
392 *
393 * This should be used for linking to user profiles and anywhere else a
394 * sanitized and unique slug to a user is needed.
395 *
396 * @since 1.5.0
397 *
398 * @todo Refactor to use a WP core function, if possible.
399 *
400 * @param int $user_id User ID to check.
401 * @return string|bool The username of the matched user, or false.
402 */
403function bp_members_get_user_nicename( $user_id ) {
404        $bp = buddypress();
405
406        if ( !$user_nicename = wp_cache_get( 'bp_members_user_nicename_' . $user_id, 'bp' ) ) {
407                $update_cache = true;
408
409                // User ID matches logged in user.
410                if ( bp_loggedin_user_id() == $user_id ) {
411                        $userdata = &$bp->loggedin_user->userdata;
412
413                // User ID matches displayed in user.
414                } elseif ( bp_displayed_user_id() == $user_id ) {
415                        $userdata = &$bp->displayed_user->userdata;
416
417                // No user ID match.
418                } else {
419                        $userdata = false;
420                }
421
422                // No match so go dig.
423                if ( empty( $userdata ) ) {
424
425                        // User not found so return false.
426                        if ( !$userdata = bp_core_get_core_userdata( $user_id ) ) {
427                                return false;
428                        }
429                }
430
431                // User nicename found.
432                $user_nicename = $userdata->user_nicename;
433
434        // Nicename found in cache so don't update it again.
435        } else {
436                $update_cache = false;
437        }
438
439        // Add this to cache.
440        if ( true == $update_cache && !empty( $user_nicename ) ) {
441                wp_cache_set( 'bp_members_user_nicename_' . $user_id, $user_nicename, 'bp' );
442        }
443
444        /**
445         * Filters the user_nicename based on originally provided user ID.
446         *
447         * @since 1.5.0
448         *
449         * @param string $username User nice name determined by user ID.
450         */
451        return apply_filters( 'bp_members_get_user_nicename', $user_nicename );
452}
453
454/**
455 * Return the email address for the user based on user ID.
456 *
457 * @since 1.0.0
458 *
459 * @param int $uid User ID to check.
460 * @return string The email for the matched user. Empty string if no user
461 *                matched the $uid.
462 */
463function bp_core_get_user_email( $uid ) {
464
465        if ( !$email = wp_cache_get( 'bp_user_email_' . $uid, 'bp' ) ) {
466
467                // User exists.
468                $ud = bp_core_get_core_userdata( $uid );
469                if ( ! empty( $ud ) ) {
470                        $email = $ud->user_email;
471
472                // User was deleted.
473                } else {
474                        $email = '';
475                }
476
477                wp_cache_set( 'bp_user_email_' . $uid, $email, 'bp' );
478        }
479
480        /**
481         * Filters the user email for user based on user ID.
482         *
483         * @since 1.0.1
484         *
485         * @param string $email Email determined for the user.
486         */
487        return apply_filters( 'bp_core_get_user_email', $email );
488}
489
490/**
491 * Return a HTML formatted link for a user with the user's full name as the link text.
492 *
493 * Eg: <a href="http://andy.example.com/">Andy Peatling</a>
494 *
495 * Optional parameters will return just the name or just the URL.
496 *
497 * @since 1.0.0
498 *
499 * @param int  $user_id   User ID to check.
500 * @param bool $no_anchor Disable URL and HTML and just return full name.
501 *                        Default: false.
502 * @param bool $just_link Disable full name and HTML and just return the URL
503 *                        text. Default false.
504 * @return string|bool The link text based on passed parameters, or false on
505 *                     no match.
506 */
507function bp_core_get_userlink( $user_id, $no_anchor = false, $just_link = false ) {
508        $display_name = bp_core_get_user_displayname( $user_id );
509
510        if ( empty( $display_name ) ) {
511                return false;
512        }
513
514        if ( ! empty( $no_anchor ) ) {
515                return $display_name;
516        }
517
518        if ( !$url = bp_core_get_user_domain( $user_id ) ) {
519                return false;
520        }
521
522        if ( ! empty( $just_link ) ) {
523                return $url;
524        }
525
526        /**
527         * Filters the link text for the passed in user.
528         *
529         * @since 1.2.0
530         *
531         * @param string $value   Link text based on passed parameters.
532         * @param int    $user_id ID of the user to check.
533         */
534        return apply_filters( 'bp_core_get_userlink', '<a href="' . $url . '">' . $display_name . '</a>', $user_id );
535}
536
537/**
538 * Fetch the display name for a group of users.
539 *
540 * Uses the 'Name' field in xprofile if available. Falls back on WP
541 * display_name, and then user_nicename.
542 *
543 * @since 2.0.0
544 *
545 * @param array $user_ids Array of user IDs to get display names for.
546 * @return array
547 */
548function bp_core_get_user_displaynames( $user_ids ) {
549
550        // Sanitize.
551        $user_ids = wp_parse_id_list( $user_ids );
552
553        // Remove dupes and empties.
554        $user_ids = array_unique( array_filter( $user_ids ) );
555
556        if ( empty( $user_ids ) ) {
557                return array();
558        }
559
560        $uncached_ids = array();
561        foreach ( $user_ids as $user_id ) {
562                if ( false === wp_cache_get( 'bp_user_fullname_' . $user_id, 'bp' ) ) {
563                        $uncached_ids[] = $user_id;
564                }
565        }
566
567        // Prime caches.
568        if ( ! empty( $uncached_ids ) ) {
569                if ( bp_is_active( 'xprofile' ) ) {
570                        $fullname_data = BP_XProfile_ProfileData::get_value_byid( 1, $uncached_ids );
571
572                        // Key by user_id.
573                        $fullnames = array();
574                        foreach ( $fullname_data as $fd ) {
575                                if ( ! empty( $fd->value ) ) {
576                                        $fullnames[ intval( $fd->user_id ) ] = $fd->value;
577                                }
578                        }
579
580                        // If xprofiledata is not found for any users,  we'll look
581                        // them up separately.
582                        $no_xprofile_ids = array_diff( $uncached_ids, array_keys( $fullnames ) );
583                } else {
584                        $fullnames = array();
585                        $no_xprofile_ids = $user_ids;
586                }
587
588                if ( ! empty( $no_xprofile_ids ) ) {
589                        // Use WP_User_Query because we don't need BP information.
590                        $query = new WP_User_Query( array(
591                                'include'     => $no_xprofile_ids,
592                                'fields'      => array( 'ID', 'user_nicename', 'display_name', ),
593                                'count_total' => false,
594                                'blog_id'     => 0,
595                        ) );
596
597                        foreach ( $query->results as $qr ) {
598                                $fullnames[ $qr->ID ] = ! empty( $qr->display_name ) ? $qr->display_name : $qr->user_nicename;
599
600                                // If xprofile is active, set this value as the
601                                // xprofile display name as well.
602                                if ( bp_is_active( 'xprofile' ) ) {
603                                        xprofile_set_field_data( 1, $qr->ID, $fullnames[ $qr->ID ] );
604                                }
605                        }
606                }
607
608                foreach ( $fullnames as $fuser_id => $fname ) {
609                        wp_cache_set( 'bp_user_fullname_' . $fuser_id, $fname, 'bp' );
610                }
611        }
612
613        $retval = array();
614        foreach ( $user_ids as $user_id ) {
615                $retval[ $user_id ] = wp_cache_get( 'bp_user_fullname_' . $user_id, 'bp' );
616        }
617
618        return $retval;
619}
620
621/**
622 * Fetch the display name for a user.
623 *
624 * @since 1.0.1
625 *
626 * @param int|string|bool $user_id_or_username User ID or username.
627 * @return string|bool The display name for the user in question, or false if
628 *                     user not found.
629 */
630function bp_core_get_user_displayname( $user_id_or_username ) {
631        if ( empty( $user_id_or_username ) ) {
632                return false;
633        }
634
635        if ( ! is_numeric( $user_id_or_username ) ) {
636                $user_id = bp_core_get_userid( $user_id_or_username );
637        } else {
638                $user_id = $user_id_or_username;
639        }
640
641        if ( empty( $user_id ) ) {
642                return false;
643        }
644
645        $display_names = bp_core_get_user_displaynames( array( $user_id ) );
646
647        if ( ! isset( $display_names[ $user_id ] ) ) {
648                $fullname = false;
649        } else {
650                $fullname = $display_names[ $user_id ];
651        }
652
653        /**
654         * Filters the display name for the passed in user.
655         *
656         * @since 1.0.1
657         *
658         * @param string $fullname Display name for the user.
659         * @param int    $user_id  ID of the user to check.
660         */
661        return apply_filters( 'bp_core_get_user_displayname', $fullname, $user_id );
662}
663add_filter( 'bp_core_get_user_displayname', 'strip_tags', 1 );
664add_filter( 'bp_core_get_user_displayname', 'trim'          );
665add_filter( 'bp_core_get_user_displayname', 'stripslashes'  );
666add_filter( 'bp_core_get_user_displayname', 'esc_html'      );
667
668/**
669 * Return the user link for the user based on user email address.
670 *
671 * @since 1.0.0
672 *
673 * @param string $email The email address for the user.
674 * @return string The link to the users home base. False on no match.
675 */
676function bp_core_get_userlink_by_email( $email ) {
677        $user = get_user_by( 'email', $email );
678
679        /**
680         * Filters the user link for the user based on user email address.
681         *
682         * @since 1.0.1
683         *
684         * @param string|bool $value URL for the user if found, otherwise false.
685         */
686        return apply_filters( 'bp_core_get_userlink_by_email', bp_core_get_userlink( $user->ID, false, false, true ) );
687}
688
689/**
690 * Return the user link for the user based on the supplied identifier.
691 *
692 * @since 1.0.0
693 *
694 * @param string $username If BP_ENABLE_USERNAME_COMPATIBILITY_MODE is set,
695 *                         this should be user_login, otherwise it should
696 *                         be user_nicename.
697 * @return string|bool The link to the user's domain, false on no match.
698 */
699function bp_core_get_userlink_by_username( $username ) {
700        if ( bp_is_username_compatibility_mode() ) {
701                $user_id = bp_core_get_userid( $username );
702        } else {
703                $user_id = bp_core_get_userid_from_nicename( $username );
704        }
705
706        /**
707         * Filters the user link for the user based on username.
708         *
709         * @since 1.0.1
710         *
711         * @param string|bool $value URL for the user if found, otherwise false.
712         */
713        return apply_filters( 'bp_core_get_userlink_by_username', bp_core_get_userlink( $user_id, false, false, true ) );
714}
715
716/**
717 * Return the total number of members for the installation.
718 *
719 * Note that this is a raw count of non-spam, activated users. It does not
720 * account for users who have logged activity (last_active). See
721 * {@link bp_core_get_active_member_count()}.
722 *
723 * @since 1.2.0
724 *
725 * @return int The total number of members.
726 */
727function bp_core_get_total_member_count() {
728        global $wpdb;
729
730        $count = wp_cache_get( 'bp_total_member_count', 'bp' );
731
732        if ( false === $count ) {
733                $status_sql = bp_core_get_status_sql();
734                $count = $wpdb->get_var( "SELECT COUNT(ID) FROM {$wpdb->users} WHERE {$status_sql}" );
735                wp_cache_set( 'bp_total_member_count', $count, 'bp' );
736        }
737
738        /**
739         * Filters the total number of members for the installation.
740         *
741         * @since 1.2.0
742         *
743         * @param int $count Total number of members.
744         */
745        return apply_filters( 'bp_core_get_total_member_count', $count );
746}
747
748/**
749 * Return the total number of members, limited to those members with last_activity.
750 *
751 * @since 1.6.0
752 *
753 * @return int The number of active members.
754 */
755function bp_core_get_active_member_count() {
756        global $wpdb;
757
758        $count = get_transient( 'bp_active_member_count' );
759        if ( false === $count ) {
760                $bp = buddypress();
761
762                // Avoid a costly join by splitting the lookup.
763                if ( is_multisite() ) {
764                        $sql = "SELECT ID FROM {$wpdb->users} WHERE (user_status != 0 OR deleted != 0 OR user_status != 0)";
765                } else {
766                        $sql = "SELECT ID FROM {$wpdb->users} WHERE user_status != 0";
767                }
768
769                $exclude_users     = $wpdb->get_col( $sql );
770                $exclude_users_sql = !empty( $exclude_users ) ? "AND user_id NOT IN (" . implode( ',', wp_parse_id_list( $exclude_users ) ) . ")" : '';
771                $count             = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(user_id) FROM {$bp->members->table_name_last_activity} WHERE component = %s AND type = 'last_activity' {$exclude_users_sql}", $bp->members->id ) );
772
773                set_transient( 'bp_active_member_count', $count );
774        }
775
776        /**
777         * Filters the total number of members for the installation limited to those with last_activity.
778         *
779         * @since 1.6.0
780         *
781         * @param int $count Total number of active members.
782         */
783        return apply_filters( 'bp_core_get_active_member_count', $count );
784}
785
786/**
787 * Process a spammed or unspammed user.
788 *
789 * This function is called from three places:
790 *
791 * - in bp_settings_action_capabilities() (from the front-end)
792 * - by bp_core_mark_user_spam_admin()    (from wp-admin)
793 * - bp_core_mark_user_ham_admin()        (from wp-admin)
794 *
795 * @since 1.6.0
796 *
797 * @param int    $user_id       The ID of the user being spammed/hammed.
798 * @param string $status        'spam' if being marked as spam, 'ham' otherwise.
799 * @param bool   $do_wp_cleanup True to force the cleanup of WordPress content
800 *                              and status, otherwise false. Generally, this should
801 *                              only be false if WordPress is expected to have
802 *                              performed this cleanup independently, as when hooked
803 *                              to 'make_spam_user'.
804 * @return bool True on success, false on failure.
805 */
806function bp_core_process_spammer_status( $user_id, $status, $do_wp_cleanup = true ) {
807        global $wpdb;
808
809        // Bail if no user ID.
810        if ( empty( $user_id ) ) {
811                return;
812        }
813
814        // Bail if user ID is super admin.
815        if ( is_super_admin( $user_id ) ) {
816                return;
817        }
818
819        // Get the functions file.
820        if ( is_multisite() ) {
821                require_once( ABSPATH . 'wp-admin/includes/ms.php' );
822        }
823
824        $is_spam = ( 'spam' == $status );
825
826        // Only you can prevent infinite loops.
827        remove_action( 'make_spam_user', 'bp_core_mark_user_spam_admin' );
828        remove_action( 'make_ham_user',  'bp_core_mark_user_ham_admin'  );
829
830        // Force the cleanup of WordPress content and status for multisite configs.
831        if ( $do_wp_cleanup ) {
832
833                // Get the blogs for the user.
834                $blogs = get_blogs_of_user( $user_id, true );
835
836                foreach ( (array) array_values( $blogs ) as $details ) {
837
838                        // Do not mark the main or current root blog as spam.
839                        if ( 1 == $details->userblog_id || bp_get_root_blog_id() == $details->userblog_id ) {
840                                continue;
841                        }
842
843                        // Update the blog status.
844                        update_blog_status( $details->userblog_id, 'spam', $is_spam );
845                }
846
847                // Finally, mark this user as a spammer.
848                if ( is_multisite() ) {
849                        update_user_status( $user_id, 'spam', $is_spam );
850                }
851        }
852
853        // Update the user status.
854        $wpdb->update( $wpdb->users, array( 'user_status' => $is_spam ), array( 'ID' => $user_id ) );
855
856        // Clean user cache.
857        clean_user_cache( $user_id );
858
859        if ( ! is_multisite() ) {
860                // Call multisite actions in single site mode for good measure.
861                if ( true === $is_spam ) {
862
863                        /**
864                         * Fires at end of processing spammer in Dashboard if not multisite and user is spam.
865                         *
866                         * @since 1.5.0
867                         *
868                         * @param int $value user ID.
869                         */
870                        do_action( 'make_spam_user', $user_id );
871                } else {
872
873                        /**
874                         * Fires at end of processing spammer in Dashboard if not multisite and user is not spam.
875                         *
876                         * @since 1.5.0
877                         *
878                         * @param int $value user ID.
879                         */
880                        do_action( 'make_ham_user', $user_id );
881                }
882        }
883
884        // Hide this user's activity.
885        if ( ( true === $is_spam ) && bp_is_active( 'activity' ) ) {
886                bp_activity_hide_user_activity( $user_id );
887        }
888
889        // We need a special hook for is_spam so that components can delete data at spam time.
890        if ( true === $is_spam ) {
891
892                /**
893                 * Fires at the end of the process spammer process if the user is spam.
894                 *
895                 * @since 1.5.0
896                 *
897                 * @param int $value Displayed user ID.
898                 */
899                do_action( 'bp_make_spam_user', $user_id );
900        } else {
901
902                /**
903                 * Fires at the end of the process spammer process if the user is not spam.
904                 *
905                 * @since 1.5.0
906                 *
907                 * @param int $value Displayed user ID.
908                 */
909                do_action( 'bp_make_ham_user', $user_id );
910        }
911
912        /**
913         * Fires at the end of the process for hanlding spammer status.
914         *
915         * @since 1.5.5
916         *
917         * @param int  $user_id ID of the processed user.
918         * @param bool $is_spam The determined spam status of processed user.
919         */
920        do_action( 'bp_core_process_spammer_status', $user_id, $is_spam );
921
922        // Put things back how we found them.
923        add_action( 'make_spam_user', 'bp_core_mark_user_spam_admin' );
924        add_action( 'make_ham_user',  'bp_core_mark_user_ham_admin'  );
925
926        return true;
927}
928/**
929 * Hook to WP's make_spam_user and run our custom BP spam functions.
930 *
931 * @since 1.6.0
932 *
933 * @param int $user_id The user ID passed from the make_spam_user hook.
934 */
935function bp_core_mark_user_spam_admin( $user_id ) {
936        bp_core_process_spammer_status( $user_id, 'spam', false );
937}
938add_action( 'make_spam_user', 'bp_core_mark_user_spam_admin' );
939
940/**
941 * Hook to WP's make_ham_user and run our custom BP spam functions.
942 *
943 * @since 1.6.0
944 *
945 * @param int $user_id The user ID passed from the make_ham_user hook.
946 */
947function bp_core_mark_user_ham_admin( $user_id ) {
948        bp_core_process_spammer_status( $user_id, 'ham', false );
949}
950add_action( 'make_ham_user', 'bp_core_mark_user_ham_admin' );
951
952/**
953 * Check whether a user has been marked as a spammer.
954 *
955 * @since 1.6.0
956 *
957 * @param int $user_id The ID for the user.
958 * @return bool True if spammer, otherwise false.
959 */
960function bp_is_user_spammer( $user_id = 0 ) {
961
962        // No user to check.
963        if ( empty( $user_id ) ) {
964                return false;
965        }
966
967        $bp = buddypress();
968
969        // Assume user is not spam.
970        $is_spammer = false;
971
972        // Setup our user.
973        $user = false;
974
975        // Get locally-cached data if available.
976        switch ( $user_id ) {
977                case bp_loggedin_user_id() :
978                        $user = ! empty( $bp->loggedin_user->userdata ) ? $bp->loggedin_user->userdata : false;
979                        break;
980
981                case bp_displayed_user_id() :
982                        $user = ! empty( $bp->displayed_user->userdata ) ? $bp->displayed_user->userdata : false;
983                        break;
984        }
985
986        // Manually get userdata if still empty.
987        if ( empty( $user ) ) {
988                $user = get_userdata( $user_id );
989        }
990
991        // No user found.
992        if ( empty( $user ) ) {
993                $is_spammer = false;
994
995        // User found.
996        } else {
997
998                // Check if spam.
999                if ( !empty( $user->spam ) ) {
1000                        $is_spammer = true;
1001                }
1002
1003                if ( 1 == $user->user_status ) {
1004                        $is_spammer = true;
1005                }
1006        }
1007
1008        /**
1009         * Filters whether a user is marked as a spammer.
1010         *
1011         * @since 1.6.0
1012         *
1013         * @param bool $is_spammer Whether or not user is marked as spammer.
1014         */
1015        return apply_filters( 'bp_is_user_spammer', (bool) $is_spammer );
1016}
1017
1018/**
1019 * Check whether a user has been marked as deleted.
1020 *
1021 * @since 1.6.0
1022 *
1023 * @param int $user_id The ID for the user.
1024 * @return bool True if deleted, otherwise false.
1025 */
1026function bp_is_user_deleted( $user_id = 0 ) {
1027
1028        // No user to check.
1029        if ( empty( $user_id ) ) {
1030                return false;
1031        }
1032
1033        $bp = buddypress();
1034
1035        // Assume user is not deleted.
1036        $is_deleted = false;
1037
1038        // Setup our user.
1039        $user = false;
1040
1041        // Get locally-cached data if available.
1042        switch ( $user_id ) {
1043                case bp_loggedin_user_id() :
1044                        $user = ! empty( $bp->loggedin_user->userdata ) ? $bp->loggedin_user->userdata : false;
1045                        break;
1046
1047                case bp_displayed_user_id() :
1048                        $user = ! empty( $bp->displayed_user->userdata ) ? $bp->displayed_user->userdata : false;
1049                        break;
1050        }
1051
1052        // Manually get userdata if still empty.
1053        if ( empty( $user ) ) {
1054                $user = get_userdata( $user_id );
1055        }
1056
1057        // No user found.
1058        if ( empty( $user ) ) {
1059                $is_deleted = true;
1060
1061        // User found.
1062        } else {
1063
1064                // Check if deleted.
1065                if ( !empty( $user->deleted ) ) {
1066                        $is_deleted = true;
1067                }
1068
1069                if ( 2 == $user->user_status ) {
1070                        $is_deleted = true;
1071                }
1072        }
1073
1074        /**
1075         * Filters whether a user is marked as deleted.
1076         *
1077         * @since 1.6.0
1078         *
1079         * @param bool $is_deleted Whether or not user is marked as deleted.
1080         */
1081        return apply_filters( 'bp_is_user_deleted', (bool) $is_deleted );
1082}
1083
1084/**
1085 * Check whether a user is "active", ie neither deleted nor spammer.
1086 *
1087 * @since 1.6.0
1088 *
1089 * @param int $user_id The user ID to check.
1090 * @return bool True if active, otherwise false.
1091 */
1092function bp_is_user_active( $user_id = 0 ) {
1093
1094        // Default to current user.
1095        if ( empty( $user_id ) && is_user_logged_in() ) {
1096                $user_id = bp_loggedin_user_id();
1097        }
1098
1099        // No user to check.
1100        if ( empty( $user_id ) ) {
1101                return false;
1102        }
1103
1104        // Check spam.
1105        if ( bp_is_user_spammer( $user_id ) ) {
1106                return false;
1107        }
1108
1109        // Check deleted.
1110        if ( bp_is_user_deleted( $user_id ) ) {
1111                return false;
1112        }
1113
1114        // Assume true if not spam or deleted.
1115        return true;
1116}
1117
1118/**
1119 * Check whether user is not active.
1120 *
1121 * @since 1.6.0
1122 *
1123 * @todo No need for the user fallback checks, since they're done in
1124 *       bp_is_user_active().
1125 *
1126 * @param int $user_id The user ID to check.
1127 * @return bool True if inactive, otherwise false.
1128 */
1129function bp_is_user_inactive( $user_id = 0 ) {
1130
1131        // Default to current user.
1132        if ( empty( $user_id ) && is_user_logged_in() ) {
1133                $user_id = bp_loggedin_user_id();
1134        }
1135
1136        // No user to check.
1137        if ( empty( $user_id ) ) {
1138                return false;
1139        }
1140
1141        // Return the inverse of active.
1142        return !bp_is_user_active( $user_id );
1143}
1144
1145/**
1146 * Update a user's last activity.
1147 *
1148 * @since 1.9.0
1149 *
1150 * @param int    $user_id ID of the user being updated.
1151 * @param string $time    Time of last activity, in 'Y-m-d H:i:s' format.
1152 * @return bool True on success, false on failure.
1153 */
1154function bp_update_user_last_activity( $user_id = 0, $time = '' ) {
1155
1156        // Fall back on current user.
1157        if ( empty( $user_id ) ) {
1158                $user_id = bp_loggedin_user_id();
1159        }
1160
1161        // Bail if the user id is 0, as there's nothing to update.
1162        if ( empty( $user_id ) ) {
1163                return false;
1164        }
1165
1166        // Fall back on current time.
1167        if ( empty( $time ) ) {
1168                $time = bp_core_current_time();
1169        }
1170
1171        // As of BuddyPress 2.0, last_activity is no longer stored in usermeta.
1172        // However, we mirror it there for backward compatibility. Do not use!
1173        // Remove our warning and re-add.
1174        remove_filter( 'update_user_metadata', '_bp_update_user_meta_last_activity_warning', 10 );
1175        remove_filter( 'get_user_metadata', '_bp_get_user_meta_last_activity_warning', 10 );
1176        bp_update_user_meta( $user_id, 'last_activity', $time );
1177        add_filter( 'update_user_metadata', '_bp_update_user_meta_last_activity_warning', 10, 4 );
1178        add_filter( 'get_user_metadata', '_bp_get_user_meta_last_activity_warning', 10, 3 );
1179
1180        return BP_Core_User::update_last_activity( $user_id, $time );
1181}
1182
1183/**
1184 * Backward compatibility for 'last_activity' usermeta fetching.
1185 *
1186 * In BuddyPress 2.0, user last_activity data was moved out of usermeta. For
1187 * backward compatibility, we continue to mirror the data there. This function
1188 * serves two purposes: it warns plugin authors of the change, and it returns
1189 * the data from the proper location.
1190 *
1191 * @since 2.0.0
1192 *
1193 * @access private For internal use only.
1194 *
1195 * @param null   $retval Null retval value.
1196 * @param int    $object_id ID of the user.
1197 * @param string $meta_key  Meta key being fetched.
1198 * @return string|null
1199 */
1200function _bp_get_user_meta_last_activity_warning( $retval, $object_id, $meta_key ) {
1201        static $warned = false;
1202
1203        if ( 'last_activity' === $meta_key ) {
1204                // Don't send the warning more than once per pageload.
1205                if ( false === $warned ) {
1206                        _doing_it_wrong( 'get_user_meta( $user_id, \'last_activity\' )', __( 'User last_activity data is no longer stored in usermeta. Use bp_get_user_last_activity() instead.', 'buddypress' ), '2.0.0' );
1207                        $warned = true;
1208                }
1209
1210                return bp_get_user_last_activity( $object_id );
1211        }
1212
1213        return $retval;
1214}
1215add_filter( 'get_user_metadata', '_bp_get_user_meta_last_activity_warning', 10, 3 );
1216
1217/**
1218 * Backward compatibility for 'last_activity' usermeta setting.
1219 *
1220 * In BuddyPress 2.0, user last_activity data was moved out of usermeta. For
1221 * backward compatibility, we continue to mirror the data there. This function
1222 * serves two purposes: it warns plugin authors of the change, and it updates
1223 * the data in the proper location.
1224 *
1225 * @since 2.0.0
1226 *
1227 * @access private For internal use only.
1228 *
1229 * @param int    $meta_id    ID of the just-set usermeta row.
1230 * @param int    $object_id  ID of the user.
1231 * @param string $meta_key   Meta key being fetched.
1232 * @param string $meta_value Active time.
1233 */
1234function _bp_update_user_meta_last_activity_warning( $meta_id, $object_id, $meta_key, $meta_value ) {
1235        if ( 'last_activity' === $meta_key ) {
1236                _doing_it_wrong( 'update_user_meta( $user_id, \'last_activity\' )', __( 'User last_activity data is no longer stored in usermeta. Use bp_update_user_last_activity() instead.', 'buddypress' ), '2.0.0' );
1237                bp_update_user_last_activity( $object_id, $meta_value );
1238        }
1239}
1240add_filter( 'update_user_metadata', '_bp_update_user_meta_last_activity_warning', 10, 4 );
1241
1242/**
1243 * Get the last activity for a given user.
1244 *
1245 * @since 1.9.0
1246 *
1247 * @param int $user_id The ID of the user.
1248 * @return string Time of last activity, in 'Y-m-d H:i:s' format, or an empty
1249 *                string if none is found.
1250 */
1251function bp_get_user_last_activity( $user_id = 0 ) {
1252        $activity = '';
1253
1254        $last_activity = BP_Core_User::get_last_activity( $user_id );
1255        if ( ! empty( $last_activity[ $user_id ] ) ) {
1256                $activity = $last_activity[ $user_id ]['date_recorded'];
1257        }
1258
1259        /**
1260         * Filters the last activity for a given user.
1261         *
1262         * @since 1.9.0
1263         *
1264         * @param string $activity Time of last activity, in 'Y-m-d H:i:s' format or
1265         *                         an empty string if none found.
1266         * @param int    $user_id  ID of the user being checked.
1267         */
1268        return apply_filters( 'bp_get_user_last_activity', $activity, $user_id );
1269}
1270
1271/**
1272 * Migrate last_activity data from the usermeta table to the activity table.
1273 *
1274 * Generally, this function is only run when BP is upgraded to 2.0. It can also
1275 * be called directly from the BuddyPress Tools panel.
1276 *
1277 * @since 2.0.0
1278 *
1279 * @return bool
1280 */
1281function bp_last_activity_migrate() {
1282        global $wpdb;
1283
1284        $bp = buddypress();
1285
1286        // Wipe out existing last_activity data in the activity table -
1287        // this helps to prevent duplicates when pulling from the usermeta
1288        // table.
1289        $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->members->table_name_last_activity} WHERE component = %s AND type = 'last_activity'", $bp->members->id ) );
1290
1291        $sql = "INSERT INTO {$bp->members->table_name_last_activity} (`user_id`, `component`, `type`, `action`, `content`, `primary_link`, `item_id`, `date_recorded` ) (
1292                  SELECT user_id, '{$bp->members->id}' as component, 'last_activity' as type, '' as action, '' as content, '' as primary_link, 0 as item_id, meta_value AS date_recorded
1293                  FROM {$wpdb->usermeta}
1294                  WHERE
1295                    meta_key = 'last_activity'
1296        );";
1297
1298        return $wpdb->query( $sql );
1299}
1300
1301/**
1302 * Fetch every post that is authored by the given user for the current blog.
1303 *
1304 * No longer used in BuddyPress.
1305 *
1306 * @todo Deprecate.
1307 *
1308 * @param int $user_id ID of the user being queried.
1309 * @return array Post IDs.
1310 */
1311function bp_core_get_all_posts_for_user( $user_id = 0 ) {
1312        global $wpdb;
1313
1314        if ( empty( $user_id ) ) {
1315                $user_id = bp_displayed_user_id();
1316        }
1317
1318        return apply_filters( 'bp_core_get_all_posts_for_user', $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_author = %d AND post_status = 'publish' AND post_type = 'post'", $user_id ) ) );
1319}
1320
1321/**
1322 * Process account deletion requests.
1323 *
1324 * Primarily used for self-deletions, as requested through Settings.
1325 *
1326 * @since 1.0.0
1327 *
1328 * @param int $user_id Optional. ID of the user to be deleted. Default: the
1329 *                     logged-in user.
1330 * @return bool True on success, false on failure.
1331 */
1332function bp_core_delete_account( $user_id = 0 ) {
1333
1334        // Use logged in user ID if none is passed.
1335        if ( empty( $user_id ) ) {
1336                $user_id = bp_loggedin_user_id();
1337        }
1338
1339        // Site admins cannot be deleted.
1340        if ( is_super_admin( $user_id ) ) {
1341                return false;
1342        }
1343
1344        // Extra checks if user is not deleting themselves.
1345        if ( bp_loggedin_user_id() !== absint( $user_id ) ) {
1346
1347                // Bail if current user cannot delete any users.
1348                if ( ! bp_current_user_can( 'delete_users' ) ) {
1349                        return false;
1350                }
1351
1352                // Bail if current user cannot delete this user.
1353                if ( ! current_user_can_for_blog( bp_get_root_blog_id(), 'delete_user', $user_id ) ) {
1354                        return false;
1355                }
1356        }
1357
1358        /**
1359         * Fires before the processing of an account deletion.
1360         *
1361         * @since 1.6.0
1362         *
1363         * @param int $user_id ID of the user account being deleted.
1364         */
1365        do_action( 'bp_core_pre_delete_account', $user_id );
1366
1367        // Specifically handle multi-site environment.
1368        if ( is_multisite() ) {
1369                require_once( ABSPATH . '/wp-admin/includes/ms.php'   );
1370                require_once( ABSPATH . '/wp-admin/includes/user.php' );
1371
1372                $retval = wpmu_delete_user( $user_id );
1373
1374        // Single site user deletion.
1375        } else {
1376                require_once( ABSPATH . '/wp-admin/includes/user.php' );
1377                $retval = wp_delete_user( $user_id );
1378        }
1379
1380        /**
1381         * Fires after the deletion of an account.
1382         *
1383         * @since 1.6.0
1384         *
1385         * @param int $user_id ID of the user account that was deleted.
1386         */
1387        do_action( 'bp_core_deleted_account', $user_id );
1388
1389        return $retval;
1390}
1391
1392/**
1393 * Delete a user's avatar when the user is deleted.
1394 *
1395 * @since 1.9.0
1396 *
1397 * @param int $user_id ID of the user who is about to be deleted.
1398 * @return bool True on success, false on failure.
1399 */
1400function bp_core_delete_avatar_on_user_delete( $user_id ) {
1401        return bp_core_delete_existing_avatar( array(
1402                'item_id' => $user_id,
1403                'object'  => 'user',
1404        ) );
1405}
1406add_action( 'wpmu_delete_user', 'bp_core_delete_avatar_on_user_delete' );
1407add_action( 'delete_user', 'bp_core_delete_avatar_on_user_delete' );
1408
1409/**
1410 * Multibyte-safe ucfirst() support.
1411 *
1412 * Uses multibyte functions when available on the PHP build.
1413 *
1414 * @since 1.0.0
1415 *
1416 * @param string $str String to be upper-cased.
1417 * @return string
1418 */
1419function bp_core_ucfirst( $str ) {
1420        if ( function_exists( 'mb_strtoupper' ) && function_exists( 'mb_substr' ) ) {
1421                $fc = mb_strtoupper( mb_substr( $str, 0, 1 ) );
1422                return $fc.mb_substr( $str, 1 );
1423        } else {
1424                return ucfirst( $str );
1425        }
1426}
1427
1428/**
1429 * Prevent spammers from logging in.
1430 *
1431 * When a user logs in, check if they have been marked as a spammer. If yes
1432 * then simply redirect them to the home page and stop them from logging in.
1433 *
1434 * @since 1.1.2
1435 *
1436 * @param WP_User|WP_Error $user Either the WP_User object or the WP_Error
1437 *                               object, as passed to the 'authenticate' filter.
1438 * @return WP_User|WP_Error If the user is not a spammer, return the WP_User
1439 *                          object. Otherwise a new WP_Error object.
1440 */
1441function bp_core_boot_spammer( $user ) {
1442
1443        // Check to see if the $user has already failed logging in, if so return $user as-is.
1444        if ( is_wp_error( $user ) || empty( $user ) ) {
1445                return $user;
1446        }
1447
1448        // The user exists; now do a check to see if the user is a spammer
1449        // if the user is a spammer, stop them in their tracks!
1450        if ( is_a( $user, 'WP_User' ) && ( ( is_multisite() && (int) $user->spam ) || 1 == $user->user_status ) ) {
1451                return new WP_Error( 'invalid_username', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.', 'buddypress' ) );
1452        }
1453
1454        // User is good to go!
1455        return $user;
1456}
1457add_filter( 'authenticate', 'bp_core_boot_spammer', 30 );
1458
1459/**
1460 * Delete last_activity data for the user when the user is deleted.
1461 *
1462 * @since 1.0.0
1463 *
1464 * @param int $user_id The user ID for the user to delete usermeta for.
1465 */
1466function bp_core_remove_data( $user_id ) {
1467
1468        // Remove last_activity data.
1469        BP_Core_User::delete_last_activity( $user_id );
1470
1471        // Flush the cache to remove the user from all cached objects.
1472        wp_cache_flush();
1473}
1474add_action( 'wpmu_delete_user',  'bp_core_remove_data' );
1475add_action( 'delete_user',       'bp_core_remove_data' );
1476add_action( 'bp_make_spam_user', 'bp_core_remove_data' );
1477
1478/**
1479 * Check whether the logged-in user can edit settings for the displayed user.
1480 *
1481 * @since 1.5.0
1482 *
1483 * @return bool True if editing is allowed, otherwise false.
1484 */
1485function bp_core_can_edit_settings() {
1486        $status = false;
1487
1488        if ( bp_is_my_profile() ) {
1489                $status = true;
1490        } elseif ( is_super_admin( bp_displayed_user_id() ) && ! is_super_admin() ) {
1491                $status = false;
1492        } elseif ( bp_current_user_can( 'bp_moderate' ) || current_user_can( 'edit_users' ) ) {
1493                $status = true;
1494        }
1495
1496        /**
1497         * Filters the status of whether the logged-in user can edit settings for the displayed user or not.
1498         *
1499         * @since 2.8.0
1500         *
1501         * @param bool True if editing is allowed, otherwise false.
1502         */
1503        return apply_filters( 'bp_core_can_edit_settings', $status );
1504}
1505
1506/** Sign-up *******************************************************************/
1507
1508/**
1509 * Flush illegal names by getting and setting 'illegal_names' site option.
1510 *
1511 * @since 1.2.5
1512 */
1513function bp_core_flush_illegal_names() {
1514        $illegal_names = get_site_option( 'illegal_names' );
1515        update_site_option( 'illegal_names', $illegal_names );
1516}
1517
1518/**
1519 * Add BuddyPress-specific items to the illegal_names array.
1520 *
1521 * @since 1.2.7
1522 *
1523 * @param array|string $value    Illegal names as being saved defined in
1524 *                               Multisite settings.
1525 * @param array|string $oldvalue The old value of the option.
1526 * @return array Merged and unique array of illegal names.
1527 */
1528function bp_core_get_illegal_names( $value = '', $oldvalue = '' ) {
1529
1530        // Make sure $value is array.
1531        if ( empty( $value ) ) {
1532                $db_illegal_names = array();
1533        }
1534
1535        if ( is_array( $value ) ) {
1536                $db_illegal_names = $value;
1537        } elseif ( is_string( $value ) ) {
1538                $db_illegal_names = explode( ' ', $value );
1539        }
1540
1541        // Add the core components' slugs to the banned list even if their components aren't active.
1542        $bp_component_slugs = array(
1543                'groups',
1544                'members',
1545                'forums',
1546                'blogs',
1547                'activity',
1548                'profile',
1549                'friends',
1550                'search',
1551                'settings',
1552                'notifications',
1553                'register',
1554                'activate'
1555        );
1556
1557        // Core constants.
1558        $slug_constants = array(
1559                'BP_GROUPS_SLUG',
1560                'BP_MEMBERS_SLUG',
1561                'BP_FORUMS_SLUG',
1562                'BP_BLOGS_SLUG',
1563                'BP_ACTIVITY_SLUG',
1564                'BP_XPROFILE_SLUG',
1565                'BP_FRIENDS_SLUG',
1566                'BP_SEARCH_SLUG',
1567                'BP_SETTINGS_SLUG',
1568                'BP_NOTIFICATIONS_SLUG',
1569                'BP_REGISTER_SLUG',
1570                'BP_ACTIVATION_SLUG',
1571        );
1572        foreach( $slug_constants as $constant ) {
1573                if ( defined( $constant ) ) {
1574                        $bp_component_slugs[] = constant( $constant );
1575                }
1576        }
1577
1578        /**
1579         * Filters the array of default illegal usernames.
1580         *
1581         * @since 1.2.2
1582         *
1583         * @param array $value Merged and unique array of illegal usernames.
1584         */
1585        $filtered_illegal_names = apply_filters( 'bp_core_illegal_usernames', array_merge( array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' ), $bp_component_slugs ) );
1586
1587        // Merge the arrays together.
1588        $merged_names           = array_merge( (array) $filtered_illegal_names, (array) $db_illegal_names );
1589
1590        // Remove duplicates.
1591        $illegal_names          = array_unique( (array) $merged_names );
1592
1593        /**
1594         * Filters the array of default illegal names.
1595         *
1596         * @since 1.2.5
1597         *
1598         * @param array $value Merged and unique array of illegal names.
1599         */
1600        return apply_filters( 'bp_core_illegal_names', $illegal_names );
1601}
1602add_filter( 'pre_update_site_option_illegal_names', 'bp_core_get_illegal_names', 10, 2 );
1603
1604/**
1605 * Check that an email address is valid for use.
1606 *
1607 * Performs the following checks:
1608 *   - Is the email address well-formed?
1609 *   - Is the email address already used?
1610 *   - If there's an email domain blacklist, is the current domain on it?
1611 *   - If there's an email domain whitelest, is the current domain on it?
1612 *
1613 * @since 1.6.2
1614 *
1615 * @param string $user_email The email being checked.
1616 * @return bool|array True if the address passes all checks; otherwise an array
1617 *                    of error codes.
1618 */
1619function bp_core_validate_email_address( $user_email ) {
1620        $errors = array();
1621
1622        $user_email = sanitize_email( $user_email );
1623
1624        // Is the email well-formed?
1625        if ( ! is_email( $user_email ) ) {
1626                $errors['invalid'] = 1;
1627        }
1628
1629        // Is the email on the Banned Email Domains list?
1630        // Note: This check only works on Multisite.
1631        if ( function_exists( 'is_email_address_unsafe' ) && is_email_address_unsafe( $user_email ) ) {
1632                $errors['domain_banned'] = 1;
1633        }
1634
1635        // Is the email on the Limited Email Domains list?
1636        // Note: This check only works on Multisite.
1637        $limited_email_domains = get_site_option( 'limited_email_domains' );
1638        if ( is_array( $limited_email_domains ) && empty( $limited_email_domains ) == false ) {
1639                $emaildomain = substr( $user_email, 1 + strpos( $user_email, '@' ) );
1640                if ( ! in_array( $emaildomain, $limited_email_domains ) ) {
1641                        $errors['domain_not_allowed'] = 1;
1642                }
1643        }
1644
1645        // Is the email alreday in use?
1646        if ( email_exists( $user_email ) ) {
1647                $errors['in_use'] = 1;
1648        }
1649
1650        $retval = ! empty( $errors ) ? $errors : true;
1651
1652        return $retval;
1653}
1654
1655/**
1656 * Add the appropriate errors to a WP_Error object, given results of a validation test.
1657 *
1658 * Functions like bp_core_validate_email_address() return a structured array
1659 * of error codes. bp_core_add_validation_error_messages() takes this array and
1660 * parses, adding the appropriate error messages to the WP_Error object.
1661 *
1662 * @since 1.7.0
1663 *
1664 * @see bp_core_validate_email_address()
1665 *
1666 * @param WP_Error $errors             WP_Error object.
1667 * @param array    $validation_results The return value of a validation function
1668 *                                     like bp_core_validate_email_address().
1669 */
1670function bp_core_add_validation_error_messages( WP_Error $errors, $validation_results ) {
1671        if ( ! empty( $validation_results['invalid'] ) ) {
1672                $errors->add( 'user_email', __( 'Please check your email address.', 'buddypress' ) );
1673        }
1674
1675        if ( ! empty( $validation_results['domain_banned'] ) ) {
1676                $errors->add( 'user_email',  __( 'Sorry, that email address is not allowed!', 'buddypress' ) );
1677        }
1678
1679        if ( ! empty( $validation_results['domain_not_allowed'] ) ) {
1680                $errors->add( 'user_email', __( 'Sorry, that email address is not allowed!', 'buddypress' ) );
1681        }
1682
1683        if ( ! empty( $validation_results['in_use'] ) ) {
1684                $errors->add( 'user_email', __( 'Sorry, that email address is already used!', 'buddypress' ) );
1685        }
1686}
1687
1688/**
1689 * Validate a user name and email address when creating a new user.
1690 *
1691 * @since 1.2.2
1692 *
1693 * @param string $user_name  Username to validate.
1694 * @param string $user_email Email address to validate.
1695 * @return array Results of user validation including errors, if any.
1696 */
1697function bp_core_validate_user_signup( $user_name, $user_email ) {
1698
1699        // Make sure illegal names include BuddyPress slugs and values.
1700        bp_core_flush_illegal_names();
1701
1702        // WordPress Multisite has its own validation. Use it, so that we
1703        // properly mirror restrictions on username, etc.
1704        if ( function_exists( 'wpmu_validate_user_signup' ) ) {
1705                $result = wpmu_validate_user_signup( $user_name, $user_email );
1706
1707        // When not running Multisite, we perform our own validation. What
1708        // follows reproduces much of the logic of wpmu_validate_user_signup(),
1709        // minus the multisite-specific restrictions on user_login.
1710        } else {
1711                $errors = new WP_Error();
1712
1713                /**
1714                 * Filters the username before being validated.
1715                 *
1716                 * @since 1.5.5
1717                 *
1718                 * @param string $user_name Username to validate.
1719                 */
1720                $user_name = apply_filters( 'pre_user_login', $user_name );
1721
1722                // User name can't be empty.
1723                if ( empty( $user_name ) ) {
1724                        $errors->add( 'user_name', __( 'Please enter a username', 'buddypress' ) );
1725                }
1726
1727                // User name can't be on the blacklist.
1728                $illegal_names = get_site_option( 'illegal_names' );
1729                if ( in_array( $user_name, (array) $illegal_names ) ) {
1730                        $errors->add( 'user_name', __( 'That username is not allowed', 'buddypress' ) );
1731                }
1732
1733                // User name must pass WP's validity check.
1734                if ( ! validate_username( $user_name ) ) {
1735                        $errors->add( 'user_name', __( 'Usernames can contain only letters, numbers, ., -, and @', 'buddypress' ) );
1736                }
1737
1738                // Minimum of 4 characters.
1739                if ( strlen( $user_name ) < 4 ) {
1740                        $errors->add( 'user_name',  __( 'Username must be at least 4 characters', 'buddypress' ) );
1741                }
1742
1743                // No underscores. @todo Why not?
1744                if ( false !== strpos( ' ' . $user_name, '_' ) ) {
1745                        $errors->add( 'user_name', __( 'Sorry, usernames may not contain the character "_"!', 'buddypress' ) );
1746                }
1747
1748                // No usernames that are all numeric. @todo Why?
1749                $match = array();
1750                preg_match( '/[0-9]*/', $user_name, $match );
1751                if ( $match[0] == $user_name ) {
1752                        $errors->add( 'user_name', __( 'Sorry, usernames must have letters too!', 'buddypress' ) );
1753                }
1754
1755                // Check into signups.
1756                $signups = BP_Signup::get( array(
1757                        'user_login' => $user_name,
1758                ) );
1759
1760                $signup = isset( $signups['signups'] ) && ! empty( $signups['signups'][0] ) ? $signups['signups'][0] : false;
1761
1762                // Check if the username has been used already.
1763                if ( username_exists( $user_name ) || ! empty( $signup ) ) {
1764                        $errors->add( 'user_name', __( 'Sorry, that username already exists!', 'buddypress' ) );
1765                }
1766
1767                // Validate the email address and process the validation results into
1768                // error messages.
1769                $validate_email = bp_core_validate_email_address( $user_email );
1770                bp_core_add_validation_error_messages( $errors, $validate_email );
1771
1772                // Assemble the return array.
1773                $result = array(
1774                        'user_name'  => $user_name,
1775                        'user_email' => $user_email,
1776                        'errors'     => $errors,
1777                );
1778
1779                // Apply WPMU legacy filter.
1780                $result = apply_filters( 'wpmu_validate_user_signup', $result );
1781        }
1782
1783        /**
1784         * Filters the result of the user signup validation.
1785         *
1786         * @since 1.2.2
1787         *
1788         * @param array $result Results of user validation including errors, if any.
1789         */
1790        return apply_filters( 'bp_core_validate_user_signup', $result );
1791}
1792
1793/**
1794 * Validate blog URL and title provided at signup.
1795 *
1796 * @since 1.2.2
1797 *
1798 * @todo Why do we have this wrapper?
1799 *
1800 * @param string $blog_url   Blog URL requested during registration.
1801 * @param string $blog_title Blog title requested during registration.
1802 * @return array
1803 */
1804function bp_core_validate_blog_signup( $blog_url, $blog_title ) {
1805        if ( ! is_multisite() || ! function_exists( 'wpmu_validate_blog_signup' ) ) {
1806                return false;
1807        }
1808
1809        /**
1810         * Filters the validated blog url and title provided at signup.
1811         *
1812         * @since 1.2.2
1813         *
1814         * @param array $value Array with the new site data and error messages.
1815         */
1816        return apply_filters( 'bp_core_validate_blog_signup', wpmu_validate_blog_signup( $blog_url, $blog_title ) );
1817}
1818
1819/**
1820 * Process data submitted at user registration and convert to a signup object.
1821 *
1822 * @since 1.2.0
1823 *
1824 * @todo There appears to be a bug in the return value on success.
1825 *
1826 * @param string $user_login    Login name requested by the user.
1827 * @param string $user_password Password requested by the user.
1828 * @param string $user_email    Email address entered by the user.
1829 * @param array  $usermeta      Miscellaneous metadata about the user (blog-specific
1830 *                              signup data, xprofile data, etc).
1831 * @return int|false True on success, WP_Error on failure.
1832 */
1833function bp_core_signup_user( $user_login, $user_password, $user_email, $usermeta ) {
1834        $bp = buddypress();
1835
1836        // We need to cast $user_id to pass to the filters.
1837        $user_id = false;
1838
1839        // Multisite installs have their own install procedure.
1840        if ( is_multisite() ) {
1841                wpmu_signup_user( $user_login, $user_email, $usermeta );
1842
1843        } else {
1844                // Format data.
1845                $user_login     = preg_replace( '/\s+/', '', sanitize_user( $user_login, true ) );
1846                $user_email     = sanitize_email( $user_email );
1847                $activation_key = wp_generate_password( 32, false );
1848
1849                /**
1850                 * WordPress's default behavior is to create user accounts
1851                 * immediately at registration time. BuddyPress uses a system
1852                 * borrowed from WordPress Multisite, where signups are stored
1853                 * separately and accounts are only created at the time of
1854                 * activation. For backward compatibility with plugins that may
1855                 * be anticipating WP's default behavior, BP silently creates
1856                 * accounts for registrations (though it does not use them). If
1857                 * you know that you are not running any plugins dependent on
1858                 * these pending accounts, you may want to save a little DB
1859                 * clutter by defining setting the BP_SIGNUPS_SKIP_USER_CREATION
1860                 * to true in your wp-config.php file.
1861                 */
1862                if ( ! defined( 'BP_SIGNUPS_SKIP_USER_CREATION' ) || ! BP_SIGNUPS_SKIP_USER_CREATION ) {
1863                        $user_id = BP_Signup::add_backcompat( $user_login, $user_password, $user_email, $usermeta );
1864
1865                        if ( is_wp_error( $user_id ) ) {
1866                                return $user_id;
1867                        }
1868
1869                        bp_update_user_meta( $user_id, 'activation_key', $activation_key );
1870                }
1871
1872                $args = array(
1873                        'user_login'     => $user_login,
1874                        'user_email'     => $user_email,
1875                        'activation_key' => $activation_key,
1876                        'meta'           => $usermeta,
1877                );
1878
1879                BP_Signup::add( $args );
1880
1881                /**
1882                 * Filters if BuddyPress should send an activation key for a new signup.
1883                 *
1884                 * @since 1.2.3
1885                 *
1886                 * @param bool   $value          Whether or not to send the activation key.
1887                 * @param int    $user_id        User ID to send activation key to.
1888                 * @param string $user_email     User email to send activation key to.
1889                 * @param string $activation_key Activation key to be sent.
1890                 * @param array  $usermeta       Miscellaneous metadata about the user (blog-specific
1891                 *                               signup data, xprofile data, etc).
1892                 */
1893                if ( apply_filters( 'bp_core_signup_send_activation_key', true, $user_id, $user_email, $activation_key, $usermeta ) ) {
1894                        bp_core_signup_send_validation_email( $user_id, $user_email, $activation_key, $user_login );
1895                }
1896        }
1897
1898        $bp->signup->username = $user_login;
1899
1900        /**
1901         * Fires at the end of the process to sign up a user.
1902         *
1903         * @since 1.2.2
1904         *
1905         * @param bool|WP_Error   $user_id       True on success, WP_Error on failure.
1906         * @param string          $user_login    Login name requested by the user.
1907         * @param string          $user_password Password requested by the user.
1908         * @param string          $user_email    Email address requested by the user.
1909         * @param array           $usermeta      Miscellaneous metadata about the user (blog-specific
1910         *                                       signup data, xprofile data, etc).
1911         */
1912        do_action( 'bp_core_signup_user', $user_id, $user_login, $user_password, $user_email, $usermeta );
1913
1914        return $user_id;
1915}
1916
1917/**
1918 * Create a blog and user based on data supplied at user registration.
1919 *
1920 * @since 1.2.2
1921 *
1922 * @param string $blog_domain Domain requested by user.
1923 * @param string $blog_path   Path requested by user.
1924 * @param string $blog_title  Title as entered by user.
1925 * @param string $user_name   user_login of requesting user.
1926 * @param string $user_email  Email address of requesting user.
1927 * @param string $usermeta    Miscellaneous metadata for the user.
1928 * @return bool
1929 */
1930function bp_core_signup_blog( $blog_domain, $blog_path, $blog_title, $user_name, $user_email, $usermeta ) {
1931        if ( ! is_multisite() || ! function_exists( 'wpmu_signup_blog' ) ) {
1932                return false;
1933        }
1934
1935        /**
1936         * Filters the result of wpmu_signup_blog().
1937         *
1938         * This filter provides no value and is retained for
1939         * backwards compatibility.
1940         *
1941         * @since 1.2.2
1942         *
1943         * @param void $value
1944         */
1945        return apply_filters( 'bp_core_signup_blog', wpmu_signup_blog( $blog_domain, $blog_path, $blog_title, $user_name, $user_email, $usermeta ) );
1946}
1947
1948/**
1949 * Activate a signup, as identified by an activation key.
1950 *
1951 * @since 1.2.2
1952 *
1953 * @param string $key Activation key.
1954 * @return int|bool User ID on success, false on failure.
1955 */
1956function bp_core_activate_signup( $key ) {
1957        global $wpdb;
1958
1959        $user = false;
1960
1961        // Multisite installs have their own activation routine.
1962        if ( is_multisite() ) {
1963                $user = wpmu_activate_signup( $key );
1964
1965                // If there were errors, add a message and redirect.
1966                if ( ! empty( $user->errors ) ) {
1967                        return $user;
1968                }
1969
1970                $user_id = $user['user_id'];
1971
1972        } else {
1973                $signups = BP_Signup::get( array(
1974                        'activation_key' => $key,
1975                ) );
1976
1977                if ( empty( $signups['signups'] ) ) {
1978                        return new WP_Error( 'invalid_key', __( 'Invalid activation key.', 'buddypress' ) );
1979                }
1980
1981                $signup = $signups['signups'][0];
1982
1983                if ( $signup->active ) {
1984                        if ( empty( $signup->domain ) ) {
1985                                return new WP_Error( 'already_active', __( 'The user is already active.', 'buddypress' ), $signup );
1986                        } else {
1987                                return new WP_Error( 'already_active', __( 'The site is already active.', 'buddypress' ), $signup );
1988                        }
1989                }
1990
1991                // Password is hashed again in wp_insert_user.
1992                $password = wp_generate_password( 12, false );
1993
1994                $user_id = username_exists( $signup->user_login );
1995
1996                // Create the user. This should only be necessary if BP_SIGNUPS_SKIP_USER_CREATION is true.
1997                if ( ! $user_id ) {
1998                        $user_id = wp_create_user( $signup->user_login, $password, $signup->user_email );
1999
2000                // Otherwise, update the existing user's status.
2001                } elseif ( $key === bp_get_user_meta( $user_id, 'activation_key', true ) || $key === wp_hash( $user_id ) ) {
2002
2003                        // Change the user's status so they become active.
2004                        if ( ! $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_status = 0 WHERE ID = %d", $user_id ) ) ) {
2005                                return new WP_Error( 'invalid_key', __( 'Invalid activation key.', 'buddypress' ) );
2006                        }
2007
2008                        bp_delete_user_meta( $user_id, 'activation_key' );
2009
2010                        $member = get_userdata( $user_id );
2011                        $member->set_role( get_option('default_role') );
2012
2013                        $user_already_created = true;
2014
2015                } else {
2016                        $user_already_exists = true;
2017                }
2018
2019                if ( ! $user_id ) {
2020                        return new WP_Error( 'create_user', __( 'Could not create user', 'buddypress' ), $signup );
2021                }
2022
2023                // Fetch the signup so we have the data later on.
2024                $signups = BP_Signup::get( array(
2025                        'activation_key' => $key,
2026                ) );
2027
2028                $signup = isset( $signups['signups'] ) && ! empty( $signups['signups'][0] ) ? $signups['signups'][0] : false;
2029
2030                // Activate the signup.
2031                BP_Signup::validate( $key );
2032
2033                if ( isset( $user_already_exists ) ) {
2034                        return new WP_Error( 'user_already_exists', __( 'That username is already activated.', 'buddypress' ), $signup );
2035                }
2036
2037                // Set up data to pass to the legacy filter.
2038                $user = array(
2039                        'user_id'  => $user_id,
2040                        'password' => $signup->meta['password'],
2041                        'meta'     => $signup->meta,
2042                );
2043
2044                // Notify the site admin of a new user registration.
2045                if ( apply_filters( 'bp_sent_notification_to_admin_on_user_registration', true) )
2046                        wp_new_user_notification( $user_id );
2047
2048                if ( isset( $user_already_created ) ) {
2049
2050                        /**
2051                         * Fires if the user has already been created.
2052                         *
2053                         * @since 1.2.2
2054                         *
2055                         * @param int    $user_id ID of the user being checked.
2056                         * @param string $key     Activation key.
2057                         * @param array  $user    Array of user data.
2058                         */
2059                        do_action( 'bp_core_activated_user', $user_id, $key, $user );
2060                        return $user_id;
2061                }
2062        }
2063
2064        // Set any profile data.
2065        if ( bp_is_active( 'xprofile' ) ) {
2066                if ( ! empty( $user['meta']['profile_field_ids'] ) ) {
2067                        $profile_field_ids = explode( ',', $user['meta']['profile_field_ids'] );
2068
2069                        foreach( (array) $profile_field_ids as $field_id ) {
2070                                $current_field = isset( $user['meta']["field_{$field_id}"] ) ? $user['meta']["field_{$field_id}"] : false;
2071
2072                                if ( !empty( $current_field ) ) {
2073                                        xprofile_set_field_data( $field_id, $user_id, $current_field );
2074                                }
2075
2076                                /*
2077                                 * Save the visibility level.
2078                                 *
2079                                 * Use the field's default visibility if not present, and 'public' if a
2080                                 * default visibility is not defined.
2081                                 */
2082                                $key = "field_{$field_id}_visibility";
2083                                if ( isset( $user['meta'][ $key ] ) ) {
2084                                        $visibility_level = $user['meta'][ $key ];
2085                                } else {
2086                                        $vfield           = xprofile_get_field( $field_id );
2087                                        $visibility_level = isset( $vfield->default_visibility ) ? $vfield->default_visibility : 'public';
2088                                }
2089                                xprofile_set_field_visibility_level( $field_id, $user_id, $visibility_level );
2090                        }
2091                }
2092        }
2093
2094        // Replace the password automatically generated by WordPress by the one the user chose.
2095        if ( ! empty( $user['meta']['password'] ) ) {
2096                $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_pass = %s WHERE ID = %d", $user['meta']['password'], $user_id ) );
2097
2098                /**
2099                 * Make sure to clean the user's cache as we've
2100                 * directly edited the password without using
2101                 * wp_update_user().
2102                 *
2103                 * If we can't use wp_update_user() that's because
2104                 * we already hashed the password at the signup step.
2105                 */
2106                $uc = wp_cache_get( $user_id, 'users' );
2107
2108                if ( ! empty( $uc->ID ) ) {
2109                        clean_user_cache( $uc->ID );
2110                }
2111        }
2112
2113        /**
2114         * Fires at the end of the user activation process.
2115         *
2116         * @since 1.2.2
2117         *
2118         * @param int    $user_id ID of the user being checked.
2119         * @param string $key     Activation key.
2120         * @param array  $user    Array of user data.
2121         */
2122        do_action( 'bp_core_activated_user', $user_id, $key, $user );
2123
2124        return $user_id;
2125}
2126
2127/**
2128 * Migrate signups from pre-2.0 configuration to wp_signups.
2129 *
2130 * @since 2.0.1
2131 */
2132function bp_members_migrate_signups() {
2133        global $wpdb;
2134
2135        $status_2_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->users} WHERE user_status = '2'" );
2136
2137        if ( ! empty( $status_2_ids ) ) {
2138                $signups = get_users( array(
2139                        'fields'  => array(
2140                                'ID',
2141                                'user_login',
2142                                'user_pass',
2143                                'user_registered',
2144                                'user_email',
2145                                'display_name',
2146                        ),
2147                        'include' => $status_2_ids,
2148                ) );
2149
2150                // Fetch activation keys separately, to avoid the all_with_meta
2151                // overhead.
2152                $status_2_ids_sql = implode( ',', $status_2_ids );
2153                $ak_data = $wpdb->get_results( "SELECT user_id, meta_value FROM {$wpdb->usermeta} WHERE meta_key = 'activation_key' AND user_id IN ({$status_2_ids_sql})" );
2154
2155                // Rekey.
2156                $activation_keys = array();
2157                foreach ( $ak_data as $ak_datum ) {
2158                        $activation_keys[ intval( $ak_datum->user_id ) ] = $ak_datum->meta_value;
2159                }
2160
2161                unset( $status_2_ids_sql, $status_2_ids, $ak_data );
2162
2163                // Merge.
2164                foreach ( $signups as &$signup ) {
2165                        if ( isset( $activation_keys[ $signup->ID ] ) ) {
2166                                $signup->activation_key = $activation_keys[ $signup->ID ];
2167                        }
2168                }
2169
2170                // Reset the signup var as we're using it to process the migration.
2171                unset( $signup );
2172
2173        } else {
2174                return;
2175        }
2176
2177        foreach ( $signups as $signup ) {
2178                $meta = array();
2179
2180                // Rebuild the activation key, if missing.
2181                if ( empty( $signup->activation_key ) ) {
2182                        $signup->activation_key = wp_generate_password( 32, false );
2183                }
2184
2185                if ( bp_is_active( 'xprofile' ) ) {
2186                        $meta['field_1'] = $signup->display_name;
2187                }
2188
2189                $meta['password'] = $signup->user_pass;
2190
2191                $user_login = preg_replace( '/\s+/', '', sanitize_user( $signup->user_login, true ) );
2192                $user_email = sanitize_email( $signup->user_email );
2193
2194                BP_Signup::add( array(
2195                        'user_login'     => $user_login,
2196                        'user_email'     => $user_email,
2197                        'registered'     => $signup->user_registered,
2198                        'activation_key' => $signup->activation_key,
2199                        'meta'           => $meta
2200                ) );
2201
2202                // Deleting these options will remove signups from users count.
2203                delete_user_option( $signup->ID, 'capabilities' );
2204                delete_user_option( $signup->ID, 'user_level'   );
2205        }
2206}
2207
2208/**
2209 * Map a user's WP display name to the XProfile fullname field, if necessary.
2210 *
2211 * This only happens when a user is registered in wp-admin by an administrator;
2212 * during normal registration, XProfile data is provided directly by the user.
2213 *
2214 * @since 1.2.0
2215 *
2216 * @param int $user_id ID of the user.
2217 * @return bool
2218 */
2219function bp_core_map_user_registration( $user_id ) {
2220
2221        // Only map data when the site admin is adding users, not on registration.
2222        if ( ! is_admin() ) {
2223                return false;
2224        }
2225
2226        // Add the user's fullname to Xprofile.
2227        if ( bp_is_active( 'xprofile' ) ) {
2228                $firstname = bp_get_user_meta( $user_id, 'first_name', true );
2229                $lastname = ' ' . bp_get_user_meta( $user_id, 'last_name', true );
2230                $name = $firstname . $lastname;
2231
2232                if ( empty( $name ) || ' ' == $name ) {
2233                        $name = bp_get_user_meta( $user_id, 'nickname', true );
2234                }
2235
2236                xprofile_set_field_data( 1, $user_id, $name );
2237        }
2238}
2239add_action( 'user_register', 'bp_core_map_user_registration' );
2240
2241/**
2242 * Get the avatar storage directory for use during registration.
2243 *
2244 * @since 1.1.0
2245 *
2246 * @return string|bool Directory path on success, false on failure.
2247 */
2248function bp_core_signup_avatar_upload_dir() {
2249        $bp = buddypress();
2250
2251        if ( empty( $bp->signup->avatar_dir ) ) {
2252                return false;
2253        }
2254
2255        $directory = 'avatars/signups';
2256        $path      = bp_core_avatar_upload_path() . '/' . $directory . '/' . $bp->signup->avatar_dir;
2257        $newbdir   = $path;
2258        $newurl    = bp_core_avatar_url() . '/' . $directory . '/' . $bp->signup->avatar_dir;
2259        $newburl   = $newurl;
2260        $newsubdir = '/' . $directory . '/' . $bp->signup->avatar_dir;
2261
2262        /**
2263         * Filters the avatar storage directory for use during registration.
2264         *
2265         * @since 1.1.1
2266         *
2267         * @param array $value Array of path and URL values for created storage directory.
2268         */
2269        return apply_filters( 'bp_core_signup_avatar_upload_dir', array(
2270                'path'    => $path,
2271                'url'     => $newurl,
2272                'subdir'  => $newsubdir,
2273                'basedir' => $newbdir,
2274                'baseurl' => $newburl,
2275                'error'   => false
2276        ) );
2277}
2278
2279/**
2280 * Send activation email to a newly registered user.
2281 *
2282 * @since 1.2.2
2283 * @since 2.5.0 Add the $user_login parameter.
2284 *
2285 * @param int|bool $user_id    ID of the new user, false if BP_SIGNUPS_SKIP_USER_CREATION is true.
2286 * @param string   $user_email Email address of the new user.
2287 * @param string   $key        Activation key.
2288 * @param string   $user_login Optional. The user login name.
2289 */
2290function bp_core_signup_send_validation_email( $user_id, $user_email, $key, $user_login = '' ) {
2291        $args = array(
2292                'tokens' => array(
2293                        'activate.url' => esc_url( trailingslashit( bp_get_activation_page() ) . "{$key}/" ),
2294                        'key'          => $key,
2295                        'user.email'   => $user_email,
2296                        'user.id'      => $user_id,
2297                ),
2298        );
2299
2300        if ( $user_id ) {
2301                $to = $user_id;
2302        } else {
2303                $to = array( array( $user_email => $user_login ) );
2304        }
2305
2306        bp_send_email( 'core-user-registration', $to, $args );
2307}
2308
2309/**
2310 * Display a "resend email" link when an unregistered user attempts to log in.
2311 *
2312 * @since 1.2.2
2313 *
2314 * @param WP_User|WP_Error|null $user     Either the WP_User or the WP_Error object.
2315 * @param string                $username The inputted, attempted username.
2316 * @param string                $password The inputted, attempted password.
2317 * @return WP_User|WP_Error
2318 */
2319function bp_core_signup_disable_inactive( $user = null, $username = '', $password ='' ) {
2320        // Login form not used.
2321        if ( empty( $username ) && empty( $password ) ) {
2322                return $user;
2323        }
2324
2325        // An existing WP_User with a user_status of 2 is either a legacy
2326        // signup, or is a user created for backward compatibility. See
2327        // {@link bp_core_signup_user()} for more details.
2328        if ( is_a( $user, 'WP_User' ) && 2 == $user->user_status ) {
2329                $user_login = $user->user_login;
2330
2331        // If no WP_User is found corresponding to the username, this
2332        // is a potential signup.
2333        } elseif ( is_wp_error( $user ) && 'invalid_username' == $user->get_error_code() ) {
2334                $user_login = $username;
2335
2336        // This is an activated user, so bail.
2337        } else {
2338                return $user;
2339        }
2340
2341        // Look for the unactivated signup corresponding to the login name.
2342        $signup = BP_Signup::get( array( 'user_login' => sanitize_user( $user_login ) ) );
2343
2344        // No signup or more than one, something is wrong. Let's bail.
2345        if ( empty( $signup['signups'][0] ) || $signup['total'] > 1 ) {
2346                return $user;
2347        }
2348
2349        // Unactivated user account found!
2350        // Set up the feedback message.
2351        $signup_id = $signup['signups'][0]->signup_id;
2352
2353        $resend_url_params = array(
2354                'action' => 'bp-resend-activation',
2355                'id'     => $signup_id,
2356        );
2357
2358        $resend_url = wp_nonce_url(
2359                add_query_arg( $resend_url_params, wp_login_url() ),
2360                'bp-resend-activation'
2361        );
2362
2363        $resend_string = '<br /><br />' . sprintf( __( 'If you have not received an email yet, <a href="%s">click here to resend it</a>.', 'buddypress' ), esc_url( $resend_url ) );
2364
2365        return new WP_Error( 'bp_account_not_activated', __( '<strong>ERROR</strong>: Your account has not been activated. Check your email for the activation link.', 'buddypress' ) . $resend_string );
2366}
2367add_filter( 'authenticate', 'bp_core_signup_disable_inactive', 30, 3 );
2368
2369/**
2370 * On the login screen, resends the activation email for a user.
2371 *
2372 * @since 2.0.0
2373 *
2374 * @see bp_core_signup_disable_inactive()
2375 */
2376function bp_members_login_resend_activation_email() {
2377        global $error;
2378
2379        if ( empty( $_GET['id'] ) || empty( $_GET['_wpnonce'] ) ) {
2380                return;
2381        }
2382
2383        // Verify nonce.
2384        if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'bp-resend-activation' ) ) {
2385                die( 'Security check' );
2386        }
2387
2388        $signup_id = (int) $_GET['id'];
2389
2390        // Resend the activation email.
2391        // also updates the 'last sent' and '# of emails sent' values.
2392        $resend = BP_Signup::resend( array( $signup_id ) );
2393
2394        // Add feedback message.
2395        if ( ! empty( $resend['errors'] ) ) {
2396                $error = __( '<strong>ERROR</strong>: Your account has already been activated.', 'buddypress' );
2397        } else {
2398                $error = __( 'Activation email resent! Please check your inbox or spam folder.', 'buddypress' );
2399        }
2400}
2401add_action( 'login_form_bp-resend-activation', 'bp_members_login_resend_activation_email' );
2402
2403/**
2404 * Redirect away from wp-signup.php if BP registration templates are present.
2405 *
2406 * @since 1.1.0
2407 */
2408function bp_core_wpsignup_redirect() {
2409
2410        // Bail in admin or if custom signup page is broken.
2411        if ( is_admin() || ! bp_has_custom_signup_page() ) {
2412                return;
2413        }
2414
2415        $action = !empty( $_GET['action'] ) ? $_GET['action'] : '';
2416
2417        // Not at the WP core signup page and action is not register.
2418        if ( ! empty( $_SERVER['SCRIPT_NAME'] ) && false === strpos( 'wp-signup.php', $_SERVER['SCRIPT_NAME'] ) && ( 'register' != $action ) ) {
2419                return;
2420        }
2421
2422        bp_core_redirect( bp_get_signup_page() );
2423}
2424add_action( 'bp_init', 'bp_core_wpsignup_redirect' );
2425
2426/**
2427 * Stop a logged-in user who is marked as a spammer.
2428 *
2429 * When an admin marks a live user as a spammer, that user can still surf
2430 * around and cause havoc on the site until that person is logged out.
2431 *
2432 * This code checks to see if a logged-in user is marked as a spammer.  If so,
2433 * we redirect the user back to wp-login.php with the 'reauth' parameter.
2434 *
2435 * This clears the logged-in spammer's cookies and will ask the spammer to
2436 * reauthenticate.
2437 *
2438 * Note: A spammer cannot log back in - {@see bp_core_boot_spammer()}.
2439 *
2440 * Runs on 'bp_init' at priority 5 so the members component globals are setup
2441 * before we do our spammer checks.
2442 *
2443 * This is important as the $bp->loggedin_user object is setup at priority 4.
2444 *
2445 * @since 1.8.0
2446 */
2447function bp_stop_live_spammer() {
2448        // If we're on the login page, stop now to prevent redirect loop.
2449        $is_login = false;
2450        if ( isset( $GLOBALS['pagenow'] ) && ( false !== strpos( $GLOBALS['pagenow'], 'wp-login.php' ) ) ) {
2451                $is_login = true;
2452        } elseif ( isset( $_SERVER['SCRIPT_NAME'] ) && false !== strpos( $_SERVER['SCRIPT_NAME'], 'wp-login.php' ) ) {
2453                $is_login = true;
2454        }
2455
2456        if ( $is_login ) {
2457                return;
2458        }
2459
2460        // User isn't logged in, so stop!
2461        if ( ! is_user_logged_in() ) {
2462                return;
2463        }
2464
2465        // If spammer, redirect to wp-login.php and reauthorize.
2466        if ( bp_is_user_spammer( bp_loggedin_user_id() ) ) {
2467                // Setup login args.
2468                $args = array(
2469                        // Custom action used to throw an error message.
2470                        'action' => 'bp-spam',
2471
2472                        // Reauthorize user to login.
2473                        'reauth' => 1
2474                );
2475
2476                /**
2477                 * Filters the url used for redirection for a logged in user marked as spam.
2478                 *
2479                 * @since 1.8.0
2480                 *
2481                 * @param string $value URL to redirect user to.
2482                 */
2483                $login_url = apply_filters( 'bp_live_spammer_redirect', add_query_arg( $args, wp_login_url() ) );
2484
2485                // Redirect user to login page.
2486                wp_redirect( $login_url );
2487                die();
2488        }
2489}
2490add_action( 'bp_init', 'bp_stop_live_spammer', 5 );
2491
2492/**
2493 * Show a custom error message when a logged-in user is marked as a spammer.
2494 *
2495 * @since 1.8.0
2496 */
2497function bp_live_spammer_login_error() {
2498        global $error;
2499
2500        $error = __( '<strong>ERROR</strong>: Your account has been marked as a spammer.', 'buddypress' );
2501
2502        // Shake shake shake!
2503        add_action( 'login_head', 'wp_shake_js', 12 );
2504}
2505add_action( 'login_form_bp-spam', 'bp_live_spammer_login_error' );
2506
2507/**
2508 * Get the displayed user Object
2509 *
2510 * @since 2.6.0
2511 *
2512 * @return object The displayed user object, null otherwise.
2513 */
2514function bp_get_displayed_user() {
2515        $bp = buddypress();
2516
2517        $displayed_user = null;
2518        if ( ! empty( $bp->displayed_user->id ) ) {
2519                $displayed_user = $bp->displayed_user;
2520        }
2521
2522        /**
2523         * Filters the displayed_user object corresponding to the displayed member.
2524         *
2525         * @since 2.6.0
2526         *
2527         * @param object $displayed_user The displayed_user object.
2528         */
2529        return apply_filters( 'bp_get_displayed_user', $displayed_user );
2530}
2531
2532/** Member Types *************************************************************/
2533
2534/**
2535 * Output the slug of the member type taxonomy.
2536 *
2537 * @since 2.7.0
2538 */
2539function bp_member_type_tax_name() {
2540        echo bp_get_member_type_tax_name();
2541}
2542
2543        /**
2544         * Return the slug of the member type taxonomy.
2545         *
2546         * @since 2.7.0
2547         *
2548         * @return string The unique member taxonomy slug.
2549         */
2550        function bp_get_member_type_tax_name() {
2551                /**
2552                 * Filters the slug of the member type taxonomy.
2553                 *
2554                 * @since 2.7.0
2555                 *
2556                 * @param string $value Member type taxonomy slug.
2557                 */
2558                return apply_filters( 'bp_get_member_type_tax_name', 'bp_member_type' );
2559        }
2560
2561/**
2562 * Register a member type.
2563 *
2564 * @since 2.2.0
2565 *
2566 * @param string $member_type Unique string identifier for the member type.
2567 * @param array  $args {
2568 *     Array of arguments describing the member type.
2569 *
2570 *     @type array       $labels {
2571 *         Array of labels to use in various parts of the interface.
2572 *
2573 *         @type string $name          Default name. Should typically be plural.
2574 *         @type string $singular_name Singular name.
2575 *     }
2576 *     @type bool|string $has_directory Whether the member type should have its own type-specific directory.
2577 *                                      Pass `true` to use the `$member_type` string as the type's slug.
2578 *                                      Pass a string to customize the slug. Pass `false` to disable.
2579 *                                      Default: true.
2580 * }
2581 * @return object|WP_Error Member type object on success, WP_Error object on failure.
2582 */
2583function bp_register_member_type( $member_type, $args = array() ) {
2584        $bp = buddypress();
2585
2586        if ( isset( $bp->members->types[ $member_type ] ) ) {
2587                return new WP_Error( 'bp_member_type_exists', __( 'Member type already exists.', 'buddypress' ), $member_type );
2588        }
2589
2590        $r = bp_parse_args( $args, array(
2591                'labels'        => array(),
2592                'has_directory' => true,
2593        ), 'register_member_type' );
2594
2595        $member_type = sanitize_key( $member_type );
2596
2597        /**
2598         * Filters the list of illegal member type names.
2599         *
2600         * - 'any' is a special pseudo-type, representing items unassociated with any member type.
2601         * - 'null' is a special pseudo-type, representing users without any type.
2602         * - '_none' is used internally to denote an item that should not apply to any member types.
2603         *
2604         * @since 2.4.0
2605         *
2606         * @param array $illegal_names Array of illegal names.
2607         */
2608        $illegal_names = apply_filters( 'bp_member_type_illegal_names', array( 'any', 'null', '_none' ) );
2609        if ( in_array( $member_type, $illegal_names, true ) ) {
2610                return new WP_Error( 'bp_member_type_illegal_name', __( 'You may not register a member type with this name.', 'buddypress' ), $member_type );
2611        }
2612
2613        // Store the post type name as data in the object (not just as the array key).
2614        $r['name'] = $member_type;
2615
2616        // Make sure the relevant labels have been filled in.
2617        $default_name = isset( $r['labels']['name'] ) ? $r['labels']['name'] : ucfirst( $r['name'] );
2618        $r['labels'] = array_merge( array(
2619                'name'          => $default_name,
2620                'singular_name' => $default_name,
2621        ), $r['labels'] );
2622
2623        // Directory slug.
2624        if ( $r['has_directory'] ) {
2625                // A string value is intepreted as the directory slug. Otherwise fall back on member type.
2626                if ( is_string( $r['has_directory'] ) ) {
2627                        $directory_slug = $r['has_directory'];
2628                } else {
2629                        $directory_slug = $member_type;
2630                }
2631
2632                // Sanitize for use in URLs.
2633                $r['directory_slug'] = sanitize_title( $directory_slug );
2634                $r['has_directory']  = true;
2635        } else {
2636                $r['directory_slug'] = '';
2637                $r['has_directory']  = false;
2638        }
2639
2640        $bp->members->types[ $member_type ] = $type = (object) $r;
2641
2642        /**
2643         * Fires after a member type is registered.
2644         *
2645         * @since 2.2.0
2646         *
2647         * @param string $member_type Member type identifier.
2648         * @param object $type        Member type object.
2649         */
2650        do_action( 'bp_registered_member_type', $member_type, $type );
2651
2652        return $type;
2653}
2654
2655/**
2656 * Retrieve a member type object by name.
2657 *
2658 * @since 2.2.0
2659 *
2660 * @param string $member_type The name of the member type.
2661 * @return object A member type object.
2662 */
2663function bp_get_member_type_object( $member_type ) {
2664        $types = bp_get_member_types( array(), 'objects' );
2665
2666        if ( empty( $types[ $member_type ] ) ) {
2667                return null;
2668        }
2669
2670        return $types[ $member_type ];
2671}
2672
2673/**
2674 * Get a list of all registered member type objects.
2675 *
2676 * @since 2.2.0
2677 *
2678 * @see bp_register_member_type() for accepted arguments.
2679 *
2680 * @param array|string $args     Optional. An array of key => value arguments to match against
2681 *                               the member type objects. Default empty array.
2682 * @param string       $output   Optional. The type of output to return. Accepts 'names'
2683 *                               or 'objects'. Default 'names'.
2684 * @param string       $operator Optional. The logical operation to perform. 'or' means only one
2685 *                               element from the array needs to match; 'and' means all elements
2686 *                               must match. Accepts 'or' or 'and'. Default 'and'.
2687 * @return array A list of member type names or objects.
2688 */
2689function bp_get_member_types( $args = array(), $output = 'names', $operator = 'and' ) {
2690        $types = buddypress()->members->types;
2691
2692        $types = wp_filter_object_list( $types, $args, $operator );
2693
2694        /**
2695         * Filters the array of member type objects.
2696         *
2697         * This filter is run before the $output filter has been applied, so that
2698         * filtering functions have access to the entire member type objects.
2699         *
2700         * @since 2.2.0
2701         *
2702         * @param array  $types     Member type objects, keyed by name.
2703         * @param array  $args      Array of key=>value arguments for filtering.
2704         * @param string $operator  'or' to match any of $args, 'and' to require all.
2705         */
2706        $types = apply_filters( 'bp_get_member_types', $types, $args, $operator );
2707
2708        if ( 'names' === $output ) {
2709                $types = wp_list_pluck( $types, 'name' );
2710        }
2711
2712        return $types;
2713}
2714
2715/**
2716 * Set type for a member.
2717 *
2718 * @since 2.2.0
2719 *
2720 * @param int    $user_id     ID of the user.
2721 * @param string $member_type Member type.
2722 * @param bool   $append      Optional. True to append this to existing types for user,
2723 *                            false to replace. Default: false.
2724 * @return false|array $retval See {@see bp_set_object_terms()}.
2725 */
2726function bp_set_member_type( $user_id, $member_type, $append = false ) {
2727        // Pass an empty $member_type to remove a user's type.
2728        if ( ! empty( $member_type ) && ! bp_get_member_type_object( $member_type ) ) {
2729                return false;
2730        }
2731
2732        $retval = bp_set_object_terms( $user_id, $member_type, bp_get_member_type_tax_name(), $append );
2733
2734        // Bust the cache if the type has been updated.
2735        if ( ! is_wp_error( $retval ) ) {
2736                wp_cache_delete( $user_id, 'bp_member_member_type' );
2737
2738                /**
2739                 * Fires just after a user's member type has been changed.
2740                 *
2741                 * @since 2.2.0
2742                 *
2743                 * @param int    $user_id     ID of the user whose member type has been updated.
2744                 * @param string $member_type Member type.
2745                 * @param bool   $append      Whether the type is being appended to existing types.
2746                 */
2747                do_action( 'bp_set_member_type', $user_id, $member_type, $append );
2748        }
2749
2750        return $retval;
2751}
2752
2753/**
2754 * Remove type for a member.
2755 *
2756 * @since 2.3.0
2757 *
2758 * @param int    $user_id     ID of the user.
2759 * @param string $member_type Member Type.
2760 * @return bool|WP_Error
2761 */
2762function bp_remove_member_type( $user_id, $member_type ) {
2763        // Bail if no valid member type was passed.
2764        if ( empty( $member_type ) || ! bp_get_member_type_object( $member_type ) ) {
2765                return false;
2766        }
2767
2768        $deleted = bp_remove_object_terms( $user_id, $member_type, bp_get_member_type_tax_name() );
2769
2770        // Bust the cache if the type has been removed.
2771        if ( ! is_wp_error( $deleted ) ) {
2772                wp_cache_delete( $user_id, 'bp_member_member_type' );
2773
2774                /**
2775                 * Fires just after a user's member type has been removed.
2776                 *
2777                 * @since 2.3.0
2778                 *
2779                 * @param int    $user_id     ID of the user whose member type has been updated.
2780                 * @param string $member_type Member type.
2781                 */
2782                do_action( 'bp_remove_member_type', $user_id, $member_type );
2783        }
2784
2785        return $deleted;
2786}
2787
2788/**
2789 * Get type for a member.
2790 *
2791 * @since 2.2.0
2792 *
2793 * @param int  $user_id ID of the user.
2794 * @param bool $single  Optional. Whether to return a single type string. If multiple types are found
2795 *                      for the user, the oldest one will be returned. Default: true.
2796 * @return string|array|bool On success, returns a single member type (if $single is true) or an array of member
2797 *                           types (if $single is false). Returns false on failure.
2798 */
2799function bp_get_member_type( $user_id, $single = true ) {
2800        $types = wp_cache_get( $user_id, 'bp_member_member_type' );
2801
2802        if ( false === $types ) {
2803                $raw_types = bp_get_object_terms( $user_id, bp_get_member_type_tax_name() );
2804
2805                if ( ! is_wp_error( $raw_types ) ) {
2806                        $types =  array();
2807
2808                        // Only include currently registered group types.
2809                        foreach ( $raw_types as $mtype ) {
2810                                if ( bp_get_member_type_object( $mtype->name ) ) {
2811                                        $types[] = $mtype->name;
2812                                }
2813                        }
2814
2815                        wp_cache_set( $user_id, $types, 'bp_member_member_type' );
2816                }
2817        }
2818
2819        $type = false;
2820        if ( ! empty( $types ) ) {
2821                if ( $single ) {
2822                        $type = array_pop( $types );
2823                } else {
2824                        $type = $types;
2825                }
2826        }
2827
2828        /**
2829         * Filters a user's member type(s).
2830         *
2831         * @since 2.2.0
2832         *
2833         * @param string $type    Member type.
2834         * @param int    $user_id ID of the user.
2835         * @param bool   $single  Whether to return a single type string, or an array.
2836         */
2837        return apply_filters( 'bp_get_member_type', $type, $user_id, $single );
2838}
2839
2840/**
2841 * Check whether the given user has a certain member type.
2842 *
2843 * @since 2.3.0
2844 *
2845 * @param int    $user_id     $user_id ID of the user.
2846 * @param string $member_type Member Type.
2847 * @return bool Whether the user has the given member type.
2848 */
2849function bp_has_member_type( $user_id, $member_type ) {
2850        // Bail if no valid member type was passed.
2851        if ( empty( $member_type ) || ! bp_get_member_type_object( $member_type ) ) {
2852                return false;
2853        }
2854
2855        // Get all user's member types.
2856        $types = bp_get_member_type( $user_id, false );
2857
2858        if ( ! is_array( $types ) ) {
2859                return false;
2860        }
2861
2862        return in_array( $member_type, $types );
2863}
2864
2865/**
2866 * Delete a user's member type when the user when the user is deleted.
2867 *
2868 * @since 2.2.0
2869 *
2870 * @param int $user_id ID of the user.
2871 * @return false|array $value See {@see bp_set_member_type()}.
2872 */
2873function bp_remove_member_type_on_user_delete( $user_id ) {
2874        return bp_set_member_type( $user_id, '' );
2875}
2876add_action( 'wpmu_delete_user', 'bp_remove_member_type_on_user_delete' );
2877add_action( 'delete_user', 'bp_remove_member_type_on_user_delete' );
2878
2879/**
2880 * Get the "current" member type, if one is provided, in member directories.
2881 *
2882 * @since 2.3.0
2883 *
2884 * @return string
2885 */
2886function bp_get_current_member_type() {
2887
2888        /**
2889         * Filters the "current" member type, if one is provided, in member directories.
2890         *
2891         * @since 2.3.0
2892         *
2893         * @param string $value "Current" member type.
2894         */
2895        return apply_filters( 'bp_get_current_member_type', buddypress()->current_member_type );
2896}