[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
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. 13 defined( '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 */ 22 function 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 * 41 * @global BuddyPress $bp The one true BuddyPress instance. 42 */ 43 function bp_core_define_slugs() { 44 $bp = buddypress(); 45 46 // No custom members slug. 47 if ( !defined( 'BP_MEMBERS_SLUG' ) ) { 48 if ( !empty( $bp->pages->members ) ) { 49 define( 'BP_MEMBERS_SLUG', $bp->pages->members->slug ); 50 } else { 51 define( 'BP_MEMBERS_SLUG', 'members' ); 52 } 53 } 54 55 // No custom registration slug. 56 if ( !defined( 'BP_REGISTER_SLUG' ) ) { 57 if ( !empty( $bp->pages->register ) ) { 58 define( 'BP_REGISTER_SLUG', $bp->pages->register->slug ); 59 } else { 60 define( 'BP_REGISTER_SLUG', 'register' ); 61 } 62 } 63 64 // No custom activation slug. 65 if ( !defined( 'BP_ACTIVATION_SLUG' ) ) { 66 if ( !empty( $bp->pages->activate ) ) { 67 define( 'BP_ACTIVATION_SLUG', $bp->pages->activate->slug ); 68 } else { 69 define( 'BP_ACTIVATION_SLUG', 'activate' ); 70 } 71 } 72 } 73 add_action( 'bp_setup_globals', 'bp_core_define_slugs', 11 ); 74 75 /** 76 * Fetch an array of users based on the parameters passed. 77 * 78 * Since BuddyPress 1.7, bp_core_get_users() uses BP_User_Query. If you 79 * need backward compatibility with BP_Core_User::get_users(), filter the 80 * bp_use_legacy_user_query value, returning true. 81 * 82 * @since 1.2.0 83 * @since 7.0.0 Added `xprofile_query` parameter. Added `user_ids` parameter. 84 * 85 * @param array|string $args { 86 * Array of arguments. All are optional. See {@link BP_User_Query} for 87 * a more complete description of arguments. 88 * @type string $type Sort order. Default: 'active'. 89 * @type int $user_id Limit results to friends of a user. Default: false. 90 * @type mixed $exclude IDs to exclude from results. Default: false. 91 * @type string $search_terms Limit to users matching search terms. Default: false. 92 * @type string $meta_key Limit to users with a meta_key. Default: false. 93 * @type string $meta_value Limit to users with a meta_value (with meta_key). Default: false. 94 * @type array|string $member_type Array or comma-separated string of member types. 95 * @type array|string $member_type__in Array or comma-separated string of member types. 96 * `$member_type` takes precedence over this parameter. 97 * @type array|string $member_type__not_in Array or comma-separated string of member types to be excluded. 98 * @type mixed $include Limit results by user IDs. Default: false. 99 * @type mixed $user_ids IDs corresponding to the users. Default: false. 100 * @type int $per_page Results per page. Default: 20. 101 * @type int $page Page of results. Default: 1. 102 * @type bool $populate_extras Fetch optional extras. Default: true. 103 * @type array $xprofile_query Filter results by xprofile data. Requires the xprofile 104 * component. See {@see BP_XProfile_Query} for details. 105 * @type string|bool $count_total How to do total user count. Default: 'count_query'. 106 * } 107 * @return array 108 */ 109 function bp_core_get_users( $args = '' ) { 110 111 // Parse the user query arguments. 112 $r = bp_parse_args( 113 $args, 114 array( 115 'type' => 'active', // Active, newest, alphabetical, random or popular. 116 'user_id' => false, // Pass a user_id to limit to only friend connections for this user. 117 'exclude' => false, // Users to exclude from results. 118 'search_terms' => false, // Limit to users that match these search terms. 119 'meta_key' => false, // Limit to users who have this piece of usermeta. 120 'meta_value' => false, // With meta_key, limit to users where usermeta matches this value. 121 'member_type' => '', 122 'member_type__in' => '', 123 'member_type__not_in' => '', 124 'include' => false, // Pass comma separated list of user_ids to limit to only these users. 125 'user_ids' => false, 126 'per_page' => 20, // The number of results to return per page. 127 'page' => 1, // The page to return if limiting per page. 128 'populate_extras' => true, // Fetch the last active, where the user is a friend, total friend count, latest update. 129 'xprofile_query' => false, 130 'count_total' => 'count_query', // What kind of total user count to do, if any. 'count_query', 'sql_calc_found_rows', or false. 131 ), 132 'core_get_users' 133 ); 134 135 /** 136 * For legacy users. Use of BP_Core_User::get_users() is deprecated. 137 * 138 * Forcing this filter to true will use the legacy user query. As of 139 * BuddyPress 7.0.0, mirroring of the 'last_activity' value to usermeta 140 * is also disabled if true. See bp_update_user_last_activity(). 141 * 142 * @since 2.0.0 143 * 144 * @param bool $retval Defaults to false. 145 * @param string $function Current function name. 146 * @param array $r User query arguments. 147 */ 148 $use_legacy_query = apply_filters( 'bp_use_legacy_user_query', false, __FUNCTION__, $r ); 149 150 if ( $use_legacy_query ) { 151 $retval = BP_Core_User::get_users( 152 $r['type'], 153 $r['per_page'], 154 $r['page'], 155 $r['user_id'], 156 $r['include'], 157 $r['search_terms'], 158 $r['populate_extras'], 159 $r['exclude'], 160 $r['meta_key'], 161 $r['meta_value'] 162 ); 163 164 // Default behavior as of BuddyPress 1.7.0. 165 } else { 166 167 // Get users like we were asked to do... 168 $users = new BP_User_Query( $r ); 169 170 // ...but reformat the results to match bp_core_get_users() behavior. 171 $retval = array( 172 'users' => array_values( $users->results ), 173 'total' => $users->total_users 174 ); 175 } 176 177 /** 178 * Filters the results of the user query. 179 * 180 * @since 1.2.0 181 * 182 * @param array $retval Array of users for the current query. 183 * @param array $r Array of parsed query arguments. 184 */ 185 return apply_filters( 'bp_core_get_users', $retval, $r ); 186 } 187 188 /** 189 * Return the domain for the passed user: e.g. http://example.com/members/andy/. 190 * 191 * @since 1.0.0 192 * 193 * @param int $user_id The ID of the user. 194 * @param string|bool $user_nicename Optional. user_nicename of the user. 195 * @param string|bool $user_login Optional. user_login of the user. 196 * @return string 197 */ 198 function bp_core_get_user_domain( $user_id = 0, $user_nicename = false, $user_login = false ) { 199 200 if ( empty( $user_id ) ) { 201 return; 202 } 203 204 $username = bp_core_get_username( $user_id, $user_nicename, $user_login ); 205 206 if ( bp_is_username_compatibility_mode() ) { 207 $username = rawurlencode( $username ); 208 } 209 210 $after_domain = bp_core_enable_root_profiles() ? $username : bp_get_members_root_slug() . '/' . $username; 211 $domain = trailingslashit( bp_get_root_domain() . '/' . $after_domain ); 212 213 // Don't use this filter. Subject to removal in a future release. 214 // Use the 'bp_core_get_user_domain' filter instead. 215 $domain = apply_filters( 'bp_core_get_user_domain_pre_cache', $domain, $user_id, $user_nicename, $user_login ); 216 217 /** 218 * Filters the domain for the passed user. 219 * 220 * @since 1.0.1 221 * 222 * @param string $domain Domain for the passed user. 223 * @param int $user_id ID of the passed user. 224 * @param string $user_nicename User nicename of the passed user. 225 * @param string $user_login User login of the passed user. 226 */ 227 return apply_filters( 'bp_core_get_user_domain', $domain, $user_id, $user_nicename, $user_login ); 228 } 229 230 /** 231 * Fetch everything in the wp_users table for a user, without any usermeta. 232 * 233 * @since 1.2.0 234 * 235 * @param int $user_id The ID of the user. 236 * @return array|bool Array of data on success, false on failure. 237 */ 238 function bp_core_get_core_userdata( $user_id = 0 ) { 239 if ( empty( $user_id ) ) { 240 return false; 241 } 242 243 // Get core user data. 244 $userdata = BP_Core_User::get_core_userdata( $user_id ); 245 246 /** 247 * Filters the userdata for a passed user. 248 * 249 * @since 1.2.0 250 * 251 * @param array|bool $userdata Array of user data for a passed user on success, false on failure. 252 */ 253 return apply_filters( 'bp_core_get_core_userdata', $userdata ); 254 } 255 256 /** 257 * Return the ID of a user, based on user_login. 258 * 259 * No longer used. 260 * 261 * @todo Deprecate. 262 * 263 * @param string $user_login user_login of the user being queried. 264 * @return int 265 */ 266 function bp_core_get_displayed_userid( $user_login ) { 267 return apply_filters( 'bp_core_get_displayed_userid', bp_core_get_userid( $user_login ) ); 268 } 269 270 /** 271 * Return the user ID based on a user's user_login. 272 * 273 * @since 1.0.0 274 * 275 * @param string $username user_login to check. 276 * @return int|null The ID of the matched user on success, null on failure. 277 */ 278 function bp_core_get_userid( $username = '' ) { 279 if ( empty( $username ) ) { 280 return false; 281 } 282 283 $user = get_user_by( 'login', $username ); 284 285 /** 286 * Filters the ID of a user, based on user_login. 287 * 288 * @since 1.0.1 289 * 290 * @param int|null $value ID of the user or null. 291 * @param string $username User login to check. 292 */ 293 return apply_filters( 'bp_core_get_userid', ! empty( $user->ID ) ? $user->ID : null, $username ); 294 } 295 296 /** 297 * Return the user ID based on a user's user_nicename. 298 * 299 * @since 1.2.3 300 * 301 * @param string $user_nicename user_nicename to check. 302 * @return int|null The ID of the matched user on success, null on failure. 303 */ 304 function bp_core_get_userid_from_nicename( $user_nicename = '' ) { 305 if ( empty( $user_nicename ) ) { 306 return false; 307 } 308 309 $user = get_user_by( 'slug', $user_nicename ); 310 311 /** 312 * Filters the user ID based on user_nicename. 313 * 314 * @since 1.2.3 315 * 316 * @param int|null $value ID of the user or null. 317 * @param string $user_nicename User nicename to check. 318 */ 319 return apply_filters( 'bp_core_get_userid_from_nicename', ! empty( $user->ID ) ? $user->ID : null, $user_nicename ); 320 } 321 322 /** 323 * Return the username for a user based on their user id. 324 * 325 * This function is sensitive to the BP_ENABLE_USERNAME_COMPATIBILITY_MODE, 326 * so it will return the user_login or user_nicename as appropriate. 327 * 328 * @since 1.0.0 329 * 330 * @param int $user_id User ID to check. 331 * @param string|bool $user_nicename Optional. user_nicename of user being checked. 332 * @param string|bool $user_login Optional. user_login of user being checked. 333 * @return string The username of the matched user or an empty string if no user is found. 334 */ 335 function bp_core_get_username( $user_id = 0, $user_nicename = false, $user_login = false ) { 336 337 if ( ! $user_nicename && ! $user_login ) { 338 // Pull an audible and maybe use the login over the nicename. 339 if ( bp_is_username_compatibility_mode() ) { 340 $username = get_the_author_meta( 'login', $user_id ); 341 } else { 342 $username = get_the_author_meta( 'nicename', $user_id ); 343 } 344 } else { 345 $username = bp_is_username_compatibility_mode() ? $user_login : $user_nicename; 346 } 347 348 /** 349 * Filters the username based on originally provided user ID. 350 * 351 * @since 1.0.1 352 * 353 * @param string $username Username determined by user ID. 354 */ 355 return apply_filters( 'bp_core_get_username', $username ); 356 } 357 358 /** 359 * Return the user_nicename for a user based on their user_id. 360 * 361 * This should be used for linking to user profiles and anywhere else a 362 * sanitized and unique slug to a user is needed. 363 * 364 * @since 1.5.0 365 * 366 * @param int $user_id User ID to check. 367 * @return string The username of the matched user or an empty string if no user is found. 368 */ 369 function bp_members_get_user_nicename( $user_id ) { 370 371 /** 372 * Filters the user_nicename based on originally provided user ID. 373 * 374 * @since 1.5.0 375 * 376 * @param string $username User nice name determined by user ID. 377 */ 378 return apply_filters( 'bp_members_get_user_nicename', get_the_author_meta( 'nicename', $user_id ) ); 379 } 380 381 /** 382 * Return the email address for the user based on user ID. 383 * 384 * @since 1.0.0 385 * 386 * @param int $user_id User ID to check. 387 * @return string The email for the matched user. Empty string if no user 388 * matches the $user_id. 389 */ 390 function bp_core_get_user_email( $user_id ) { 391 392 /** 393 * Filters the user email for user based on user ID. 394 * 395 * @since 1.0.1 396 * 397 * @param string $email Email determined for the user. 398 */ 399 return apply_filters( 'bp_core_get_user_email', get_the_author_meta( 'email', $user_id ) ); 400 } 401 402 /** 403 * Return a HTML formatted link for a user with the user's full name as the link text. 404 * 405 * Eg: <a href="http://andy.example.com/">Andy Peatling</a> 406 * 407 * Optional parameters will return just the name or just the URL. 408 * 409 * @since 1.0.0 410 * 411 * @param int $user_id User ID to check. 412 * @param bool $no_anchor Disable URL and HTML and just return full name. 413 * Default: false. 414 * @param bool $just_link Disable full name and HTML and just return the URL 415 * text. Default false. 416 * @return string|bool The link text based on passed parameters, or false on 417 * no match. 418 */ 419 function bp_core_get_userlink( $user_id, $no_anchor = false, $just_link = false ) { 420 $display_name = bp_core_get_user_displayname( $user_id ); 421 422 if ( empty( $display_name ) ) { 423 return false; 424 } 425 426 if ( ! empty( $no_anchor ) ) { 427 return $display_name; 428 } 429 430 if ( !$url = bp_core_get_user_domain( $user_id ) ) { 431 return false; 432 } 433 434 if ( ! empty( $just_link ) ) { 435 return $url; 436 } 437 438 /** 439 * Filters the link text for the passed in user. 440 * 441 * @since 1.2.0 442 * 443 * @param string $value Link text based on passed parameters. 444 * @param int $user_id ID of the user to check. 445 */ 446 return apply_filters( 'bp_core_get_userlink', '<a href="' . esc_url( $url ) . '">' . $display_name . '</a>', $user_id ); 447 } 448 449 /** 450 * Fetch the display name for a group of users. 451 * 452 * Uses the 'Name' field in xprofile if available. Falls back on WP 453 * display_name, and then user_nicename. 454 * 455 * @since 2.0.0 456 * 457 * @param array $user_ids Array of user IDs to get display names for. 458 * @return array Associative array of the format "id" => "displayname". 459 */ 460 function bp_core_get_user_displaynames( $user_ids ) { 461 462 // Sanitize. 463 $user_ids = wp_parse_id_list( $user_ids ); 464 465 // Remove dupes and empties. 466 $user_ids = array_unique( array_filter( $user_ids ) ); 467 468 if ( empty( $user_ids ) ) { 469 return array(); 470 } 471 472 // Warm the WP users cache with a targeted bulk update. 473 cache_users( $user_ids ); 474 475 $retval = array(); 476 foreach ( $user_ids as $user_id ) { 477 $retval[ $user_id ] = bp_core_get_user_displayname( $user_id ); 478 } 479 480 return $retval; 481 } 482 483 /** 484 * Fetch the display name for a user. 485 * 486 * @since 1.0.1 487 * 488 * @param int|string|bool $user_id_or_username User ID or username. 489 * @return string|bool The display name for the user in question, or false if 490 * user not found. 491 */ 492 function bp_core_get_user_displayname( $user_id_or_username ) { 493 if ( empty( $user_id_or_username ) ) { 494 return false; 495 } 496 497 if ( ! is_numeric( $user_id_or_username ) ) { 498 $user_id = bp_core_get_userid( $user_id_or_username ); 499 } else { 500 $user_id = $user_id_or_username; 501 } 502 503 if ( empty( $user_id ) ) { 504 return false; 505 } 506 507 /** 508 * Filters the display name for the passed in user. 509 * 510 * @since 1.0.1 511 * 512 * @param string $fullname Display name for the user. 513 * @param int $user_id ID of the user to check. 514 */ 515 return apply_filters( 'bp_core_get_user_displayname', get_the_author_meta( 'display_name', $user_id ), $user_id ); 516 } 517 add_filter( 'bp_core_get_user_displayname', 'strip_tags', 1 ); 518 add_filter( 'bp_core_get_user_displayname', 'trim' ); 519 add_filter( 'bp_core_get_user_displayname', 'stripslashes' ); 520 add_filter( 'bp_core_get_user_displayname', 'esc_html' ); 521 522 /** 523 * Return the user link for the user based on user email address. 524 * 525 * @since 1.0.0 526 * 527 * @param string $email The email address for the user. 528 * @return string The link to the users home base. False on no match. 529 */ 530 function bp_core_get_userlink_by_email( $email ) { 531 $user = get_user_by( 'email', $email ); 532 533 /** 534 * Filters the user link for the user based on user email address. 535 * 536 * @since 1.0.1 537 * 538 * @param string|bool $value URL for the user if found, otherwise false. 539 */ 540 return apply_filters( 'bp_core_get_userlink_by_email', bp_core_get_userlink( $user->ID, false, false, true ) ); 541 } 542 543 /** 544 * Return the user link for the user based on the supplied identifier. 545 * 546 * @since 1.0.0 547 * 548 * @param string $username If BP_ENABLE_USERNAME_COMPATIBILITY_MODE is set, 549 * this should be user_login, otherwise it should 550 * be user_nicename. 551 * @return string|bool The link to the user's domain, false on no match. 552 */ 553 function bp_core_get_userlink_by_username( $username ) { 554 if ( bp_is_username_compatibility_mode() ) { 555 $user_id = bp_core_get_userid( $username ); 556 } else { 557 $user_id = bp_core_get_userid_from_nicename( $username ); 558 } 559 560 /** 561 * Filters the user link for the user based on username. 562 * 563 * @since 1.0.1 564 * 565 * @param string|bool $value URL for the user if found, otherwise false. 566 */ 567 return apply_filters( 'bp_core_get_userlink_by_username', bp_core_get_userlink( $user_id, false, false, true ) ); 568 } 569 570 /** 571 * Return the total number of members for the installation. 572 * 573 * Note that this is a raw count of non-spam, activated users. It does not 574 * account for users who have logged activity (last_active). See 575 * {@link bp_core_get_active_member_count()}. 576 * 577 * @since 1.2.0 578 * 579 * @global wpdb $wpdb WordPress database object. 580 * 581 * @return int The total number of members. 582 */ 583 function bp_core_get_total_member_count() { 584 global $wpdb; 585 586 $count = wp_cache_get( 'bp_total_member_count', 'bp' ); 587 588 if ( false === $count ) { 589 $status_sql = bp_core_get_status_sql(); 590 $count = $wpdb->get_var( "SELECT COUNT(ID) FROM {$wpdb->users} WHERE {$status_sql}" ); 591 wp_cache_set( 'bp_total_member_count', $count, 'bp' ); 592 } 593 594 /** 595 * Filters the total number of members for the installation. 596 * 597 * @since 1.2.0 598 * 599 * @param int $count Total number of members. 600 */ 601 return apply_filters( 'bp_core_get_total_member_count', $count ); 602 } 603 604 /** 605 * Return the total number of members, limited to those members with last_activity. 606 * 607 * @since 1.6.0 608 * 609 * @global wpdb $wpdb WordPress database object. 610 * 611 * @return int The number of active members. 612 */ 613 function bp_core_get_active_member_count() { 614 global $wpdb; 615 616 $count = get_transient( 'bp_active_member_count' ); 617 if ( false === $count ) { 618 $bp = buddypress(); 619 620 // Avoid a costly join by splitting the lookup. 621 if ( is_multisite() ) { 622 $sql = "SELECT ID FROM {$wpdb->users} WHERE (user_status != 0 OR deleted != 0 OR user_status != 0)"; 623 } else { 624 $sql = "SELECT ID FROM {$wpdb->users} WHERE user_status != 0"; 625 } 626 627 $exclude_users = $wpdb->get_col( $sql ); 628 $exclude_users_sql = !empty( $exclude_users ) ? "AND user_id NOT IN (" . implode( ',', wp_parse_id_list( $exclude_users ) ) . ")" : ''; 629 $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 ) ); 630 631 set_transient( 'bp_active_member_count', $count ); 632 } 633 634 /** 635 * Filters the total number of members for the installation limited to those with last_activity. 636 * 637 * @since 1.6.0 638 * 639 * @param int $count Total number of active members. 640 */ 641 return apply_filters( 'bp_core_get_active_member_count', $count ); 642 } 643 644 /** 645 * Update the spam status of the member on multisite configs. 646 * 647 * @since 5.0.0 648 * 649 * @param int $user_id The user ID to spam or ham. 650 * @param int $value 0 to mark the user as `ham`, 1 to mark as `spam`. 651 * @return bool True if the spam status of the member changed. 652 * False otherwise. 653 */ 654 function bp_core_update_member_status( $user_id = 0, $value = 0 ) { 655 if ( ! is_multisite() || ! $user_id ) { 656 return false; 657 } 658 659 /** 660 * The `update_user_status()` function is deprecated since WordPress 5.3.0. 661 * Continue to use it if WordPress current major version is lower than 5.3. 662 */ 663 if ( bp_get_major_wp_version() < 5.3 ) { 664 return update_user_status( $user_id, 'spam', $value ); 665 } 666 667 // Otherwise use the replacement function. 668 $user = wp_update_user( array( 669 'ID' => $user_id, 670 'spam' => $value, 671 ) ); 672 673 if ( is_wp_error( $user ) ) { 674 return false; 675 } 676 677 return true; 678 } 679 680 /** 681 * Process a spammed or unspammed user. 682 * 683 * This function is called from three places: 684 * 685 * - in bp_settings_action_capabilities() (from the front-end) 686 * - by bp_core_mark_user_spam_admin() (from wp-admin) 687 * - bp_core_mark_user_ham_admin() (from wp-admin) 688 * 689 * @since 1.6.0 690 * 691 * @global wpdb $wpdb WordPress database object. 692 * 693 * @param int $user_id The ID of the user being spammed/hammed. 694 * @param string $status 'spam' if being marked as spam, 'ham' otherwise. 695 * @param bool $do_wp_cleanup Optional. True to force the cleanup of WordPress content 696 * and status, otherwise false. Generally, this should 697 * only be false if WordPress is expected to have 698 * performed this cleanup independently, as when hooked 699 * to 'make_spam_user'. 700 * @return bool True on success, false on failure. 701 */ 702 function bp_core_process_spammer_status( $user_id, $status, $do_wp_cleanup = true ) { 703 global $wpdb; 704 705 // Bail if no user ID. 706 if ( empty( $user_id ) ) { 707 return; 708 } 709 710 // Bail if user ID is super admin. 711 if ( is_super_admin( $user_id ) ) { 712 return; 713 } 714 715 // Get the functions file. 716 if ( is_multisite() ) { 717 require_once( ABSPATH . 'wp-admin/includes/ms.php' ); 718 } 719 720 $is_spam = ( 'spam' == $status ); 721 722 // Only you can prevent infinite loops. 723 remove_action( 'make_spam_user', 'bp_core_mark_user_spam_admin' ); 724 remove_action( 'make_ham_user', 'bp_core_mark_user_ham_admin' ); 725 726 // Force the cleanup of WordPress content and status for multisite configs. 727 if ( $do_wp_cleanup ) { 728 729 // Mark blogs as spam if the user is the sole admin of a site. 730 if ( is_multisite() ) { 731 /* 732 * No native function to fetch a user's blogs by role, so do it manually. 733 * 734 * This logic is mostly copied from get_blogs_of_user(). 735 */ 736 $meta = get_user_meta( $user_id ); 737 738 foreach ( $meta as $key => $val ) { 739 if ( 'capabilities' !== substr( $key, -12 ) ) { 740 continue; 741 } 742 if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) ) { 743 continue; 744 } 745 $site_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key ); 746 if ( ! is_numeric( $site_id ) ) { 747 continue; 748 } 749 750 $site_id = (int) $site_id; 751 752 // Do not mark the main or current root blog as spam. 753 if ( 1 === $site_id || bp_get_root_blog_id() === $site_id ) { 754 continue; 755 } 756 757 // Now, do check for administrator role. 758 $role = maybe_unserialize( $val ); 759 if ( empty( $role['administrator'] ) ) { 760 continue; 761 } 762 763 // Check if the site has more than 1 admin. If so, bail. 764 $counts = count_users( 'time', $site_id ); 765 if ( empty( $counts['avail_roles']['administrator'] ) || $counts['avail_roles']['administrator'] > 1 ) { 766 continue; 767 } 768 769 // Now we can spam the blog. 770 update_blog_status( $site_id, 'spam', $is_spam ); 771 } 772 } 773 774 // Finally, mark this user as a spammer. 775 bp_core_update_member_status( $user_id, $is_spam ); 776 } 777 778 // Update the user status. 779 $wpdb->update( $wpdb->users, array( 'user_status' => $is_spam ), array( 'ID' => $user_id ) ); 780 781 // Clean user cache. 782 clean_user_cache( $user_id ); 783 784 if ( ! is_multisite() ) { 785 // Call multisite actions in single site mode for good measure. 786 if ( true === $is_spam ) { 787 788 /** 789 * Fires at end of processing spammer in Dashboard if not multisite and user is spam. 790 * 791 * @since 1.5.0 792 * 793 * @param int $value user ID. 794 */ 795 do_action( 'make_spam_user', $user_id ); 796 } else { 797 798 /** 799 * Fires at end of processing spammer in Dashboard if not multisite and user is not spam. 800 * 801 * @since 1.5.0 802 * 803 * @param int $value user ID. 804 */ 805 do_action( 'make_ham_user', $user_id ); 806 } 807 } 808 809 // Hide this user's activity. 810 if ( ( true === $is_spam ) && bp_is_active( 'activity' ) ) { 811 bp_activity_hide_user_activity( $user_id ); 812 } 813 814 // We need a special hook for is_spam so that components can delete data at spam time. 815 if ( true === $is_spam ) { 816 817 /** 818 * Fires at the end of the process spammer process if the user is spam. 819 * 820 * @since 1.5.0 821 * 822 * @param int $value Displayed user ID. 823 */ 824 do_action( 'bp_make_spam_user', $user_id ); 825 } else { 826 827 /** 828 * Fires at the end of the process spammer process if the user is not spam. 829 * 830 * @since 1.5.0 831 * 832 * @param int $value Displayed user ID. 833 */ 834 do_action( 'bp_make_ham_user', $user_id ); 835 } 836 837 /** 838 * Fires at the end of the process for hanlding spammer status. 839 * 840 * @since 1.5.5 841 * 842 * @param int $user_id ID of the processed user. 843 * @param bool $is_spam The determined spam status of processed user. 844 */ 845 do_action( 'bp_core_process_spammer_status', $user_id, $is_spam ); 846 847 // Put things back how we found them. 848 add_action( 'make_spam_user', 'bp_core_mark_user_spam_admin' ); 849 add_action( 'make_ham_user', 'bp_core_mark_user_ham_admin' ); 850 851 return true; 852 } 853 /** 854 * Hook to WP's make_spam_user and run our custom BP spam functions. 855 * 856 * @since 1.6.0 857 * 858 * @param int $user_id The user ID passed from the make_spam_user hook. 859 */ 860 function bp_core_mark_user_spam_admin( $user_id ) { 861 bp_core_process_spammer_status( $user_id, 'spam', false ); 862 } 863 add_action( 'make_spam_user', 'bp_core_mark_user_spam_admin' ); 864 865 /** 866 * Hook to WP's make_ham_user and run our custom BP spam functions. 867 * 868 * @since 1.6.0 869 * 870 * @param int $user_id The user ID passed from the make_ham_user hook. 871 */ 872 function bp_core_mark_user_ham_admin( $user_id ) { 873 bp_core_process_spammer_status( $user_id, 'ham', false ); 874 } 875 add_action( 'make_ham_user', 'bp_core_mark_user_ham_admin' ); 876 877 /** 878 * Check whether a user has been marked as a spammer. 879 * 880 * @since 1.6.0 881 * 882 * @global BuddyPress $bp The one true BuddyPress instance. 883 * 884 * @param int $user_id The ID for the user. 885 * @return bool True if spammer, otherwise false. 886 */ 887 function bp_is_user_spammer( $user_id = 0 ) { 888 889 // No user to check. 890 if ( empty( $user_id ) ) { 891 return false; 892 } 893 894 $bp = buddypress(); 895 896 // Assume user is not spam. 897 $is_spammer = false; 898 899 // Setup our user. 900 $user = false; 901 902 // Get locally-cached data if available. 903 switch ( $user_id ) { 904 case bp_loggedin_user_id() : 905 $user = ! empty( $bp->loggedin_user->userdata ) ? $bp->loggedin_user->userdata : false; 906 break; 907 908 case bp_displayed_user_id() : 909 $user = ! empty( $bp->displayed_user->userdata ) ? $bp->displayed_user->userdata : false; 910 break; 911 912 case bp_get_member_user_id() : 913 global $members_template; 914 $user = isset( $members_template ) && isset( $members_template->member ) ? $members_template->member : false; 915 break; 916 } 917 918 // Manually get userdata if still empty. 919 if ( empty( $user ) ) { 920 $user = get_userdata( $user_id ); 921 } 922 923 // No user found. 924 if ( empty( $user ) ) { 925 $is_spammer = false; 926 927 // User found. 928 } else { 929 930 // Check if spam. 931 if ( !empty( $user->spam ) ) { 932 $is_spammer = true; 933 } 934 935 if ( 1 == $user->user_status ) { 936 $is_spammer = true; 937 } 938 } 939 940 /** 941 * Filters whether a user is marked as a spammer. 942 * 943 * @since 1.6.0 944 * 945 * @param bool $is_spammer Whether or not user is marked as spammer. 946 * @param \WP_User $user The user to which we are acting on. 947 */ 948 return apply_filters( 'bp_is_user_spammer', (bool) $is_spammer, $user ); 949 } 950 951 /** 952 * Check whether a user has been marked as deleted. 953 * 954 * @since 1.6.0 955 * 956 * @global BuddyPress $bp The one true BuddyPress instance. 957 * 958 * @param int $user_id The ID for the user. 959 * @return bool True if deleted, otherwise false. 960 */ 961 function bp_is_user_deleted( $user_id = 0 ) { 962 963 // No user to check. 964 if ( empty( $user_id ) ) { 965 return false; 966 } 967 968 $bp = buddypress(); 969 970 // Assume user is not deleted. 971 $is_deleted = false; 972 973 // Setup our user. 974 $user = false; 975 976 // Get locally-cached data if available. 977 switch ( $user_id ) { 978 case bp_loggedin_user_id() : 979 $user = ! empty( $bp->loggedin_user->userdata ) ? $bp->loggedin_user->userdata : false; 980 break; 981 982 case bp_displayed_user_id() : 983 $user = ! empty( $bp->displayed_user->userdata ) ? $bp->displayed_user->userdata : false; 984 break; 985 } 986 987 // Manually get userdata if still empty. 988 if ( empty( $user ) ) { 989 $user = get_userdata( $user_id ); 990 } 991 992 // No user found. 993 if ( empty( $user ) ) { 994 $is_deleted = true; 995 996 // User found. 997 } else { 998 999 // Check if deleted. 1000 if ( !empty( $user->deleted ) ) { 1001 $is_deleted = true; 1002 } 1003 1004 if ( 2 == $user->user_status ) { 1005 $is_deleted = true; 1006 } 1007 } 1008 1009 /** 1010 * Filters whether a user is marked as deleted. 1011 * 1012 * @since 1.6.0 1013 * 1014 * @param bool $is_deleted Whether or not user is marked as deleted. 1015 * @param \WP_User $user The user to which we are acting on. 1016 */ 1017 return apply_filters( 'bp_is_user_deleted', (bool) $is_deleted, $user ); 1018 } 1019 1020 /** 1021 * Check whether a user is "active", ie neither deleted nor spammer. 1022 * 1023 * @since 1.6.0 1024 * 1025 * @param int $user_id Optional. The user ID to check. 1026 * @return bool True if active, otherwise false. 1027 */ 1028 function bp_is_user_active( $user_id = 0 ) { 1029 1030 // Default to current user. 1031 if ( empty( $user_id ) && is_user_logged_in() ) { 1032 $user_id = bp_loggedin_user_id(); 1033 } 1034 1035 // No user to check. 1036 if ( empty( $user_id ) ) { 1037 return false; 1038 } 1039 1040 // Check spam. 1041 if ( bp_is_user_spammer( $user_id ) ) { 1042 return false; 1043 } 1044 1045 // Check deleted. 1046 if ( bp_is_user_deleted( $user_id ) ) { 1047 return false; 1048 } 1049 1050 // Assume true if not spam or deleted. 1051 return true; 1052 } 1053 1054 /** 1055 * Check whether user is not active. 1056 * 1057 * @since 1.6.0 1058 * 1059 * @param int $user_id Optional. The user ID to check. 1060 * @return bool True if inactive, otherwise false. 1061 */ 1062 function bp_is_user_inactive( $user_id = 0 ) { 1063 // Return the inverse of active. 1064 return ! bp_is_user_active( $user_id ); 1065 } 1066 1067 /** 1068 * Update a user's last activity. 1069 * 1070 * @since 1.9.0 1071 * @since 7.0.0 Backward compatibility usermeta mirroring is only allowed if the 1072 * legacy user query is enabled. 1073 * 1074 * @param int $user_id Optional. ID of the user being updated. 1075 * @param string $time Optional. Time of last activity, in 'Y-m-d H:i:s' format. 1076 * @return bool True on success, false on failure. 1077 */ 1078 function bp_update_user_last_activity( $user_id = 0, $time = '' ) { 1079 1080 // Fall back on current user. 1081 if ( empty( $user_id ) ) { 1082 $user_id = bp_loggedin_user_id(); 1083 } 1084 1085 // Bail if the user id is 0, as there's nothing to update. 1086 if ( empty( $user_id ) ) { 1087 return false; 1088 } 1089 1090 // Fall back on current time. 1091 if ( empty( $time ) ) { 1092 $time = bp_core_current_time(); 1093 } 1094 1095 /** This filter is documented in bp_core_get_users() */ 1096 $use_legacy_query = apply_filters( 'bp_use_legacy_user_query', false, __FUNCTION__, [ 'user_id' => $user_id ] ); 1097 1098 /* 1099 * As of BuddyPress 2.0, last_activity is no longer stored in usermeta. 1100 * However, we mirror it there for backward compatibility. Do not use! 1101 * 1102 * As of BuddyPress 7.0, mirroring is only allowed if the legacy user 1103 * query is enabled. 1104 */ 1105 if ( $use_legacy_query ) { 1106 remove_filter( 'update_user_metadata', '_bp_update_user_meta_last_activity_warning', 10 ); 1107 remove_filter( 'get_user_metadata', '_bp_get_user_meta_last_activity_warning', 10 ); 1108 bp_update_user_meta( $user_id, 'last_activity', $time ); 1109 add_filter( 'update_user_metadata', '_bp_update_user_meta_last_activity_warning', 10, 4 ); 1110 add_filter( 'get_user_metadata', '_bp_get_user_meta_last_activity_warning', 10, 4 ); 1111 } 1112 1113 return BP_Core_User::update_last_activity( $user_id, $time ); 1114 } 1115 1116 /** 1117 * Backward compatibility for 'last_activity' usermeta fetching. 1118 * 1119 * In BuddyPress 2.0, user last_activity data was moved out of usermeta. For 1120 * backward compatibility, we continue to mirror the data there. This function 1121 * serves two purposes: it warns plugin authors of the change, and it returns 1122 * the data from the proper location. 1123 * 1124 * @since 2.0.0 1125 * @since 2.9.3 Added the `$single` parameter. 1126 * 1127 * @access private For internal use only. 1128 * 1129 * @param null $retval Null retval value. 1130 * @param int $object_id ID of the user. 1131 * @param string $meta_key Meta key being fetched. 1132 * @param bool $single Whether a single key is being fetched (vs an array). 1133 * @return string|null 1134 */ 1135 function _bp_get_user_meta_last_activity_warning( $retval, $object_id, $meta_key, $single ) { 1136 static $warned = false; 1137 1138 if ( 'last_activity' === $meta_key ) { 1139 // Don't send the warning more than once per pageload. 1140 if ( false === $warned ) { 1141 _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' ); 1142 $warned = true; 1143 } 1144 1145 $user_last_activity = bp_get_user_last_activity( $object_id ); 1146 if ( $single ) { 1147 return $user_last_activity; 1148 } else { 1149 return array( $user_last_activity ); 1150 } 1151 } 1152 1153 return $retval; 1154 } 1155 add_filter( 'get_user_metadata', '_bp_get_user_meta_last_activity_warning', 10, 4 ); 1156 1157 /** 1158 * Backward compatibility for 'last_activity' usermeta setting. 1159 * 1160 * In BuddyPress 2.0, user last_activity data was moved out of usermeta. For 1161 * backward compatibility, we continue to mirror the data there. This function 1162 * serves two purposes: it warns plugin authors of the change, and it updates 1163 * the data in the proper location. 1164 * 1165 * @since 2.0.0 1166 * 1167 * @access private For internal use only. 1168 * 1169 * @param int $meta_id ID of the just-set usermeta row. 1170 * @param int $object_id ID of the user. 1171 * @param string $meta_key Meta key being fetched. 1172 * @param string $meta_value Active time. 1173 */ 1174 function _bp_update_user_meta_last_activity_warning( $meta_id, $object_id, $meta_key, $meta_value ) { 1175 if ( 'last_activity' === $meta_key ) { 1176 _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' ); 1177 bp_update_user_last_activity( $object_id, $meta_value ); 1178 } 1179 } 1180 add_filter( 'update_user_metadata', '_bp_update_user_meta_last_activity_warning', 10, 4 ); 1181 1182 /** 1183 * Get the last activity for a given user. 1184 * 1185 * @since 1.9.0 1186 * 1187 * @param int $user_id The ID of the user. 1188 * @return string Time of last activity, in 'Y-m-d H:i:s' format, or an empty 1189 * string if none is found. 1190 */ 1191 function bp_get_user_last_activity( $user_id = 0 ) { 1192 $activity = ''; 1193 1194 $last_activity = BP_Core_User::get_last_activity( $user_id ); 1195 if ( ! empty( $last_activity[ $user_id ] ) ) { 1196 $activity = $last_activity[ $user_id ]['date_recorded']; 1197 } 1198 1199 /** 1200 * Filters the last activity for a given user. 1201 * 1202 * @since 1.9.0 1203 * 1204 * @param string $activity Time of last activity, in 'Y-m-d H:i:s' format or 1205 * an empty string if none found. 1206 * @param int $user_id ID of the user being checked. 1207 */ 1208 return apply_filters( 'bp_get_user_last_activity', $activity, $user_id ); 1209 } 1210 1211 /** 1212 * Migrate last_activity data from the usermeta table to the activity table. 1213 * 1214 * Generally, this function is only run when BP is upgraded to 2.0. It can also 1215 * be called directly from the BuddyPress Tools panel. 1216 * 1217 * @since 2.0.0 1218 * 1219 * @global BuddyPress $bp The one true BuddyPress instance. 1220 * @global wpdb $wpdb WordPress database object. 1221 * 1222 * @return bool 1223 */ 1224 function bp_last_activity_migrate() { 1225 global $wpdb; 1226 1227 $bp = buddypress(); 1228 1229 // Wipe out existing last_activity data in the activity table - 1230 // this helps to prevent duplicates when pulling from the usermeta 1231 // table. 1232 $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->members->table_name_last_activity} WHERE component = %s AND type = 'last_activity'", $bp->members->id ) ); 1233 1234 $sql = "INSERT INTO {$bp->members->table_name_last_activity} (`user_id`, `component`, `type`, `action`, `content`, `primary_link`, `item_id`, `date_recorded` ) ( 1235 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 1236 FROM {$wpdb->usermeta} 1237 WHERE 1238 meta_key = 'last_activity' 1239 );"; 1240 1241 return $wpdb->query( $sql ); 1242 } 1243 1244 /** 1245 * Fetch every post that is authored by the given user for the current blog. 1246 * 1247 * No longer used in BuddyPress. 1248 * 1249 * @todo Deprecate. 1250 * 1251 * @param int $user_id ID of the user being queried. 1252 * @return array Post IDs. 1253 */ 1254 function bp_core_get_all_posts_for_user( $user_id = 0 ) { 1255 global $wpdb; 1256 1257 if ( empty( $user_id ) ) { 1258 $user_id = bp_displayed_user_id(); 1259 } 1260 1261 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 ) ) ); 1262 } 1263 1264 /** 1265 * Process account deletion requests. 1266 * 1267 * Primarily used for self-deletions, as requested through Settings. 1268 * 1269 * @since 1.0.0 1270 * 1271 * @param int $user_id Optional. ID of the user to be deleted. Default: the 1272 * logged-in user. 1273 * @return bool True on success, false on failure. 1274 */ 1275 function bp_core_delete_account( $user_id = 0 ) { 1276 1277 // Use logged in user ID if none is passed. 1278 if ( empty( $user_id ) ) { 1279 $user_id = bp_loggedin_user_id(); 1280 } 1281 1282 // Site admins cannot be deleted. 1283 if ( is_super_admin( $user_id ) ) { 1284 return false; 1285 } 1286 1287 // Extra checks if user is not deleting themselves. 1288 if ( bp_loggedin_user_id() !== absint( $user_id ) ) { 1289 1290 // Bail if current user cannot delete any users. 1291 if ( ! bp_current_user_can( 'delete_users' ) ) { 1292 return false; 1293 } 1294 1295 // Bail if current user cannot delete this user. 1296 if ( ! current_user_can_for_blog( bp_get_root_blog_id(), 'delete_user', $user_id ) ) { 1297 return false; 1298 } 1299 } 1300 1301 /** 1302 * Fires before the processing of an account deletion. 1303 * 1304 * @since 1.6.0 1305 * 1306 * @param int $user_id ID of the user account being deleted. 1307 */ 1308 do_action( 'bp_core_pre_delete_account', $user_id ); 1309 1310 // Specifically handle multi-site environment. 1311 if ( is_multisite() ) { 1312 require_once( ABSPATH . '/wp-admin/includes/ms.php' ); 1313 require_once( ABSPATH . '/wp-admin/includes/user.php' ); 1314 1315 $retval = wpmu_delete_user( $user_id ); 1316 1317 // Single site user deletion. 1318 } else { 1319 require_once( ABSPATH . '/wp-admin/includes/user.php' ); 1320 $retval = wp_delete_user( $user_id ); 1321 } 1322 1323 /** 1324 * Fires after the deletion of an account. 1325 * 1326 * @since 1.6.0 1327 * 1328 * @param int $user_id ID of the user account that was deleted. 1329 */ 1330 do_action( 'bp_core_deleted_account', $user_id ); 1331 1332 return $retval; 1333 } 1334 1335 /** 1336 * Determines whether user data should be removed on the 'delete_user' hook. 1337 * 1338 * WordPress's 'delete_user' hook is ambiguous: on a standard installation, it means that a user 1339 * account is being removed from the system, while on Multisite it simply means the user is 1340 * being removed from a specific site (ie its roles are being revoked). As a rule, this means 1341 * that BuddyPress should remove user data on the delete_user hook only on non-Multisite 1342 * installations - only when the user account is being removed altogether. However, this behavior 1343 * can be filtered in a global, per-user, or per-component fashion. 1344 * 1345 * @since 6.0.0 1346 * 1347 * @param string $data_type Type of data to be removed. 1348 * @param int $user_id ID of the user, as passed to 'delete_user'. 1349 * @return bool 1350 */ 1351 function bp_remove_user_data_on_delete_user_hook( $component, $user_id ) { 1352 $remove = ! is_multisite(); 1353 1354 /** 1355 * Filters whether to remove user data on the 'delete_user' hook. 1356 * 1357 * @param bool $remove Whether data should be removed. 1358 * @param string $data_type Type of data to be removed. 1359 * @param int $user_id ID of the user, as passed to 'delete_user'. 1360 */ 1361 return apply_filters( 'bp_remove_user_data_on_delete_user_hook', $remove, $component, $user_id ); 1362 } 1363 1364 /** 1365 * Delete a user's avatar when the user is deleted. 1366 * 1367 * @since 1.9.0 1368 * 1369 * @param int $user_id ID of the user who is about to be deleted. 1370 * @return bool True on success, false on failure. 1371 */ 1372 function bp_core_delete_avatar_on_user_delete( $user_id ) { 1373 return bp_core_delete_existing_avatar( array( 1374 'item_id' => $user_id, 1375 'object' => 'user', 1376 ) ); 1377 } 1378 add_action( 'wpmu_delete_user', 'bp_core_delete_avatar_on_user_delete' ); 1379 1380 /** 1381 * Deletes last_activity data on the 'delete_user' hook. 1382 * 1383 * @since 6.0.0 1384 * 1385 * @param int $user_id The ID of the deleted user. 1386 */ 1387 function bp_core_delete_avatar_on_delete_user( $user_id ) { 1388 if ( ! bp_remove_user_data_on_delete_user_hook( 'avatar', $user_id ) ) { 1389 return; 1390 } 1391 1392 bp_core_delete_avatar_on_user_delete( $user_id ); 1393 } 1394 add_action( 'delete_user', 'bp_core_delete_avatar_on_delete_user' ); 1395 1396 /** 1397 * Multibyte-safe ucfirst() support. 1398 * 1399 * Uses multibyte functions when available on the PHP build. 1400 * 1401 * @since 1.0.0 1402 * 1403 * @param string $str String to be upper-cased. 1404 * @return string 1405 */ 1406 function bp_core_ucfirst( $str ) { 1407 if ( function_exists( 'mb_strtoupper' ) && function_exists( 'mb_substr' ) ) { 1408 $fc = mb_strtoupper( mb_substr( $str, 0, 1 ) ); 1409 return $fc.mb_substr( $str, 1 ); 1410 } else { 1411 return ucfirst( $str ); 1412 } 1413 } 1414 1415 /** 1416 * Prevent spammers from logging in. 1417 * 1418 * When a user logs in, check if they have been marked as a spammer. If yes 1419 * then simply redirect them to the home page and stop them from logging in. 1420 * 1421 * @since 1.1.2 1422 * 1423 * @param WP_User|WP_Error $user Either the WP_User object or the WP_Error 1424 * object, as passed to the 'authenticate' filter. 1425 * @return WP_User|WP_Error If the user is not a spammer, return the WP_User 1426 * object. Otherwise a new WP_Error object. 1427 */ 1428 function bp_core_boot_spammer( $user ) { 1429 1430 // Check to see if the $user has already failed logging in, if so return $user as-is. 1431 if ( is_wp_error( $user ) || empty( $user ) ) { 1432 return $user; 1433 } 1434 1435 // The user exists; now do a check to see if the user is a spammer 1436 // if the user is a spammer, stop them in their tracks! 1437 if ( is_a( $user, 'WP_User' ) && ( ( is_multisite() && (int) $user->spam ) || 1 == $user->user_status ) ) { 1438 return new WP_Error( 'invalid_username', __( '<strong>Error</strong>: Your account has been marked as a spammer.', 'buddypress' ) ); 1439 } 1440 1441 // User is good to go! 1442 return $user; 1443 } 1444 add_filter( 'authenticate', 'bp_core_boot_spammer', 30 ); 1445 1446 /** 1447 * Delete last_activity data for the user when the user is deleted. 1448 * 1449 * @since 1.0.0 1450 * 1451 * @param int $user_id The user ID for the user to delete usermeta for. 1452 */ 1453 function bp_core_remove_data( $user_id ) { 1454 1455 // Remove last_activity data. 1456 BP_Core_User::delete_last_activity( $user_id ); 1457 1458 // Flush the cache to remove the user from all cached objects. 1459 wp_cache_flush(); 1460 } 1461 add_action( 'wpmu_delete_user', 'bp_core_remove_data' ); 1462 add_action( 'bp_make_spam_user', 'bp_core_remove_data' ); 1463 1464 /** 1465 * Deletes last_activity data on the 'delete_user' hook. 1466 * 1467 * @since 6.0.0 1468 * 1469 * @param int $user_id The ID of the deleted user. 1470 */ 1471 function bp_core_remove_data_on_delete_user( $user_id ) { 1472 if ( ! bp_remove_user_data_on_delete_user_hook( 'last_activity', $user_id ) ) { 1473 return; 1474 } 1475 1476 bp_core_remove_data( $user_id ); 1477 } 1478 add_action( 'delete_user', 'bp_core_remove_data_on_delete_user' ); 1479 1480 /** 1481 * Check whether the logged-in user can edit settings for the displayed user. 1482 * 1483 * @since 1.5.0 1484 * 1485 * @return bool True if editing is allowed, otherwise false. 1486 */ 1487 function bp_core_can_edit_settings() { 1488 $status = false; 1489 1490 if ( bp_is_my_profile() ) { 1491 $status = true; 1492 } elseif ( is_super_admin( bp_displayed_user_id() ) && ! is_super_admin() ) { 1493 $status = false; 1494 } elseif ( bp_current_user_can( 'bp_moderate' ) || current_user_can( 'edit_users' ) ) { 1495 $status = true; 1496 } 1497 1498 /** 1499 * Filters the status of whether the logged-in user can edit settings for the displayed user or not. 1500 * 1501 * @since 2.8.0 1502 * 1503 * @param bool True if editing is allowed, otherwise false. 1504 */ 1505 return apply_filters( 'bp_core_can_edit_settings', $status ); 1506 } 1507 1508 /** Sign-up *******************************************************************/ 1509 1510 /** 1511 * Flush illegal names by getting and setting 'illegal_names' site option. 1512 * 1513 * @since 1.2.5 1514 */ 1515 function bp_core_flush_illegal_names() { 1516 $illegal_names = get_site_option( 'illegal_names' ); 1517 update_site_option( 'illegal_names', $illegal_names ); 1518 } 1519 1520 /** 1521 * Add BuddyPress-specific items to the illegal_names array. 1522 * 1523 * @since 1.2.7 1524 * 1525 * @param array|string $value Illegal names as being saved defined in 1526 * Multisite settings. 1527 * @return array Merged and unique array of illegal names. 1528 */ 1529 function bp_core_get_illegal_names( $value = '' ) { 1530 1531 // Make sure $value is array. 1532 if ( empty( $value ) ) { 1533 $db_illegal_names = array(); 1534 } 1535 1536 if ( is_array( $value ) ) { 1537 $db_illegal_names = $value; 1538 } elseif ( is_string( $value ) ) { 1539 $db_illegal_names = explode( ' ', $value ); 1540 } 1541 1542 // Add the core components' slugs to the banned list even if their components aren't active. 1543 $bp_component_slugs = array( 1544 'groups', 1545 'members', 1546 'forums', 1547 'blogs', 1548 'activity', 1549 'profile', 1550 'friends', 1551 'search', 1552 'settings', 1553 'notifications', 1554 'register', 1555 'activate', 1556 ); 1557 1558 // Core constants. 1559 $slug_constants = array( 1560 'BP_GROUPS_SLUG', 1561 'BP_MEMBERS_SLUG', 1562 'BP_FORUMS_SLUG', 1563 'BP_BLOGS_SLUG', 1564 'BP_ACTIVITY_SLUG', 1565 'BP_XPROFILE_SLUG', 1566 'BP_FRIENDS_SLUG', 1567 'BP_SEARCH_SLUG', 1568 'BP_SETTINGS_SLUG', 1569 'BP_NOTIFICATIONS_SLUG', 1570 'BP_REGISTER_SLUG', 1571 'BP_ACTIVATION_SLUG', 1572 ); 1573 foreach ( $slug_constants as $constant ) { 1574 if ( defined( $constant ) ) { 1575 $bp_component_slugs[] = constant( $constant ); 1576 } 1577 } 1578 1579 /** 1580 * Filters the array of default illegal usernames. 1581 * 1582 * @since 1.2.2 1583 * 1584 * @param array $value Merged and unique array of illegal usernames. 1585 */ 1586 $filtered_illegal_names = apply_filters( 'bp_core_illegal_usernames', array_merge( array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' ), $bp_component_slugs ) ); 1587 1588 /** 1589 * Filters the list of illegal usernames from WordPress. 1590 * 1591 * @since 3.0 1592 * 1593 * @param array Array of illegal usernames. 1594 */ 1595 $wp_filtered_illegal_names = apply_filters( 'illegal_user_logins', array() ); 1596 1597 // First merge BuddyPress illegal names. 1598 $bp_merged_names = array_merge( (array) $filtered_illegal_names, (array) $db_illegal_names ); 1599 1600 // Then merge WordPress and BuddyPress illegal names. 1601 $merged_names = array_merge( (array) $wp_filtered_illegal_names, (array) $bp_merged_names ); 1602 1603 // Remove duplicates. 1604 $illegal_names = array_unique( (array) $merged_names ); 1605 1606 /** 1607 * Filters the array of default illegal names. 1608 * 1609 * @since 1.2.5 1610 * 1611 * @param array $value Merged and unique array of illegal names. 1612 */ 1613 return apply_filters( 'bp_core_illegal_names', $illegal_names ); 1614 } 1615 add_filter( 'pre_update_site_option_illegal_names', 'bp_core_get_illegal_names' ); 1616 1617 /** 1618 * Check that an email address is valid for use. 1619 * 1620 * Performs the following checks: 1621 * - Is the email address well-formed? 1622 * - Is the email address already used? 1623 * - If there are disallowed email domains, is the current domain among them? 1624 * - If there's an email domain whitelest, is the current domain on it? 1625 * 1626 * @since 1.6.2 1627 * 1628 * @param string $user_email The email being checked. 1629 * @return bool|array True if the address passes all checks; otherwise an array 1630 * of error codes. 1631 */ 1632 function bp_core_validate_email_address( $user_email ) { 1633 $errors = array(); 1634 1635 $user_email = sanitize_email( $user_email ); 1636 1637 // Is the email well-formed? 1638 if ( ! is_email( $user_email ) ) { 1639 $errors['invalid'] = 1; 1640 } 1641 1642 // Is the email on the Banned Email Domains list? 1643 // Note: This check only works on Multisite. 1644 if ( function_exists( 'is_email_address_unsafe' ) && is_email_address_unsafe( $user_email ) ) { 1645 $errors['domain_banned'] = 1; 1646 } 1647 1648 // Is the email on the Limited Email Domains list? 1649 // Note: This check only works on Multisite. 1650 $limited_email_domains = get_site_option( 'limited_email_domains' ); 1651 if ( is_array( $limited_email_domains ) && empty( $limited_email_domains ) == false ) { 1652 $emaildomain = substr( $user_email, 1 + strpos( $user_email, '@' ) ); 1653 if ( ! in_array( $emaildomain, $limited_email_domains ) ) { 1654 $errors['domain_not_allowed'] = 1; 1655 } 1656 } 1657 1658 // Is the email alreday in use? 1659 if ( email_exists( $user_email ) ) { 1660 $errors['in_use'] = 1; 1661 } 1662 1663 $retval = ! empty( $errors ) ? $errors : true; 1664 1665 return $retval; 1666 } 1667 1668 /** 1669 * Add the appropriate errors to a WP_Error object, given results of a validation test. 1670 * 1671 * Functions like bp_core_validate_email_address() return a structured array 1672 * of error codes. bp_core_add_validation_error_messages() takes this array and 1673 * parses, adding the appropriate error messages to the WP_Error object. 1674 * 1675 * @since 1.7.0 1676 * 1677 * @see bp_core_validate_email_address() 1678 * 1679 * @param WP_Error $errors WP_Error object. 1680 * @param array $validation_results The return value of a validation function 1681 * like bp_core_validate_email_address(). 1682 */ 1683 function bp_core_add_validation_error_messages( WP_Error $errors, $validation_results ) { 1684 if ( ! empty( $validation_results['invalid'] ) ) { 1685 $errors->add( 'user_email', __( 'Please check your email address.', 'buddypress' ) ); 1686 } 1687 1688 if ( ! empty( $validation_results['domain_banned'] ) ) { 1689 $errors->add( 'user_email', __( 'Sorry, that email address is not allowed!', 'buddypress' ) ); 1690 } 1691 1692 if ( ! empty( $validation_results['domain_not_allowed'] ) ) { 1693 $errors->add( 'user_email', __( 'Sorry, that email address is not allowed!', 'buddypress' ) ); 1694 } 1695 1696 if ( ! empty( $validation_results['in_use'] ) ) { 1697 $errors->add( 'user_email', __( 'Sorry, that email address is already used!', 'buddypress' ) ); 1698 } 1699 } 1700 1701 /** 1702 * Validate a user name and email address when creating a new user. 1703 * 1704 * @since 1.2.2 1705 * 1706 * @param string $user_name Username to validate. 1707 * @param string $user_email Email address to validate. 1708 * @return array Results of user validation including errors, if any. 1709 */ 1710 function bp_core_validate_user_signup( $user_name, $user_email ) { 1711 1712 // Make sure illegal names include BuddyPress slugs and values. 1713 bp_core_flush_illegal_names(); 1714 1715 // WordPress Multisite has its own validation. Use it, so that we 1716 // properly mirror restrictions on username, etc. 1717 if ( function_exists( 'wpmu_validate_user_signup' ) ) { 1718 $result = wpmu_validate_user_signup( $user_name, $user_email ); 1719 1720 // When not running Multisite, we perform our own validation. What 1721 // follows reproduces much of the logic of wpmu_validate_user_signup(), 1722 // minus the multisite-specific restrictions on user_login. 1723 } else { 1724 $errors = new WP_Error(); 1725 1726 /** 1727 * Filters the username before being validated. 1728 * 1729 * @since 1.5.5 1730 * 1731 * @param string $user_name Username to validate. 1732 */ 1733 $user_name = apply_filters( 'pre_user_login', $user_name ); 1734 1735 // User name can't be empty. 1736 if ( empty( $user_name ) ) { 1737 $errors->add( 'user_name', __( 'Please enter a username', 'buddypress' ) ); 1738 } 1739 1740 // User name can't be on the list of illegal names. 1741 $illegal_names = get_site_option( 'illegal_names' ); 1742 if ( in_array( $user_name, (array) $illegal_names ) ) { 1743 $errors->add( 'user_name', __( 'That username is not allowed', 'buddypress' ) ); 1744 } 1745 1746 // User name must pass WP's validity check. 1747 if ( ! validate_username( $user_name ) ) { 1748 $errors->add( 'user_name', __( 'Usernames can contain only letters, numbers, ., -, and @', 'buddypress' ) ); 1749 } 1750 1751 // Minimum of 4 characters. 1752 if ( strlen( $user_name ) < 4 ) { 1753 $errors->add( 'user_name', __( 'Username must be at least 4 characters', 'buddypress' ) ); 1754 } 1755 1756 // No underscores. @todo Why not? 1757 if ( false !== strpos( ' ' . $user_name, '_' ) ) { 1758 $errors->add( 'user_name', __( 'Sorry, usernames may not contain the character "_"!', 'buddypress' ) ); 1759 } 1760 1761 // No usernames that are all numeric. @todo Why? 1762 $match = array(); 1763 preg_match( '/[0-9]*/', $user_name, $match ); 1764 if ( $match[0] == $user_name ) { 1765 $errors->add( 'user_name', __( 'Sorry, usernames must have letters too!', 'buddypress' ) ); 1766 } 1767 1768 // Check into signups. 1769 $signups = BP_Signup::get( array( 1770 'user_login' => $user_name, 1771 ) ); 1772 1773 $signup = isset( $signups['signups'] ) && ! empty( $signups['signups'][0] ) ? $signups['signups'][0] : false; 1774 1775 // Check if the username has been used already. 1776 if ( username_exists( $user_name ) || ! empty( $signup ) ) { 1777 $errors->add( 'user_name', __( 'Sorry, that username already exists!', 'buddypress' ) ); 1778 } 1779 1780 // Validate the email address and process the validation results into 1781 // error messages. 1782 $validate_email = bp_core_validate_email_address( $user_email ); 1783 bp_core_add_validation_error_messages( $errors, $validate_email ); 1784 1785 // Assemble the return array. 1786 $result = array( 1787 'user_name' => $user_name, 1788 'user_email' => $user_email, 1789 'errors' => $errors, 1790 ); 1791 1792 // Apply WPMU legacy filter. 1793 $result = apply_filters( 'wpmu_validate_user_signup', $result ); 1794 } 1795 1796 /** 1797 * Filters the result of the user signup validation. 1798 * 1799 * @since 1.2.2 1800 * 1801 * @param array $result Results of user validation including errors, if any. 1802 */ 1803 return apply_filters( 'bp_core_validate_user_signup', $result ); 1804 } 1805 1806 /** 1807 * Validate a user password. 1808 * 1809 * @since 7.0.0 1810 * 1811 * @param string $pass The password. 1812 * @param string $confirm_pass The confirmed password. 1813 * @param null|WP_User $userdata Null or the userdata object when a member updates their password from front-end. 1814 * @return WP_Error A WP error object possibly containing error messages. 1815 */ 1816 function bp_members_validate_user_password( $pass, $confirm_pass, $userdata = null ) { 1817 $errors = new WP_Error(); 1818 1819 if ( ! $pass || ! $confirm_pass ) { 1820 $errors->add( 'missing_user_password', __( 'Please make sure you enter your password twice', 'buddypress' ) ); 1821 } 1822 1823 if ( $pass && $confirm_pass && $pass !== $confirm_pass ) { 1824 $errors->add( 'mismatching_user_password', __( 'The passwords you entered do not match.', 'buddypress' ) ); 1825 } 1826 1827 /** 1828 * Filter here to add password validation errors. 1829 * 1830 * @since 7.0.0 1831 * 1832 * @param WP_Error $errors Password validation errors. 1833 * @param string $pass The password. 1834 * @param string $confirm_pass The confirmed password. 1835 * @param null|WP_User $userdata Null or the userdata object when a member updates their password from front-end. 1836 */ 1837 return apply_filters( 'bp_members_validate_user_password', $errors, $pass, $confirm_pass, $userdata ); 1838 } 1839 1840 /** 1841 * Validate blog URL and title provided at signup. 1842 * 1843 * @since 1.2.2 1844 * 1845 * @todo Why do we have this wrapper? 1846 * 1847 * @param string $blog_url Blog URL requested during registration. 1848 * @param string $blog_title Blog title requested during registration. 1849 * @return array 1850 */ 1851 function bp_core_validate_blog_signup( $blog_url, $blog_title ) { 1852 if ( ! is_multisite() || ! function_exists( 'wpmu_validate_blog_signup' ) ) { 1853 return false; 1854 } 1855 1856 /** 1857 * Filters the validated blog url and title provided at signup. 1858 * 1859 * @since 1.2.2 1860 * 1861 * @param array $value Array with the new site data and error messages. 1862 */ 1863 return apply_filters( 'bp_core_validate_blog_signup', wpmu_validate_blog_signup( $blog_url, $blog_title ) ); 1864 } 1865 1866 /** 1867 * Process data submitted at user registration and convert to a signup object. 1868 * 1869 * @since 1.2.0 1870 * 1871 * @global BuddyPress $bp The one true BuddyPress instance. 1872 * 1873 * @todo There appears to be a bug in the return value on success. 1874 * 1875 * @param string $user_login Login name requested by the user. 1876 * @param string $user_password Password requested by the user. 1877 * @param string $user_email Email address entered by the user. 1878 * @param array $usermeta Miscellaneous metadata about the user (blog-specific 1879 * signup data, xprofile data, etc). 1880 * @return int|false True on success, WP_Error on failure. 1881 */ 1882 function bp_core_signup_user( $user_login, $user_password, $user_email, $usermeta ) { 1883 $bp = buddypress(); 1884 1885 // We need to cast $user_id to pass to the filters. 1886 $user_id = false; 1887 1888 // Multisite installs have their own install procedure. 1889 if ( is_multisite() ) { 1890 wpmu_signup_user( $user_login, $user_email, $usermeta ); 1891 1892 } else { 1893 // Format data. 1894 $user_login = preg_replace( '/\s+/', '', sanitize_user( $user_login, true ) ); 1895 $user_email = sanitize_email( $user_email ); 1896 $activation_key = wp_generate_password( 32, false ); 1897 1898 /** 1899 * WordPress's default behavior is to create user accounts 1900 * immediately at registration time. BuddyPress uses a system 1901 * borrowed from WordPress Multisite, where signups are stored 1902 * separately and accounts are only created at the time of 1903 * activation. For backward compatibility with plugins that may 1904 * be anticipating WP's default behavior, BP silently creates 1905 * accounts for registrations (though it does not use them). If 1906 * you know that you are not running any plugins dependent on 1907 * these pending accounts, you may want to save a little DB 1908 * clutter by defining setting the BP_SIGNUPS_SKIP_USER_CREATION 1909 * to true in your wp-config.php file. 1910 */ 1911 if ( ! defined( 'BP_SIGNUPS_SKIP_USER_CREATION' ) || ! BP_SIGNUPS_SKIP_USER_CREATION ) { 1912 $user_id = BP_Signup::add_backcompat( $user_login, $user_password, $user_email, $usermeta ); 1913 1914 if ( is_wp_error( $user_id ) ) { 1915 return $user_id; 1916 } 1917 1918 bp_update_user_meta( $user_id, 'activation_key', $activation_key ); 1919 } 1920 1921 $args = array( 1922 'user_login' => $user_login, 1923 'user_email' => $user_email, 1924 'activation_key' => $activation_key, 1925 'meta' => $usermeta, 1926 ); 1927 1928 BP_Signup::add( $args ); 1929 1930 /** 1931 * Filters if BuddyPress should send an activation key for a new signup. 1932 * 1933 * @since 1.2.3 1934 * 1935 * @param bool $value Whether or not to send the activation key. 1936 * @param int $user_id User ID to send activation key to. 1937 * @param string $user_email User email to send activation key to. 1938 * @param string $activation_key Activation key to be sent. 1939 * @param array $usermeta Miscellaneous metadata about the user (blog-specific 1940 * signup data, xprofile data, etc). 1941 */ 1942 if ( apply_filters( 'bp_core_signup_send_activation_key', true, $user_id, $user_email, $activation_key, $usermeta ) ) { 1943 $salutation = $user_login; 1944 if ( bp_is_active( 'xprofile' ) && isset( $usermeta[ 'field_' . bp_xprofile_fullname_field_id() ] ) ) { 1945 $salutation = $usermeta[ 'field_' . bp_xprofile_fullname_field_id() ]; 1946 } 1947 1948 bp_core_signup_send_validation_email( $user_id, $user_email, $activation_key, $salutation ); 1949 } 1950 } 1951 1952 $bp->signup->username = $user_login; 1953 1954 /** 1955 * Fires at the end of the process to sign up a user. 1956 * 1957 * @since 1.2.2 1958 * 1959 * @param bool|WP_Error $user_id True on success, WP_Error on failure. 1960 * @param string $user_login Login name requested by the user. 1961 * @param string $user_password Password requested by the user. 1962 * @param string $user_email Email address requested by the user. 1963 * @param array $usermeta Miscellaneous metadata about the user (blog-specific 1964 * signup data, xprofile data, etc). 1965 */ 1966 do_action( 'bp_core_signup_user', $user_id, $user_login, $user_password, $user_email, $usermeta ); 1967 1968 return $user_id; 1969 } 1970 1971 /** 1972 * Create a blog and user based on data supplied at user registration. 1973 * 1974 * @since 1.2.2 1975 * 1976 * @param string $blog_domain Domain requested by user. 1977 * @param string $blog_path Path requested by user. 1978 * @param string $blog_title Title as entered by user. 1979 * @param string $user_name user_login of requesting user. 1980 * @param string $user_email Email address of requesting user. 1981 * @param string $usermeta Miscellaneous metadata for the user. 1982 * @return bool 1983 */ 1984 function bp_core_signup_blog( $blog_domain, $blog_path, $blog_title, $user_name, $user_email, $usermeta ) { 1985 if ( ! is_multisite() || ! function_exists( 'wpmu_signup_blog' ) ) { 1986 return false; 1987 } 1988 1989 /** 1990 * Filters the result of wpmu_signup_blog(). 1991 * 1992 * This filter provides no value and is retained for 1993 * backwards compatibility. 1994 * 1995 * @since 1.2.2 1996 * 1997 * @param void $value 1998 */ 1999 return apply_filters( 'bp_core_signup_blog', wpmu_signup_blog( $blog_domain, $blog_path, $blog_title, $user_name, $user_email, $usermeta ) ); 2000 } 2001 2002 /** 2003 * Activate a signup, as identified by an activation key. 2004 * 2005 * @since 1.2.2 2006 * 2007 * @global wpdb $wpdb WordPress database object. 2008 * 2009 * @param string $key Activation key. 2010 * @return int|bool User ID on success, false on failure. 2011 */ 2012 function bp_core_activate_signup( $key ) { 2013 global $wpdb; 2014 2015 $user = false; 2016 2017 // Multisite installs have their own activation routine. 2018 if ( is_multisite() ) { 2019 $user = wpmu_activate_signup( $key ); 2020 2021 // If there were errors, add a message and redirect. 2022 if ( ! empty( $user->errors ) ) { 2023 return $user; 2024 } 2025 2026 $user_id = $user['user_id']; 2027 2028 } else { 2029 $signups = BP_Signup::get( array( 2030 'activation_key' => $key, 2031 ) ); 2032 2033 if ( empty( $signups['signups'] ) ) { 2034 return new WP_Error( 'invalid_key', __( 'Invalid activation key.', 'buddypress' ) ); 2035 } 2036 2037 $signup = $signups['signups'][0]; 2038 2039 if ( $signup->active ) { 2040 if ( empty( $signup->domain ) ) { 2041 return new WP_Error( 'already_active', __( 'The user is already active.', 'buddypress' ), $signup ); 2042 } else { 2043 return new WP_Error( 'already_active', __( 'The site is already active.', 'buddypress' ), $signup ); 2044 } 2045 } 2046 2047 // Password is hashed again in wp_insert_user. 2048 $password = wp_generate_password( 12, false ); 2049 2050 $user_id = username_exists( $signup->user_login ); 2051 2052 // Create the user. This should only be necessary if BP_SIGNUPS_SKIP_USER_CREATION is true. 2053 if ( ! $user_id ) { 2054 $user_id = wp_create_user( $signup->user_login, $password, $signup->user_email ); 2055 2056 // Otherwise, update the existing user's status. 2057 } elseif ( $key === bp_get_user_meta( $user_id, 'activation_key', true ) || $key === wp_hash( $user_id ) ) { 2058 2059 // Change the user's status so they become active. 2060 if ( ! $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_status = 0 WHERE ID = %d", $user_id ) ) ) { 2061 return new WP_Error( 'invalid_key', __( 'Invalid activation key.', 'buddypress' ) ); 2062 } 2063 2064 bp_delete_user_meta( $user_id, 'activation_key' ); 2065 2066 $user_already_created = true; 2067 2068 } else { 2069 $user_already_exists = true; 2070 } 2071 2072 if ( ! $user_id ) { 2073 return new WP_Error( 'create_user', __( 'Could not create user', 'buddypress' ), $signup ); 2074 } 2075 2076 // Fetch the signup so we have the data later on. 2077 $signups = BP_Signup::get( array( 2078 'activation_key' => $key, 2079 ) ); 2080 2081 $signup = isset( $signups['signups'] ) && ! empty( $signups['signups'][0] ) ? $signups['signups'][0] : false; 2082 2083 // Activate the signup. 2084 BP_Signup::validate( $key ); 2085 2086 if ( isset( $user_already_exists ) ) { 2087 return new WP_Error( 'user_already_exists', __( 'That username is already activated.', 'buddypress' ), $signup ); 2088 } 2089 2090 // Set up data to pass to the legacy filter. 2091 $user = array( 2092 'user_id' => $user_id, 2093 'password' => isset( $signup->meta['password'] ) ? $signup->meta['password'] : '', 2094 'meta' => $signup->meta, 2095 ); 2096 2097 /** 2098 * Maybe notify the site admin of a new user registration. 2099 * 2100 * @since 1.2.2 2101 * 2102 * @param bool $notification Whether to send the notification or not. 2103 */ 2104 if ( apply_filters( 'bp_core_send_user_registration_admin_notification', true ) ) { 2105 wp_new_user_notification( $user_id ); 2106 } 2107 2108 if ( isset( $user_already_created ) ) { 2109 2110 /** 2111 * Fires if the user has already been created. 2112 * 2113 * @since 1.2.2 2114 * 2115 * @param int $user_id ID of the user being checked. 2116 * @param string $key Activation key. 2117 * @param array $user Array of user data. 2118 */ 2119 do_action( 'bp_core_activated_user', $user_id, $key, $user ); 2120 return $user_id; 2121 } 2122 } 2123 2124 // Set any profile data. 2125 if ( bp_is_active( 'xprofile' ) ) { 2126 if ( ! empty( $user['meta']['profile_field_ids'] ) ) { 2127 $profile_field_ids = explode( ',', $user['meta']['profile_field_ids'] ); 2128 2129 foreach( (array) $profile_field_ids as $field_id ) { 2130 $current_field = isset( $user['meta']["field_{$field_id}"] ) ? $user['meta']["field_{$field_id}"] : false; 2131 2132 if ( ! empty( $current_field ) ) { 2133 xprofile_set_field_data( $field_id, $user_id, $current_field ); 2134 } 2135 2136 /* 2137 * Save the visibility level. 2138 * 2139 * Use the field's default visibility if not present, and 'public' if a 2140 * default visibility is not defined. 2141 */ 2142 $key = "field_{$field_id}_visibility"; 2143 if ( isset( $user['meta'][ $key ] ) ) { 2144 $visibility_level = $user['meta'][ $key ]; 2145 } else { 2146 $vfield = xprofile_get_field( $field_id, null, false ); 2147 $visibility_level = isset( $vfield->default_visibility ) ? $vfield->default_visibility : 'public'; 2148 } 2149 xprofile_set_field_visibility_level( $field_id, $user_id, $visibility_level ); 2150 } 2151 } 2152 } 2153 2154 // Replace the password automatically generated by WordPress by the one the user chose. 2155 if ( ! empty( $user['meta']['password'] ) ) { 2156 $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->users} SET user_pass = %s WHERE ID = %d", $user['meta']['password'], $user_id ) ); 2157 2158 /** 2159 * Make sure to clean the user's cache as we've 2160 * directly edited the password without using 2161 * wp_update_user(). 2162 * 2163 * If we can't use wp_update_user() that's because 2164 * we already hashed the password at the signup step. 2165 */ 2166 $uc = wp_cache_get( $user_id, 'users' ); 2167 2168 if ( ! empty( $uc->ID ) ) { 2169 clean_user_cache( $uc->ID ); 2170 } 2171 } 2172 2173 /** 2174 * Fires at the end of the user activation process. 2175 * 2176 * @since 1.2.2 2177 * 2178 * @param int $user_id ID of the user being checked. 2179 * @param string $key Activation key. 2180 * @param array $user Array of user data. 2181 */ 2182 do_action( 'bp_core_activated_user', $user_id, $key, $user ); 2183 2184 return $user_id; 2185 } 2186 2187 /** 2188 * Add default WordPress role for new signups on the BP root blog. 2189 * 2190 * @since 3.0.0 2191 * 2192 * @param int $user_id The user ID to add the default role for. 2193 */ 2194 function bp_members_add_role_after_activation( $user_id ) { 2195 // Get default role to add. 2196 $role = bp_get_option( 'default_role' ); 2197 2198 // Multisite. 2199 if ( is_multisite() && ! is_user_member_of_blog( $user_id, bp_get_root_blog_id() ) ) { 2200 add_user_to_blog( bp_get_root_blog_id(), $user_id, $role ); 2201 2202 // Single-site. 2203 } elseif ( ! is_multisite() ) { 2204 $member = get_userdata( $user_id ); 2205 $member->set_role( $role ); 2206 } 2207 } 2208 add_action( 'bp_core_activated_user', 'bp_members_add_role_after_activation', 1 ); 2209 2210 /** 2211 * Migrate signups from pre-2.0 configuration to wp_signups. 2212 * 2213 * @since 2.0.1 2214 * 2215 * @global wpdb $wpdb WordPress database object. 2216 */ 2217 function bp_members_migrate_signups() { 2218 global $wpdb; 2219 2220 $status_2_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->users} WHERE user_status = '2'" ); 2221 2222 if ( ! empty( $status_2_ids ) ) { 2223 $signups = get_users( array( 2224 'fields' => array( 2225 'ID', 2226 'user_login', 2227 'user_pass', 2228 'user_registered', 2229 'user_email', 2230 'display_name', 2231 ), 2232 'include' => $status_2_ids, 2233 ) ); 2234 2235 // Fetch activation keys separately, to avoid the all_with_meta 2236 // overhead. 2237 $status_2_ids_sql = implode( ',', $status_2_ids ); 2238 $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})" ); 2239 2240 // Rekey. 2241 $activation_keys = array(); 2242 foreach ( $ak_data as $ak_datum ) { 2243 $activation_keys[ intval( $ak_datum->user_id ) ] = $ak_datum->meta_value; 2244 } 2245 2246 unset( $status_2_ids_sql, $status_2_ids, $ak_data ); 2247 2248 // Merge. 2249 foreach ( $signups as &$signup ) { 2250 if ( isset( $activation_keys[ $signup->ID ] ) ) { 2251 $signup->activation_key = $activation_keys[ $signup->ID ]; 2252 } 2253 } 2254 2255 // Reset the signup var as we're using it to process the migration. 2256 unset( $signup ); 2257 2258 } else { 2259 return; 2260 } 2261 2262 foreach ( $signups as $signup ) { 2263 $meta = array(); 2264 2265 // Rebuild the activation key, if missing. 2266 if ( empty( $signup->activation_key ) ) { 2267 $signup->activation_key = wp_generate_password( 32, false ); 2268 } 2269 2270 if ( bp_is_active( 'xprofile' ) ) { 2271 $meta['field_1'] = $signup->display_name; 2272 } 2273 2274 $meta['password'] = $signup->user_pass; 2275 2276 $user_login = preg_replace( '/\s+/', '', sanitize_user( $signup->user_login, true ) ); 2277 $user_email = sanitize_email( $signup->user_email ); 2278 2279 BP_Signup::add( array( 2280 'user_login' => $user_login, 2281 'user_email' => $user_email, 2282 'registered' => $signup->user_registered, 2283 'activation_key' => $signup->activation_key, 2284 'meta' => $meta 2285 ) ); 2286 2287 // Deleting these options will remove signups from users count. 2288 delete_user_option( $signup->ID, 'capabilities' ); 2289 delete_user_option( $signup->ID, 'user_level' ); 2290 } 2291 } 2292 2293 /** 2294 * Map a user's WP display name to the XProfile fullname field, if necessary. 2295 * 2296 * This only happens when a user is registered in wp-admin by an administrator; 2297 * during normal registration, XProfile data is provided directly by the user. 2298 * 2299 * @since 1.2.0 2300 * 2301 * @param int $user_id ID of the user. 2302 * @return bool 2303 */ 2304 function bp_core_map_user_registration( $user_id ) { 2305 2306 // Only map data when the site admin is adding users, not on registration. 2307 if ( ! is_admin() ) { 2308 return false; 2309 } 2310 2311 // Add the user's fullname to Xprofile. 2312 if ( bp_is_active( 'xprofile' ) ) { 2313 $firstname = bp_get_user_meta( $user_id, 'first_name', true ); 2314 $lastname = ' ' . bp_get_user_meta( $user_id, 'last_name', true ); 2315 $name = $firstname . $lastname; 2316 2317 if ( empty( $name ) || ' ' == $name ) { 2318 $name = bp_get_user_meta( $user_id, 'nickname', true ); 2319 } 2320 2321 xprofile_set_field_data( 1, $user_id, $name ); 2322 } 2323 } 2324 add_action( 'user_register', 'bp_core_map_user_registration' ); 2325 2326 /** 2327 * Get the avatar storage directory for use during registration. 2328 * 2329 * @since 1.1.0 2330 * 2331 * @global BuddyPress $bp The one true BuddyPress instance. 2332 * 2333 * @return string|bool Directory path on success, false on failure. 2334 */ 2335 function bp_core_signup_avatar_upload_dir() { 2336 $bp = buddypress(); 2337 2338 if ( empty( $bp->signup->avatar_dir ) ) { 2339 return false; 2340 } 2341 2342 $directory = 'avatars/signups'; 2343 $path = bp_core_avatar_upload_path() . '/' . $directory . '/' . $bp->signup->avatar_dir; 2344 $newbdir = $path; 2345 $newurl = bp_core_avatar_url() . '/' . $directory . '/' . $bp->signup->avatar_dir; 2346 $newburl = $newurl; 2347 $newsubdir = '/' . $directory . '/' . $bp->signup->avatar_dir; 2348 2349 /** 2350 * Filters the avatar storage directory for use during registration. 2351 * 2352 * @since 1.1.1 2353 * 2354 * @param array $value Array of path and URL values for created storage directory. 2355 */ 2356 return apply_filters( 'bp_core_signup_avatar_upload_dir', array( 2357 'path' => $path, 2358 'url' => $newurl, 2359 'subdir' => $newsubdir, 2360 'basedir' => $newbdir, 2361 'baseurl' => $newburl, 2362 'error' => false, 2363 ) ); 2364 } 2365 2366 /** 2367 * Send activation email to a newly registered user. 2368 * 2369 * @since 1.2.2 2370 * @since 2.5.0 Add the $user_login parameter. 2371 * @since 5.0.0 Change $user_login parameter to more general $salutation. 2372 * 2373 * @param int|bool $user_id ID of the new user, false if BP_SIGNUPS_SKIP_USER_CREATION is true. 2374 * @param string $user_email Email address of the new user. 2375 * @param string $key Activation key. 2376 * @param string $salutation Optional. The name to be used as a salutation in the email. 2377 */ 2378 function bp_core_signup_send_validation_email( $user_id, $user_email, $key, $salutation = '' ) { 2379 $args = array( 2380 'tokens' => array( 2381 'activate.url' => esc_url( trailingslashit( bp_get_activation_page() ) . "{$key}/" ), 2382 'key' => $key, 2383 'user.email' => $user_email, 2384 'user.id' => $user_id, 2385 ), 2386 ); 2387 2388 $to = array( array( $user_email => $salutation ) ); 2389 2390 bp_send_email( 'core-user-registration', $to, $args ); 2391 2392 // Record that the activation email has been sent. 2393 $signup = bp_members_get_signup_by( 'activation_key', $key ); 2394 2395 if ( $signup ) { 2396 $meta = array( 2397 'sent_date' => current_time( 'mysql', true ), 2398 'count_sent' => $signup->count_sent + 1 2399 ); 2400 2401 BP_Signup::update( array( 2402 'signup_id' => $signup->id, 2403 'meta' => $meta, 2404 ) ); 2405 } 2406 } 2407 2408 /** 2409 * Display a "resend email" link when an unregistered user attempts to log in. 2410 * 2411 * @since 1.2.2 2412 * 2413 * @param WP_User|WP_Error|null $user Either the WP_User or the WP_Error object. 2414 * @param string $username The inputted, attempted username. 2415 * @param string $password The inputted, attempted password. 2416 * @return WP_User|WP_Error 2417 */ 2418 function bp_core_signup_disable_inactive( $user = null, $username = '', $password ='' ) { 2419 // Login form not used. 2420 if ( empty( $username ) && empty( $password ) ) { 2421 return $user; 2422 } 2423 2424 // An existing WP_User with a user_status of 2 is either a legacy 2425 // signup, or is a user created for backward compatibility. See 2426 // {@link bp_core_signup_user()} for more details. 2427 if ( is_a( $user, 'WP_User' ) && 2 == $user->user_status ) { 2428 $user_login = $user->user_login; 2429 2430 // If no WP_User is found corresponding to the username, this 2431 // is a potential signup. 2432 } elseif ( is_wp_error( $user ) && 'invalid_username' == $user->get_error_code() ) { 2433 $user_login = $username; 2434 2435 // This is an activated user, so bail. 2436 } else { 2437 return $user; 2438 } 2439 2440 // Look for the unactivated signup corresponding to the login name. 2441 $signup = BP_Signup::get( array( 'user_login' => sanitize_user( $user_login ) ) ); 2442 2443 // No signup or more than one, something is wrong. Let's bail. 2444 if ( empty( $signup['signups'][0] ) || $signup['total'] > 1 ) { 2445 return $user; 2446 } 2447 2448 // Unactivated user account found! 2449 /* 2450 * Don't allow users to resend their own activation email 2451 * when membership requests are enabled. 2452 */ 2453 if ( bp_get_membership_requests_required() ) { 2454 $error_message = sprintf( 2455 '<strong>%1$s</strong> %2$s', 2456 esc_html_x( 'Error:', 'Warning displayed on the WP Login screen', 'buddypress' ), 2457 esc_html_x( 'Your membership request has not yet been approved.', 'Error message displayed on the WP Login screen', 'buddypress' ) 2458 ); 2459 } else { 2460 // Set up the feedback message. 2461 $signup_id = $signup['signups'][0]->signup_id; 2462 2463 $resend_url_params = array( 2464 'action' => 'bp-resend-activation', 2465 'id' => $signup_id, 2466 ); 2467 2468 $resend_url = wp_nonce_url( 2469 add_query_arg( $resend_url_params, wp_login_url() ), 2470 'bp-resend-activation' 2471 ); 2472 2473 $error_message = sprintf( 2474 '<strong>%1$s</strong> %2$s<br /><br />%3$s', 2475 esc_html_x( 'Error:', 'Warning displayed on the WP Login screen', 'buddypress' ), 2476 esc_html_x( 'Your account has not been activated. Check your email for the activation link.', 'Error message displayed on the WP Login screen', 'buddypress' ), 2477 sprintf( 2478 /* translators: %s: the link to resend the activation email. */ 2479 esc_html_x( 'If you have not received an email yet, %s.', 'WP Login screen message', 'buddypress' ), 2480 sprintf( 2481 '<a href="%1$s">%2$s</a>', 2482 esc_url( $resend_url ), 2483 esc_html_x( 'click here to resend it', 'Text of the link to resend the activation email', 'buddypress' ) 2484 ) 2485 ) 2486 ); 2487 } 2488 2489 return new WP_Error( 'bp_account_not_activated', $error_message ); 2490 } 2491 add_filter( 'authenticate', 'bp_core_signup_disable_inactive', 30, 3 ); 2492 2493 /** 2494 * On the login screen, resends the activation email for a user. 2495 * 2496 * @since 2.0.0 2497 * 2498 * @see bp_core_signup_disable_inactive() 2499 */ 2500 function bp_members_login_resend_activation_email() { 2501 global $error; 2502 2503 if ( empty( $_GET['id'] ) || empty( $_GET['_wpnonce'] ) ) { 2504 return; 2505 } 2506 2507 // Verify nonce. 2508 if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'bp-resend-activation' ) ) { 2509 die( 'Security check' ); 2510 } 2511 2512 $signup_id = (int) $_GET['id']; 2513 2514 // Resend the activation email. 2515 // also updates the 'last sent' and '# of emails sent' values. 2516 $resend = BP_Signup::resend( array( $signup_id ) ); 2517 2518 // Add feedback message. 2519 if ( ! empty( $resend['errors'] ) ) { 2520 $error = __( '<strong>Error</strong>: Your account has already been activated.', 'buddypress' ); 2521 } else { 2522 $error = __( 'Activation email resent! Please check your inbox or spam folder.', 'buddypress' ); 2523 } 2524 } 2525 add_action( 'login_form_bp-resend-activation', 'bp_members_login_resend_activation_email' ); 2526 2527 /** 2528 * Redirect away from wp-signup.php if BP registration templates are present. 2529 * 2530 * @since 1.1.0 2531 */ 2532 function bp_core_wpsignup_redirect() { 2533 2534 // Bail in admin or if custom signup page is broken. 2535 if ( is_admin() || ! bp_has_custom_signup_page() ) { 2536 return; 2537 } 2538 2539 $is_wp_signup = false; 2540 if ( ! empty( $_SERVER['SCRIPT_NAME'] ) ) { 2541 $script_name_path = wp_parse_url( $_SERVER['SCRIPT_NAME'], PHP_URL_PATH ); 2542 2543 if ( 'wp-signup.php' === basename( $script_name_path ) || ( 'wp-login.php' === basename( $script_name_path ) && ! empty( $_GET['action'] ) && 'register' === $_GET['action'] ) ) { 2544 $is_wp_signup = true; 2545 } 2546 } 2547 2548 // If this is not wp-signup.php, there's nothing to do here. 2549 if ( ! $is_wp_signup ) { 2550 return; 2551 } 2552 2553 /* 2554 * We redirect wp-signup.php to the registration page except when it's a site signup. 2555 * In that case, redirect to the BP site creation page if available, otherwise allow 2556 * access to wp-signup.php. 2557 */ 2558 $redirect_to = bp_get_signup_page(); 2559 2560 $is_site_creation = false; 2561 2562 $referer = wp_get_referer(); 2563 2564 // A new site is being added. 2565 if ( isset( $_POST['stage'] ) && $_POST['stage'] === 'gimmeanotherblog' ) { 2566 $is_site_creation = true; 2567 2568 // We've arrived at wp-signup.php from my-sites.php. 2569 } elseif ( $referer ) { 2570 $referer_path = wp_parse_url( $referer, PHP_URL_PATH ); 2571 $is_site_creation = false !== strpos( $referer_path, 'wp-admin/my-sites.php' ); 2572 } 2573 2574 if ( $is_site_creation ) { 2575 if ( bp_is_active( 'blogs' ) ) { 2576 $redirect_to = trailingslashit( bp_get_blogs_directory_permalink() . 'create' ); 2577 } else { 2578 // Perform no redirect in this case. 2579 $redirect_to = ''; 2580 } 2581 } 2582 2583 if ( ! $redirect_to ) { 2584 return; 2585 } 2586 2587 bp_core_redirect( $redirect_to ); 2588 } 2589 add_action( 'bp_init', 'bp_core_wpsignup_redirect' ); 2590 2591 /** 2592 * Stop a logged-in user who is marked as a spammer. 2593 * 2594 * When an admin marks a live user as a spammer, that user can still surf 2595 * around and cause havoc on the site until that person is logged out. 2596 * 2597 * This code checks to see if a logged-in user is marked as a spammer. If so, 2598 * we redirect the user back to wp-login.php with the 'reauth' parameter. 2599 * 2600 * This clears the logged-in spammer's cookies and will ask the spammer to 2601 * reauthenticate. 2602 * 2603 * Note: A spammer cannot log back in - {@see bp_core_boot_spammer()}. 2604 * 2605 * Runs on 'bp_init' at priority 5 so the members component globals are setup 2606 * before we do our spammer checks. 2607 * 2608 * This is important as the $bp->loggedin_user object is setup at priority 4. 2609 * 2610 * @since 1.8.0 2611 */ 2612 function bp_stop_live_spammer() { 2613 // If we're on the login page, stop now to prevent redirect loop. 2614 $is_login = false; 2615 if ( isset( $GLOBALS['pagenow'] ) && ( false !== strpos( $GLOBALS['pagenow'], 'wp-login.php' ) ) ) { 2616 $is_login = true; 2617 } elseif ( isset( $_SERVER['SCRIPT_NAME'] ) && false !== strpos( $_SERVER['SCRIPT_NAME'], 'wp-login.php' ) ) { 2618 $is_login = true; 2619 } 2620 2621 if ( $is_login ) { 2622 return; 2623 } 2624 2625 // User isn't logged in, so stop! 2626 if ( ! is_user_logged_in() ) { 2627 return; 2628 } 2629 2630 // If spammer, redirect to wp-login.php and reauthorize. 2631 if ( bp_is_user_spammer( bp_loggedin_user_id() ) ) { 2632 // Setup login args. 2633 $args = array( 2634 // Custom action used to throw an error message. 2635 'action' => 'bp-spam', 2636 2637 // Reauthorize user to login. 2638 'reauth' => 1 2639 ); 2640 2641 /** 2642 * Filters the url used for redirection for a logged in user marked as spam. 2643 * 2644 * @since 1.8.0 2645 * 2646 * @param string $value URL to redirect user to. 2647 */ 2648 $login_url = apply_filters( 'bp_live_spammer_redirect', add_query_arg( $args, wp_login_url() ) ); 2649 2650 // Redirect user to login page. 2651 wp_redirect( $login_url ); 2652 die(); 2653 } 2654 } 2655 add_action( 'bp_init', 'bp_stop_live_spammer', 5 ); 2656 2657 /** 2658 * Show a custom error message when a logged-in user is marked as a spammer. 2659 * 2660 * @since 1.8.0 2661 */ 2662 function bp_live_spammer_login_error() { 2663 global $error; 2664 2665 $error = __( '<strong>Error</strong>: Your account has been marked as a spammer.', 'buddypress' ); 2666 2667 // Shake shake shake! 2668 add_action( 'login_head', 'wp_shake_js', 12 ); 2669 } 2670 add_action( 'login_form_bp-spam', 'bp_live_spammer_login_error' ); 2671 2672 /** 2673 * Get the displayed user Object 2674 * 2675 * @since 2.6.0 2676 * 2677 * @global BuddyPress $bp The one true BuddyPress instance. 2678 * 2679 * @return object The displayed user object, null otherwise. 2680 */ 2681 function bp_get_displayed_user() { 2682 $bp = buddypress(); 2683 2684 $displayed_user = null; 2685 if ( ! empty( $bp->displayed_user->id ) ) { 2686 $displayed_user = $bp->displayed_user; 2687 } 2688 2689 /** 2690 * Filters the displayed_user object corresponding to the displayed member. 2691 * 2692 * @since 2.6.0 2693 * 2694 * @param object $displayed_user The displayed_user object. 2695 */ 2696 return apply_filters( 'bp_get_displayed_user', $displayed_user ); 2697 } 2698 2699 /** Member Types *************************************************************/ 2700 2701 /** 2702 * Output the slug of the member type taxonomy. 2703 * 2704 * @since 2.7.0 2705 */ 2706 function bp_member_type_tax_name() { 2707 echo bp_get_member_type_tax_name(); 2708 } 2709 /** 2710 * Return the slug of the member type taxonomy. 2711 * 2712 * @since 2.7.0 2713 * 2714 * @return string The unique member taxonomy slug. 2715 */ 2716 function bp_get_member_type_tax_name() { 2717 2718 /** 2719 * Filters the slug of the member type taxonomy. 2720 * 2721 * @since 2.7.0 2722 * 2723 * @param string $value Member type taxonomy slug. 2724 */ 2725 return apply_filters( 'bp_get_member_type_tax_name', 'bp_member_type' ); 2726 } 2727 2728 /** 2729 * Returns labels used by the member type taxonomy. 2730 * 2731 * @since 7.0.0 2732 * 2733 * @return array 2734 */ 2735 function bp_get_member_type_tax_labels() { 2736 2737 /** 2738 * Filters Member type taxonomy labels. 2739 * 2740 * @since 7.0.0 2741 * 2742 * @param array $value Associative array (name => label). 2743 */ 2744 return apply_filters( 2745 'bp_get_member_type_tax_labels', 2746 array( 2747 // General labels. 2748 'name' => _x( 'Member Types', 'Member type taxonomy name', 'buddypress' ), 2749 'singular_name' => _x( 'Member Type', 'Member type taxonomy singular name', 'buddypress' ), 2750 'search_items' => _x( 'Search Member Types', 'Member type taxonomy search items label', 'buddypress' ), 2751 'popular_items' => _x( 'Popular Member Types', 'Member type taxonomy popular items label', 'buddypress' ), 2752 'all_items' => _x( 'All Member Types', 'Member type taxonomy all items label', 'buddypress' ), 2753 'parent_item' => _x( 'Parent Member Type', 'Member type taxonomy parent item label', 'buddypress' ), 2754 'parent_item_colon' => _x( 'Parent Member Type:', 'Member type taxonomy parent item label', 'buddypress' ), 2755 'edit_item' => _x( 'Edit Member Type', 'Member type taxonomy edit item label', 'buddypress' ), 2756 'view_item' => _x( 'View Member Type', 'Member type taxonomy view item label', 'buddypress' ), 2757 'update_item' => _x( 'Update Member Type', 'Member type taxonomy update item label', 'buddypress' ), 2758 'add_new_item' => _x( 'Add New Member Type', 'Member type taxonomy add new item label', 'buddypress' ), 2759 'new_item_name' => _x( 'New Member Type Name', 'Member type taxonomy new item name label', 'buddypress' ), 2760 'separate_items_with_commas' => _x( 'Separate member types with commas', 'Member type taxonomy separate items with commas label', 'buddypress' ), 2761 'add_or_remove_items' => _x( 'Add or remove member types', 'Member type taxonomy add or remove items label', 'buddypress' ), 2762 'choose_from_most_used' => _x( 'Choose from the most used meber types', 'Member type taxonomy choose from most used label', 'buddypress' ), 2763 'not_found' => _x( 'No member types found.', 'Member type taxonomy not found label', 'buddypress' ), 2764 'no_terms' => _x( 'No member types', 'Member type taxonomy no terms label', 'buddypress' ), 2765 'items_list_navigation' => _x( 'Member Types list navigation', 'Member type taxonomy items list navigation label', 'buddypress' ), 2766 'items_list' => _x( 'Member Types list', 'Member type taxonomy items list label', 'buddypress' ), 2767 2768 /* translators: Tab heading when selecting from the most used terms. */ 2769 'most_used' => _x( 'Most Used', 'Member type taxonomy most used items label', 'buddypress' ), 2770 'back_to_items' => _x( '← Back to Member Types', 'Member type taxonomy back to items label', 'buddypress' ), 2771 2772 // Specific to BuddyPress. 2773 'bp_type_id_label' => _x( 'Member Type ID', 'BP Member type ID label', 'buddypress' ), 2774 'bp_type_id_description' => _x( 'Enter a lower-case string without spaces or special characters (used internally to identify the member type).', 'BP Member type ID description', 'buddypress' ), 2775 'bp_type_show_in_list' => _x( 'Show on Member', 'BP Member type show in list', 'buddypress' ), 2776 ) 2777 ); 2778 } 2779 2780 /** 2781 * Returns arguments used by the Member type taxonomy. 2782 * 2783 * @since 7.0.0 2784 * 2785 * @return array 2786 */ 2787 function bp_get_member_type_tax_args() { 2788 2789 /** 2790 * Filters Member type taxonomy args. 2791 * 2792 * @since 7.0.0 2793 * 2794 * @param array $value Associative array (key => arg). 2795 */ 2796 return apply_filters( 2797 'bp_get_member_type_tax_args', 2798 array_merge( 2799 array( 2800 'description' => _x( 'BuddyPress Member Types', 'Member type taxonomy description', 'buddypress' ), 2801 'labels' => array_merge( bp_get_member_type_tax_labels(), bp_get_taxonomy_common_labels() ), 2802 ), 2803 bp_get_taxonomy_common_args() 2804 ) 2805 ); 2806 } 2807 2808 /** 2809 * Extend generic Type metadata schema to match Member Type needs. 2810 * 2811 * @since 7.0.0 2812 * 2813 * @param array $schema The generic Type metadata schema. 2814 * @param string $taxonomy The taxonomy name the schema applies to. 2815 * @return array The Member Type metadata schema. 2816 */ 2817 function bp_get_member_type_metadata_schema( $schema = array(), $taxonomy = '' ) { 2818 if ( bp_get_member_type_tax_name() === $taxonomy ) { 2819 2820 // Directory. 2821 if ( isset( $schema['bp_type_has_directory']['description'] ) ) { 2822 $schema['bp_type_has_directory']['description'] = __( 'Make a list of members matching this type available on the members directory.', 'buddypress' ); 2823 } 2824 2825 // Slug. 2826 if ( isset( $schema['bp_type_directory_slug']['description'] ) ) { 2827 $schema['bp_type_directory_slug']['description'] = __( 'Enter if you want the type slug to be different from its ID.', 'buddypress' ); 2828 } 2829 2830 // List. 2831 $schema['bp_type_show_in_list'] = array( 2832 'description' => __( 'Show where member types may be listed, like in the member header.', 'buddypress' ), 2833 'type' => 'boolean', 2834 'single' => true, 2835 'sanitize_callback' => 'absint', 2836 ); 2837 } 2838 2839 return $schema; 2840 } 2841 add_filter( 'bp_get_type_metadata_schema', 'bp_get_member_type_metadata_schema', 1, 2 ); 2842 2843 /** 2844 * Registers the Member type metadata. 2845 * 2846 * @since 7.0.0 2847 */ 2848 function bp_register_member_type_metadata() { 2849 $type_taxonomy = bp_get_member_type_tax_name(); 2850 2851 foreach ( bp_get_type_metadata_schema( false, $type_taxonomy ) as $meta_key => $meta_args ) { 2852 bp_register_type_meta( $type_taxonomy, $meta_key, $meta_args ); 2853 } 2854 } 2855 add_action( 'bp_register_type_metadata', 'bp_register_member_type_metadata' ); 2856 2857 /** 2858 * Register a member type. 2859 * 2860 * @since 2.2.0 2861 * 2862 * @global BuddyPress $bp The one true BuddyPress instance. 2863 * 2864 * @param string $member_type Unique string identifier for the member type. 2865 * @param array $args { 2866 * Array of arguments describing the member type. 2867 * 2868 * @type array $labels { 2869 * Array of labels to use in various parts of the interface. 2870 * 2871 * @type string $name Default name. Should typically be plural. 2872 * @type string $singular_name Singular name. 2873 * } 2874 * @type bool|string $has_directory Whether the member type should have its own type-specific directory. 2875 * Pass `true` to use the `$member_type` string as the type's slug. 2876 * Pass a string to customize the slug. Pass `false` to disable. 2877 * Default: true. 2878 * @type bool $show_in_list Whether this member type should be shown in lists rendered by 2879 * bp_member_type_list(). Default: false. 2880 * @type bool $code Whether this member type is registered using code. Default: true. 2881 * @type int $db_id The member type term ID. Default: 0. 2882 * } 2883 * @return object|WP_Error Member type object on success, WP_Error object on failure. 2884 */ 2885 function bp_register_member_type( $member_type, $args = array() ) { 2886 $bp = buddypress(); 2887 2888 if ( isset( $bp->members->types[ $member_type ] ) ) { 2889 return new WP_Error( 'bp_member_type_exists', __( 'Member type already exists.', 'buddypress' ), $member_type ); 2890 } 2891 2892 $r = bp_parse_args( 2893 $args, 2894 array( 2895 'labels' => array(), 2896 'has_directory' => true, 2897 'show_in_list' => false, 2898 'code' => true, 2899 'db_id' => 0, 2900 ), 2901 'register_member_type' 2902 ); 2903 2904 $member_type = sanitize_key( $member_type ); 2905 2906 /** 2907 * Filters the list of illegal member type names. 2908 * 2909 * - 'any' is a special pseudo-type, representing items unassociated with any member type. 2910 * - 'null' is a special pseudo-type, representing users without any type. 2911 * - '_none' is used internally to denote an item that should not apply to any member types. 2912 * 2913 * @since 2.4.0 2914 * 2915 * @param array $illegal_names Array of illegal names. 2916 */ 2917 $illegal_names = apply_filters( 'bp_member_type_illegal_names', array( 'any', 'null', '_none' ) ); 2918 if ( in_array( $member_type, $illegal_names, true ) ) { 2919 return new WP_Error( 'bp_member_type_illegal_name', __( 'You may not register a member type with this name.', 'buddypress' ), $member_type ); 2920 } 2921 2922 // Store the post type name as data in the object (not just as the array key). 2923 $r['name'] = $member_type; 2924 2925 // Make sure the relevant labels have been filled in. 2926 $default_name = isset( $r['labels']['name'] ) ? $r['labels']['name'] : ucfirst( $r['name'] ); 2927 $r['labels'] = array_merge( array( 2928 'name' => $default_name, 2929 'singular_name' => $default_name, 2930 ), $r['labels'] ); 2931 2932 // Directory slug. 2933 if ( $r['has_directory'] ) { 2934 // A string value is intepreted as the directory slug. Otherwise fall back on member type. 2935 if ( is_string( $r['has_directory'] ) ) { 2936 $directory_slug = $r['has_directory']; 2937 } else { 2938 $directory_slug = $member_type; 2939 } 2940 2941 // Sanitize for use in URLs. 2942 $r['directory_slug'] = sanitize_title( $directory_slug ); 2943 $r['has_directory'] = true; 2944 } else { 2945 $r['directory_slug'] = ''; 2946 $r['has_directory'] = false; 2947 } 2948 2949 // Show the list of member types on front-end (member header, for now). 2950 $r['show_in_list'] = (bool) $r['show_in_list']; 2951 2952 $bp->members->types[ $member_type ] = $type = (object) $r; 2953 2954 /** 2955 * Fires after a member type is registered. 2956 * 2957 * @since 2.2.0 2958 * 2959 * @param string $member_type Member type identifier. 2960 * @param object $type Member type object. 2961 */ 2962 do_action( 'bp_registered_member_type', $member_type, $type ); 2963 2964 return $type; 2965 } 2966 2967 /** 2968 * Retrieve a member type object by name. 2969 * 2970 * @since 2.2.0 2971 * 2972 * @param string $member_type The name of the member type. 2973 * @return object|null A member type object or null if it doesn't exist. 2974 */ 2975 function bp_get_member_type_object( $member_type ) { 2976 $types = bp_get_member_types( array(), 'objects' ); 2977 2978 if ( empty( $types[ $member_type ] ) ) { 2979 return null; 2980 } 2981 2982 return $types[ $member_type ]; 2983 } 2984 2985 /** 2986 * Get a list of all registered member type objects. 2987 * 2988 * @since 2.2.0 2989 * 2990 * @global BuddyPress $bp The one true BuddyPress instance. 2991 * 2992 * @see bp_register_member_type() for accepted arguments. 2993 * 2994 * @param array|string $args Optional. An array of key => value arguments to match against 2995 * the member type objects. Default empty array. 2996 * @param string $output Optional. The type of output to return. Accepts 'names' 2997 * or 'objects'. Default 'names'. 2998 * @param string $operator Optional. The logical operation to perform. 'or' means only one 2999 * element from the array needs to match; 'and' means all elements 3000 * must match. Accepts 'or' or 'and'. Default 'and'. 3001 * @return array A list of member type names or objects. 3002 */ 3003 function bp_get_member_types( $args = array(), $output = 'names', $operator = 'and' ) { 3004 $bp = buddypress(); 3005 $types = $bp->members->types; 3006 3007 // Merge with types available into the database. 3008 if ( ! isset( $args['code'] ) || true !== $args['code'] ) { 3009 $types = bp_get_taxonomy_types( bp_get_member_type_tax_name(), $types ); 3010 } 3011 3012 $types = wp_filter_object_list( $types, $args, $operator ); 3013 3014 /** 3015 * Filters the array of member type objects. 3016 * 3017 * This filter is run before the $output filter has been applied, so that 3018 * filtering functions have access to the entire member type objects. 3019 * 3020 * @since 2.2.0 3021 * 3022 * @param array $types Member type objects, keyed by name. 3023 * @param array $args Array of key=>value arguments for filtering. 3024 * @param string $operator 'or' to match any of $args, 'and' to require all. 3025 */ 3026 $types = apply_filters( 'bp_get_member_types', $types, $args, $operator ); 3027 3028 if ( 'names' === $output ) { 3029 $types = wp_list_pluck( $types, 'name' ); 3030 } 3031 3032 return $types; 3033 } 3034 3035 /** 3036 * Only gets the member types registered by code. 3037 * 3038 * @since 7.0.0 3039 * 3040 * @return array The member types registered by code. 3041 */ 3042 function bp_get_member_types_registered_by_code() { 3043 return bp_get_member_types( 3044 array( 3045 'code' => true, 3046 ), 3047 'objects' 3048 ); 3049 } 3050 add_filter( bp_get_member_type_tax_name() . '_registered_by_code', 'bp_get_member_types_registered_by_code' ); 3051 3052 /** 3053 * Generates missing metadata for a type registered by code. 3054 * 3055 * @since 7.0.0 3056 * 3057 * @return array The member type metadata. 3058 */ 3059 function bp_set_registered_by_code_member_type_metadata( $metadata = array(), $type = '' ) { 3060 $member_type = bp_get_member_type_object( $type ); 3061 3062 foreach ( get_object_vars( $member_type ) as $object_key => $object_value ) { 3063 if ( 'labels' === $object_key ) { 3064 foreach ( $object_value as $label_key => $label_value ) { 3065 $metadata[ 'bp_type_' . $label_key ] = $label_value; 3066 } 3067 } elseif ( ! in_array( $object_key, array( 'name', 'code', 'db_id' ), true ) ) { 3068 $metadata[ 'bp_type_' . $object_key ] = $object_value; 3069 } 3070 } 3071 3072 /** 3073 * Save metadata into database to avoid generating metadata 3074 * each time a type is listed into the Types Admin screen. 3075 */ 3076 if ( isset( $member_type->db_id ) && $member_type->db_id ) { 3077 bp_update_type_metadata( $member_type->db_id, bp_get_member_type_tax_name(), $metadata ); 3078 } 3079 3080 return $metadata; 3081 } 3082 add_filter( bp_get_member_type_tax_name() . '_set_registered_by_code_metada', 'bp_set_registered_by_code_member_type_metadata', 10, 2 ); 3083 3084 /** 3085 * Insert member types registered by code not yet saved into the database as WP Terms. 3086 * 3087 * @since 7.0.0 3088 */ 3089 function bp_insert_member_types_registered_by_code() { 3090 $all_types = bp_get_member_types( array(), 'objects' ); 3091 $unsaved_types = wp_filter_object_list( $all_types, array( 'db_id' => 0 ), 'and', 'name' ); 3092 3093 if ( $unsaved_types ) { 3094 foreach ( $unsaved_types as $type_name ) { 3095 bp_insert_term( 3096 $type_name, 3097 bp_get_member_type_tax_name(), 3098 array( 3099 'slug' => $type_name, 3100 ) 3101 ); 3102 } 3103 } 3104 } 3105 add_action( bp_get_member_type_tax_name() . '_add_form', 'bp_insert_member_types_registered_by_code', 1 ); 3106 3107 /** 3108 * Set type for a member. 3109 * 3110 * @since 2.2.0 3111 * @since 7.0.0 $member_type parameter also accepts an array of member type names. 3112 * 3113 * @param int $user_id ID of the user. 3114 * @param string|array $member_type The member type name or an array of member type names. 3115 * @param bool $append Optional. True to append this to existing types for user, 3116 * false to replace. Default: false. 3117 * @return bool|array $retval See {@see bp_set_object_terms()}. 3118 */ 3119 function bp_set_member_type( $user_id, $member_type, $append = false ) { 3120 // Pass an empty $member_type to remove a user's type. 3121 if ( ! empty( $member_type ) ) { 3122 $member_types = (array) $member_type; 3123 $valid_types = array_filter( array_map( 'bp_get_member_type_object', $member_types ) ); 3124 3125 if ( $valid_types ) { 3126 $member_type = wp_list_pluck( $valid_types, 'name' ); 3127 } else { 3128 return false; 3129 } 3130 } 3131 3132 $retval = bp_set_object_terms( $user_id, $member_type, bp_get_member_type_tax_name(), $append ); 3133 3134 // Bust the cache if the type has been updated. 3135 if ( ! is_wp_error( $retval ) ) { 3136 wp_cache_delete( $user_id, 'bp_member_member_type' ); 3137 3138 /** 3139 * Fires just after a user's member type has been changed. 3140 * 3141 * @since 2.2.0 3142 * 3143 * @param int $user_id ID of the user whose member type has been updated. 3144 * @param string|array $member_type The member type name or an array of member type names. 3145 * @param bool $append Whether the type is being appended to existing types. 3146 */ 3147 do_action( 'bp_set_member_type', $user_id, $member_type, $append ); 3148 } 3149 3150 return $retval; 3151 } 3152 3153 /** 3154 * Remove type for a member. 3155 * 3156 * @since 2.3.0 3157 * 3158 * @param int $user_id ID of the user. 3159 * @param string $member_type Member Type. 3160 * @return bool|WP_Error 3161 */ 3162 function bp_remove_member_type( $user_id, $member_type ) { 3163 // Bail if no valid member type was passed. 3164 if ( empty( $member_type ) || ! bp_get_member_type_object( $member_type ) ) { 3165 return false; 3166 } 3167 3168 // No need to continue if the member doesn't have the type. 3169 $existing_types = bp_get_member_type( $user_id, false ); 3170 if ( ! is_array( $existing_types ) || ! in_array( $member_type, $existing_types, true ) ) { 3171 return false; 3172 } 3173 3174 $deleted = bp_remove_object_terms( $user_id, $member_type, bp_get_member_type_tax_name() ); 3175 3176 // Bust the cache if the type has been removed. 3177 if ( ! is_wp_error( $deleted ) ) { 3178 wp_cache_delete( $user_id, 'bp_member_member_type' ); 3179 3180 /** 3181 * Fires just after a user's member type has been removed. 3182 * 3183 * @since 2.3.0 3184 * 3185 * @param int $user_id ID of the user whose member type has been updated. 3186 * @param string $member_type Member type. 3187 */ 3188 do_action( 'bp_remove_member_type', $user_id, $member_type ); 3189 } 3190 3191 return $deleted; 3192 } 3193 3194 /** 3195 * Get type for a member. 3196 * 3197 * @since 2.2.0 3198 * @since 7.0.0 Adds the `$use_db` parameter. 3199 * 3200 * @param int $user_id ID of the user. 3201 * @param bool $single Optional. Whether to return a single type string. If multiple types are found 3202 * for the user, the oldest one will be returned. Default: true. 3203 * @param bool $use_db Optional. Whether to request all member types or only the ones registered by code. 3204 * Default: true. 3205 * @return string|array|bool On success, returns a single member type (if $single is true) or an array of member 3206 * types (if $single is false). Returns false on failure. 3207 */ 3208 function bp_get_member_type( $user_id, $single = true, $use_db = true ) { 3209 $types = wp_cache_get( $user_id, 'bp_member_member_type' ); 3210 3211 if ( false === $types ) { 3212 $raw_types = bp_get_object_terms( $user_id, bp_get_member_type_tax_name() ); 3213 3214 if ( ! is_wp_error( $raw_types ) ) { 3215 $types = array(); 3216 3217 // Only include currently registered group types. 3218 foreach ( $raw_types as $mtype ) { 3219 if ( bp_get_member_type_object( $mtype->name ) ) { 3220 $types[] = $mtype->name; 3221 } 3222 } 3223 3224 wp_cache_set( $user_id, $types, 'bp_member_member_type' ); 3225 } 3226 } 3227 3228 if ( false === $use_db && $types ) { 3229 $registred_by_code = bp_get_member_types_registered_by_code(); 3230 $ctype_names = wp_list_pluck( $registred_by_code, 'name' ); 3231 $types = array_intersect( $types, $ctype_names ); 3232 } 3233 3234 $type = false; 3235 if ( ! empty( $types ) ) { 3236 if ( $single ) { 3237 $type = array_pop( $types ); 3238 } else { 3239 $type = $types; 3240 } 3241 } 3242 3243 /** 3244 * Filters a user's member type(s). 3245 * 3246 * @since 2.2.0 3247 * 3248 * @param string|array|bool $type A single member type (if $single is true) or an array of member types 3249 * (if $single is false) or false on failure. 3250 * @param int $user_id ID of the user. 3251 * @param bool $single Whether to return a single type string, or an array. 3252 */ 3253 return apply_filters( 'bp_get_member_type', $type, $user_id, $single ); 3254 } 3255 3256 /** 3257 * Check whether the given user has a certain member type. 3258 * 3259 * @since 2.3.0 3260 * 3261 * @param int $user_id $user_id ID of the user. 3262 * @param string $member_type Member Type. 3263 * @return bool Whether the user has the given member type. 3264 */ 3265 function bp_has_member_type( $user_id, $member_type ) { 3266 // Bail if no valid member type was passed. 3267 if ( empty( $member_type ) || ! bp_get_member_type_object( $member_type ) ) { 3268 return false; 3269 } 3270 3271 // Get all user's member types. 3272 $types = bp_get_member_type( $user_id, false ); 3273 3274 if ( ! is_array( $types ) ) { 3275 return false; 3276 } 3277 3278 return in_array( $member_type, $types, true ); 3279 } 3280 3281 /** 3282 * Delete a user's member type when the user when the user is deleted. 3283 * 3284 * @since 2.2.0 3285 * 3286 * @param int $user_id ID of the user. 3287 * @return bool|array $value See {@see bp_set_member_type()}. 3288 */ 3289 function bp_remove_member_type_on_user_delete( $user_id ) { 3290 return bp_set_member_type( $user_id, '' ); 3291 } 3292 add_action( 'wpmu_delete_user', 'bp_remove_member_type_on_user_delete' ); 3293 3294 /** 3295 * Deletes user member type on the 'delete_user' hook. 3296 * 3297 * @since 6.0.0 3298 * 3299 * @param int $user_id The ID of the deleted user. 3300 */ 3301 function bp_remove_member_type_on_delete_user( $user_id ) { 3302 if ( ! bp_remove_user_data_on_delete_user_hook( 'member_type', $user_id ) ) { 3303 return; 3304 } 3305 3306 bp_remove_member_type_on_user_delete( $user_id ); 3307 } 3308 add_action( 'delete_user', 'bp_remove_member_type_on_delete_user' ); 3309 3310 /** 3311 * Get the "current" member type, if one is provided, in member directories. 3312 * 3313 * @since 2.3.0 3314 * 3315 * @global BuddyPress $bp The one true BuddyPress instance. 3316 * 3317 * @return string 3318 */ 3319 function bp_get_current_member_type() { 3320 $bp = buddypress(); 3321 3322 /** 3323 * Filters the "current" member type, if one is provided, in member directories. 3324 * 3325 * @since 2.3.0 3326 * 3327 * @param string $value "Current" member type. 3328 */ 3329 return apply_filters( 'bp_get_current_member_type', $bp->current_member_type ); 3330 } 3331 3332 /** 3333 * Setup the avatar upload directory for a user. 3334 * 3335 * @since 6.0.0 3336 * 3337 * @param string $directory The root directory name. Optional. 3338 * @param int $user_id The user ID. Optional. 3339 * @return array Array containing the path, URL, and other helpful settings. 3340 */ 3341 function bp_members_avatar_upload_dir( $directory = 'avatars', $user_id = 0 ) { 3342 3343 // Use displayed user if no user ID was passed. 3344 if ( empty( $user_id ) ) { 3345 $user_id = bp_displayed_user_id(); 3346 } 3347 3348 // Failsafe against accidentally nooped $directory parameter. 3349 if ( empty( $directory ) ) { 3350 $directory = 'avatars'; 3351 } 3352 3353 $path = bp_core_avatar_upload_path() . '/' . $directory . '/' . $user_id; 3354 $newbdir = $path; 3355 $newurl = bp_core_avatar_url() . '/' . $directory . '/' . $user_id; 3356 $newburl = $newurl; 3357 $newsubdir = '/' . $directory . '/' . $user_id; 3358 3359 /** 3360 * Filters the avatar upload directory for a user. 3361 * 3362 * @since 6.0.0 3363 * 3364 * @param array $value Array containing the path, URL, and other helpful settings. 3365 */ 3366 return apply_filters( 'bp_members_avatar_upload_dir', array( 3367 'path' => $path, 3368 'url' => $newurl, 3369 'subdir' => $newsubdir, 3370 'basedir' => $newbdir, 3371 'baseurl' => $newburl, 3372 'error' => false, 3373 ) ); 3374 } 3375 3376 /** 3377 * Send welcome email on successful user activation. 3378 * 3379 * @since 8.0.0 3380 * 3381 * @param int $user_id The new user's ID. 3382 */ 3383 function bp_send_welcome_email( $user_id = 0 ) { 3384 if ( ! $user_id ) { 3385 return; 3386 } 3387 3388 $profile_url = bp_core_get_user_domain( $user_id ); 3389 3390 /** 3391 * Use this filter to add/edit/remove tokens to use for your welcome email. 3392 * 3393 * @since 8.0.0 3394 * 3395 * @param array $value An array of BP Email tokens. 3396 * @param int $user_id The user ID. 3397 */ 3398 $welcome_tokens = apply_filters( 3399 'bp_send_welcome_email_tokens', 3400 array( 3401 'displayname' => bp_core_get_user_displayname( $user_id ), 3402 'profile.url' => $profile_url, 3403 'lostpassword.url' => wp_lostpassword_url( $profile_url ), 3404 ), 3405 $user_id 3406 ); 3407 3408 bp_send_email( 'core-user-activation', $user_id, array( 'tokens' => $welcome_tokens ) ); 3409 } 3410 add_action( 'bp_core_activated_user', 'bp_send_welcome_email', 10, 1 ); 3411 3412 /** 3413 * Get invitations to the BP community filtered by arguments. 3414 * 3415 * @since 8.0.0 3416 * 3417 * @param array $args Invitation arguments. See BP_Invitation::get() for list. 3418 * @return array $invites Matching BP_Invitation objects. 3419 */ 3420 function bp_members_invitations_get_invites( $args = array() ) { 3421 $invites_class = new BP_Members_Invitation_Manager(); 3422 return $invites_class->get_invitations( $args ); 3423 } 3424 3425 /** 3426 * Check whether a user has sent any community invitations. 3427 * 3428 * @since 8.0.0 3429 * 3430 * @param int $user_id ID of user to check for invitations sent by. 3431 * Defaults to the current user's ID. 3432 * 3433 * @return bool $invites True if user has sent invites. 3434 */ 3435 function bp_members_invitations_user_has_sent_invites( $user_id = 0 ) { 3436 if ( 0 === $user_id ) { 3437 $user_id = bp_loggedin_user_id(); 3438 if ( ! $user_id ) { 3439 return false; 3440 } 3441 } 3442 $invites_class = new BP_Members_Invitation_Manager(); 3443 $args = array( 3444 'inviter_id' => $user_id, 3445 ); 3446 return (bool) $invites_class->invitation_exists( $args ); 3447 } 3448 3449 /** 3450 * Invite a user to a BP community. 3451 * 3452 * @since 8.0.0 3453 * 3454 * @param array|string $args { 3455 * Array of arguments. 3456 * @type int $invitee_email Email address of the user being invited. 3457 * @type int $network_id ID of the network to which the user is being invited. 3458 * @type int $inviter_id Optional. ID of the inviting user. Default: 3459 * ID of the logged-in user. 3460 * @type string $date_modified Optional. Modified date for the invitation. 3461 * Default: current date/time. 3462 * @type string $content Optional. Message to invitee. 3463 * @type bool $send_invite Optional. Whether the invitation should be 3464 * sent now. Default: false. 3465 * } 3466 * @return bool True on success, false on failure. 3467 */ 3468 function bp_members_invitations_invite_user( $args = array() ) { 3469 $r = bp_parse_args( 3470 $args, 3471 array( 3472 'invitee_email' => '', 3473 'network_id' => get_current_network_id(), 3474 'inviter_id' => bp_loggedin_user_id(), 3475 'date_modified' => bp_core_current_time(), 3476 'content' => '', 3477 'send_invite' => 0, 3478 ), 3479 'members_invitations_invite_user' 3480 ); 3481 3482 $inv_args = array( 3483 'invitee_email' => $r['invitee_email'], 3484 'item_id' => $r['network_id'], 3485 'inviter_id' => $r['inviter_id'], 3486 'date_modified' => $r['date_modified'], 3487 'content' => $r['content'], 3488 'send_invite' => $r['send_invite'], 3489 ); 3490 3491 // Create the invitataion. 3492 $invites_class = new BP_Members_Invitation_Manager(); 3493 $created = $invites_class->add_invitation( $inv_args ); 3494 3495 /** 3496 * Fires after the creation of a new network invite. 3497 * 3498 * @since 8.0.0 3499 * 3500 * @param array $r Array of parsed arguments for the network invite. 3501 * @param int|bool $created The ID of the invitation or false if it couldn't be created. 3502 */ 3503 do_action( 'bp_members_invitations_invite_user', $r, $created ); 3504 3505 return $created; 3506 } 3507 3508 /** 3509 * Resend a membership invitation email by id. 3510 * 3511 * @since 8.0.0 3512 * 3513 * @param int $id ID of the invitation to resend. 3514 * @return bool True on success, false on failure. 3515 */ 3516 function bp_members_invitation_resend_by_id( $id = 0 ) { 3517 3518 // Find the invitation before resending it. 3519 $existing_invite = new BP_Invitation( $id ); 3520 $invites_class = new BP_Members_Invitation_Manager(); 3521 $success = $invites_class->send_invitation_by_id( $id ); 3522 3523 if ( ! $success ) { 3524 return $success; 3525 } 3526 3527 /** 3528 * Fires after the re-sending of a network invite. 3529 * 3530 * @since 8.0.0 3531 * 3532 * @param BP_Invitation $existing_invite The invitation that was resent. 3533 */ 3534 do_action( 'bp_members_invitations_resend_invitation', $existing_invite ); 3535 3536 return $success; 3537 } 3538 3539 /** 3540 * Delete a membership invitation by id. 3541 * 3542 * @since 8.0.0 3543 * 3544 * @param int $id ID of the invitation to delete. 3545 * @return int|bool Number of rows deleted on success, false on failure. 3546 */ 3547 function bp_members_invitations_delete_by_id( $id = 0 ) { 3548 3549 // Find the invitation before deleting it. 3550 $existing_invite = new BP_Invitation( $id ); 3551 $invites_class = new BP_Members_Invitation_Manager(); 3552 $success = $invites_class->delete_by_id( $id ); 3553 3554 if ( ! $success ) { 3555 return $success; 3556 } 3557 3558 // Run a different action depending on the status of the invite. 3559 if ( ! $existing_invite->invite_sent ) { 3560 /** 3561 * Fires after the deletion of an unsent community invite. 3562 * 3563 * @since 8.0.0 3564 * 3565 * @param BP_Invitation $existing_invite The invitation to be deleted. 3566 */ 3567 do_action( 'bp_members_invitations_canceled_invitation', $existing_invite ); 3568 } else if ( ! $existing_invite->accepted ) { 3569 /** 3570 * Fires after the deletion of a sent, but not yet accepted, community invite. 3571 * 3572 * @since 8.0.0 3573 * 3574 * @param BP_Invitation $existing_invite The invitation to be deleted. 3575 */ 3576 do_action( 'bp_members_invitations_revoked_invitation', $existing_invite ); 3577 } else { 3578 /** 3579 * Fires after the deletion of a sent and accepted community invite. 3580 * 3581 * @since 8.0.0 3582 * 3583 * @param BP_Invitation $existing_invite The invitation to be deleted. 3584 */ 3585 do_action( 'bp_members_invitations_deleted_invitation', $existing_invite ); 3586 } 3587 3588 return $success; 3589 } 3590 3591 /** 3592 * Delete a membership invitation. 3593 * 3594 * @since 8.0.0 3595 * 3596 * @param intring $args { 3597 * Array of arguments. 3598 * @type int|array $id Id(s) of the invitation(s) to remove. 3599 * @type int $invitee_email Email address of the user being invited. 3600 * @type int $network_id ID of the network to which the user is being invited. 3601 * @type int $inviter_id ID of the inviting user. 3602 * @type int $accepted Whether the invitation has been accepted yet. 3603 * @type int $invite_sent Whether the invitation has been sent yet. 3604 * } 3605 * @return bool True if all were deleted. 3606 */ 3607 function bp_members_invitations_delete_invites( $args = array() ) { 3608 $r = bp_parse_args( 3609 $args, 3610 array( 3611 'id' => false, 3612 'invitee_email' => '', 3613 'network_id' => get_current_network_id(), 3614 'inviter_id' => null, 3615 'accepted' => null, 3616 'invite_sent' => null, 3617 ), 3618 'members_invitations_delete_invites' 3619 ); 3620 3621 $inv_args = array( 3622 'id' => $r['id'], 3623 'invitee_email' => $r['invitee_email'], 3624 'item_id' => $r['network_id'], 3625 'inviter_id' => $r['inviter_id'], 3626 'accepted' => $r['accepted'], 3627 'invite_sent' => $r['invite_sent'], 3628 ); 3629 3630 // Find the invitation(s). 3631 $invites = bp_members_invitations_get_invites( $inv_args ); 3632 $total_count = count( $invites ); 3633 3634 // Loop through, deleting each invitation. 3635 $deleted = 0; 3636 foreach ( $invites as $invite ) { 3637 $success = bp_members_invitations_delete_by_id( $invite->id ); 3638 if ( $success ) { 3639 $deleted++; 3640 } 3641 } 3642 3643 return $deleted === $total_count; 3644 } 3645 3646 /** 3647 * Get hash based on details of a membership invitation and the inviter. 3648 * 3649 * @since 8.0.0 3650 * 3651 * @param BP_Invitation $invitation Invitation to create hash from. 3652 * 3653 * @return string $hash Calculated sha1 hash. 3654 */ 3655 function bp_members_invitations_get_hash( $invitation ) { 3656 $hash = false; 3657 3658 if ( ! empty( $invitation->id ) ) { 3659 $inviter_ud = get_userdata( $invitation->inviter_id ); 3660 if ( $inviter_ud ) { 3661 /* 3662 * Use some inviter details as part of the hash so that invitations from 3663 * users who are subsequently marked as spam will be invalidated. 3664 */ 3665 $hash = wp_hash( "{$invitation->inviter_id}:{$invitation->invitee_email}:{$inviter_ud->user_status}:{$inviter_ud->user_registered}" ); 3666 } 3667 } 3668 3669 // If there's a problem, return a string that will change and thus fail. 3670 if ( ! $hash ) { 3671 $hash = wp_generate_password( 32, false ); 3672 } 3673 3674 /** 3675 * Filters the hash calculated by the invitation details. 3676 * 3677 * @since 8.0.0 3678 * 3679 * @param string $hash Calculated sha1 hash. 3680 * @param BP_Invitation $invitation Invitation hash was created from. 3681 */ 3682 return apply_filters( 'bp_members_invitations_get_hash', $hash, $invitation ); 3683 } 3684 3685 /** 3686 * Get the current invitation specified by the $_GET parameters. 3687 * 3688 * @since 8.0.0 3689 * 3690 * @return BP_Invitation $invite Invitation specified by the $_GET parameters. 3691 */ 3692 function bp_get_members_invitation_from_request() { 3693 $invites_class = new BP_Members_Invitation_Manager(); 3694 $invite = $invites_class->get_by_id( 0 ); 3695 3696 if ( bp_get_members_invitations_allowed() && ! empty( $_GET['inv'] ) ) { 3697 // Check to make sure the passed hash matches a calculated hash. 3698 $maybe_invite = $invites_class->get_by_id( absint( $_GET['inv'] ) ); 3699 $hash = bp_members_invitations_get_hash( $maybe_invite ); 3700 3701 if ( $_GET['ih'] === $hash ) { 3702 $invite = $maybe_invite; 3703 } 3704 } 3705 3706 /** 3707 * Filters the invitation specified by the $_GET parameters. 3708 * 3709 * @since 8.0.0 3710 * 3711 * @param BP_Invitation $invite Invitation specified by the $_GET parameters. 3712 */ 3713 return apply_filters( 'bp_get_members_invitation_from_request', $invite ); 3714 } 3715 3716 /** 3717 * Get WP_User object corresponding to a record in the signups table. 3718 * 3719 * @since 10.0.0 3720 * 3721 * @param string $field Which fields to search by. Possible values are 3722 * activation_key, user_email, id. 3723 * @param string $value Value to search by. 3724 * @return bool|BP_Signup $signup Found signup, returns first found 3725 * if more than one is found. 3726 */ 3727 function bp_members_get_signup_by( $field = 'activation_key', $value = '' ) { 3728 switch ( $field ) { 3729 case 'activation_key': 3730 case 'user_email': 3731 $key = $field; 3732 break; 3733 3734 case 'id': 3735 default: 3736 $key = 'include'; 3737 break; 3738 } 3739 3740 $signups = BP_Signup::get( 3741 array( 3742 $key => $value, 3743 ) 3744 ); 3745 3746 if ( ! empty( $signups['signups'] ) ) { 3747 $signup = current( $signups['signups'] ); 3748 } else { 3749 $signup = false; 3750 } 3751 3752 return $signup; 3753 } 3754 3755 /** 3756 * Are site creation requests currently enabled? 3757 * 3758 * @since 10.0.0 3759 * 3760 * @return bool Whether site requests are currently enabled. 3761 */ 3762 function bp_members_site_requests_enabled() { 3763 3764 $matches = array( 'blog', 'all' ); 3765 3766 return is_multisite() && in_array( bp_core_get_root_option( 'registration' ), $matches, true ); 3767 } 3768 3769 /** 3770 * Returns the strength score a password needs to have to be used by a member. 3771 * 3772 * Score => Allowed Strength. 3773 * 0 => any passwords. 3774 * 1 => at least short passwords. 3775 * 2 => at least weak passwords. 3776 * 3 => at least good passwords. 3777 * 4 => at least strong passwords. 3778 * 3779 * @since 10.0.0 3780 * 3781 * @return int the strength score a password needs to have to be used by a member. 3782 */ 3783 function bp_members_user_pass_required_strength() { 3784 $default_strength = 0; 3785 if ( defined( 'BP_MEMBERS_REQUIRED_PASSWORD_STRENGTH' ) && BP_MEMBERS_REQUIRED_PASSWORD_STRENGTH ) { 3786 $default_strength = (int) BP_MEMBERS_REQUIRED_PASSWORD_STRENGTH; 3787 } 3788 3789 /** 3790 * Filter here to raise the strength score user passwords need to reach to be allowed. 3791 * 3792 * @since 10.0.0 3793 * 3794 * @param int $default_strength The strength score user passwords need to reach to be allowed. 3795 */ 3796 return (int) apply_filters( 'bp_members_user_pass_required_strength', $default_strength ); 3797 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Dec 22 01:00:54 2024 | Cross-referenced by PHPXref 0.7.1 |