[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-members/ -> bp-members-functions.php (source)

   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( '&larr; 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  }


Generated: Tue Mar 19 01:01:09 2024 Cross-referenced by PHPXref 0.7.1