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


Generated: Fri Oct 30 01:01:33 2020 Cross-referenced by PHPXref 0.7.1