[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * BuddyPress Friends Classes. 4 * 5 * @package BuddyPress 6 * @subpackage FriendsFriendship 7 * @since 1.0.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 /** 14 * BuddyPress Friendship object. 15 * 16 * @since 1.0.0 17 */ 18 class BP_Friends_Friendship { 19 20 /** 21 * ID of the friendship. 22 * 23 * @since 1.0.0 24 * @var int 25 */ 26 public $id; 27 28 /** 29 * User ID of the friendship initiator. 30 * 31 * @since 1.0.0 32 * @var int 33 */ 34 public $initiator_user_id; 35 36 /** 37 * User ID of the 'friend' - the one invited to the friendship. 38 * 39 * @since 1.0.0 40 * @var int 41 */ 42 public $friend_user_id; 43 44 /** 45 * Has the friendship been confirmed/accepted? 46 * 47 * @since 1.0.0 48 * @var int 49 */ 50 public $is_confirmed; 51 52 /** 53 * Is this a "limited" friendship? 54 * 55 * Not currently used by BuddyPress. 56 * 57 * @since 1.0.0 58 * @var int 59 */ 60 public $is_limited; 61 62 /** 63 * Date the friendship was created. 64 * 65 * @since 1.0.0 66 * @var string 67 */ 68 public $date_created; 69 70 /** 71 * Is this a request? 72 * 73 * Not currently used in BuddyPress. 74 * 75 * @since 1.0.0 76 * @var bool 77 */ 78 public $is_request; 79 80 /** 81 * Should additional friend details be queried? 82 * 83 * @since 1.0.0 84 * @var bool 85 */ 86 public $populate_friend_details; 87 88 /** 89 * Details about the friend. 90 * 91 * @since 1.0.0 92 * @var BP_Core_User 93 */ 94 public $friend; 95 96 /** 97 * Constructor method. 98 * 99 * @since 1.5.0 100 * @since 10.0.0 Updated to add deprecated notice for `$is_request`. 101 * 102 * @param int|null $id Optional. The ID of an existing friendship. 103 * @param bool $is_request Deprecated. 104 * @param bool $populate_friend_details Optional. True if friend details should be queried. 105 */ 106 public function __construct( $id = null, $is_request = false, $populate_friend_details = true ) { 107 108 if ( false !== $is_request ) { 109 _deprecated_argument( 110 __METHOD__, 111 '1.5.0', 112 sprintf( 113 /* translators: 1: the name of the method. 2: the name of the file. */ 114 esc_html__( '%1$s no longer accepts $is_request. See the inline documentation at %2$s for more details.', 'buddypress' ), 115 __METHOD__, 116 __FILE__ 117 ) 118 ); 119 } 120 121 $this->is_request = $is_request; 122 123 if ( ! empty( $id ) ) { 124 $this->id = (int) $id; 125 $this->populate_friend_details = $populate_friend_details; 126 $this->populate( $this->id ); 127 } 128 } 129 130 /** 131 * Set up data about the current friendship. 132 * 133 * @since 1.0.0 134 * 135 * @global BuddyPress $bp The one true BuddyPress instance. 136 * @global wpdb $wpdb WordPress database object. 137 */ 138 public function populate() { 139 global $wpdb; 140 141 $bp = buddypress(); 142 143 // Check cache for friendship data. 144 $friendship = wp_cache_get( $this->id, 'bp_friends_friendships' ); 145 146 // Cache missed, so query the DB. 147 if ( false === $friendship ) { 148 $friendship = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$bp->friends->table_name} WHERE id = %d", $this->id ) ); 149 150 wp_cache_set( $this->id, $friendship, 'bp_friends_friendships' ); 151 } 152 153 // No friendship found so set the ID and bail. 154 if ( empty( $friendship ) || is_wp_error( $friendship ) ) { 155 $this->id = 0; 156 return; 157 } 158 159 $this->initiator_user_id = (int) $friendship->initiator_user_id; 160 $this->friend_user_id = (int) $friendship->friend_user_id; 161 $this->is_confirmed = (int) $friendship->is_confirmed; 162 $this->is_limited = (int) $friendship->is_limited; 163 $this->date_created = $friendship->date_created; 164 165 if ( ! empty( $this->populate_friend_details ) ) { 166 if ( bp_displayed_user_id() === $this->friend_user_id ) { 167 $this->friend = new BP_Core_User( $this->initiator_user_id ); 168 } else { 169 $this->friend = new BP_Core_User( $this->friend_user_id ); 170 } 171 } 172 } 173 174 /** 175 * Save the current friendship to the database. 176 * 177 * @since 1.0.0 178 * 179 * @global BuddyPress $bp The one true BuddyPress instance. 180 * @global wpdb $wpdb WordPress database object. 181 * 182 * @return bool True on success, false on failure. 183 */ 184 public function save() { 185 global $wpdb; 186 187 $bp = buddypress(); 188 189 $this->initiator_user_id = apply_filters( 'friends_friendship_initiator_user_id_before_save', $this->initiator_user_id, $this->id ); 190 $this->friend_user_id = apply_filters( 'friends_friendship_friend_user_id_before_save', $this->friend_user_id, $this->id ); 191 $this->is_confirmed = apply_filters( 'friends_friendship_is_confirmed_before_save', $this->is_confirmed, $this->id ); 192 $this->is_limited = apply_filters( 'friends_friendship_is_limited_before_save', $this->is_limited, $this->id ); 193 $this->date_created = apply_filters( 'friends_friendship_date_created_before_save', $this->date_created, $this->id ); 194 195 /** 196 * Fires before processing and saving the current friendship request. 197 * 198 * @since 1.0.0 199 * 200 * @param BP_Friends_Friendship $value Current friendship object. Passed by reference. 201 */ 202 do_action_ref_array( 'friends_friendship_before_save', array( &$this ) ); 203 204 // Update. 205 if ( ! empty( $this->id ) ) { 206 $result = $wpdb->query( $wpdb->prepare( "UPDATE {$bp->friends->table_name} SET initiator_user_id = %d, friend_user_id = %d, is_confirmed = %d, is_limited = %d, date_created = %s WHERE id = %d", $this->initiator_user_id, $this->friend_user_id, $this->is_confirmed, $this->is_limited, $this->date_created, $this->id ) ); 207 208 // Save. 209 } else { 210 $result = $wpdb->query( $wpdb->prepare( "INSERT INTO {$bp->friends->table_name} ( initiator_user_id, friend_user_id, is_confirmed, is_limited, date_created ) VALUES ( %d, %d, %d, %d, %s )", $this->initiator_user_id, $this->friend_user_id, $this->is_confirmed, $this->is_limited, $this->date_created ) ); 211 $this->id = $wpdb->insert_id; 212 } 213 214 /** 215 * Fires after processing and saving the current friendship request. 216 * 217 * @since 1.0.0 218 * 219 * @param BP_Friends_Friendship $value Current friendship object. Passed by reference. 220 */ 221 do_action_ref_array( 'friends_friendship_after_save', array( &$this ) ); 222 223 return $result; 224 } 225 226 /** 227 * Delete the current friendship from the database. 228 * 229 * @since 1.0.0 230 * 231 * @global BuddyPress $bp The one true BuddyPress instance. 232 * @global wpdb $wpdb WordPress database object. 233 * 234 * @return bool|int 235 */ 236 public function delete() { 237 global $wpdb; 238 239 $bp = buddypress(); 240 241 return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE id = %d", $this->id ) ); 242 } 243 244 /** Static Methods ********************************************************/ 245 246 /** 247 * Get the friendships for a given user. 248 * 249 * @since 2.6.0 250 * 251 * @param int $user_id ID of the user whose friends are being retrieved. 252 * @param array $args { 253 * Optional. Filter parameters. 254 * @type int $id ID of specific friendship to retrieve. 255 * @type int $initiator_user_id ID of friendship initiator. 256 * @type int $friend_user_id ID of specific friendship to retrieve. 257 * @type int $is_confirmed Whether the friendship has been accepted. 258 * @type int $is_limited Whether the friendship is limited. 259 * @type string $order_by Column name to order by. 260 * @type string $sort_order Optional. ASC or DESC. Default: 'DESC'. 261 * } 262 * @param string $operator Optional. Operator to use in `wp_list_filter()`. 263 * 264 * @return array $friendships Array of friendship objects. 265 */ 266 public static function get_friendships( $user_id, $args = array(), $operator = 'AND' ) { 267 268 if ( empty( $user_id ) ) { 269 $user_id = bp_loggedin_user_id(); 270 } 271 272 $r = bp_parse_args( 273 $args, 274 array( 275 'id' => null, 276 'initiator_user_id' => null, 277 'friend_user_id' => null, 278 'is_confirmed' => null, 279 'is_limited' => null, 280 'order_by' => 'date_created', 281 'sort_order' => 'DESC', 282 'page' => null, 283 'per_page' => null, 284 ), 285 'bp_get_user_friendships' 286 ); 287 288 // First, we get all friendships that involve the user. 289 $friendship_ids = wp_cache_get( $user_id, 'bp_friends_friendships_for_user' ); 290 if ( false === $friendship_ids ) { 291 $friendship_ids = self::get_friendship_ids_for_user( $user_id ); 292 wp_cache_set( $user_id, $friendship_ids, 'bp_friends_friendships_for_user' ); 293 } 294 295 // Prime the membership cache. 296 $uncached_friendship_ids = bp_get_non_cached_ids( $friendship_ids, 'bp_friends_friendships' ); 297 if ( ! empty( $uncached_friendship_ids ) ) { 298 $uncached_friendships = self::get_friendships_by_id( $uncached_friendship_ids ); 299 300 foreach ( $uncached_friendships as $uncached_friendship ) { 301 wp_cache_set( $uncached_friendship->id, $uncached_friendship, 'bp_friends_friendships' ); 302 } 303 } 304 305 // Assemble filter array. 306 $filters = wp_array_slice_assoc( $r, array( 'id', 'initiator_user_id', 'friend_user_id', 'is_confirmed', 'is_limited' ) ); 307 foreach ( $filters as $filter_name => $filter_value ) { 308 if ( is_null( $filter_value ) ) { 309 unset( $filters[ $filter_name ] ); 310 } 311 } 312 313 // Populate friendship array from cache, and normalize. 314 $friendships = array(); 315 $int_keys = array( 'id', 'initiator_user_id', 'friend_user_id' ); 316 $bool_keys = array( 'is_confirmed', 'is_limited' ); 317 foreach ( $friendship_ids as $friendship_id ) { 318 // Create a limited BP_Friends_Friendship object (don't fetch the user details). 319 $friendship = new BP_Friends_Friendship( $friendship_id, false, false ); 320 321 // Sanity check. 322 if ( ! isset( $friendship->id ) ) { 323 continue; 324 } 325 326 // Integer values. 327 foreach ( $int_keys as $index ) { 328 $friendship->{$index} = intval( $friendship->{$index} ); 329 } 330 331 // Boolean values. 332 foreach ( $bool_keys as $index ) { 333 $friendship->{$index} = (bool) $friendship->{$index}; 334 } 335 336 // We need to support the same operators as wp_list_filter(). 337 if ( 'OR' == $operator || 'NOT' == $operator ) { 338 $matched = 0; 339 340 foreach ( $filters as $filter_name => $filter_value ) { 341 if ( isset( $friendship->{$filter_name} ) && $filter_value == $friendship->{$filter_name} ) { 342 $matched++; 343 } 344 } 345 346 if ( ( 'OR' == $operator && $matched > 0 ) 347 || ( 'NOT' == $operator && 0 == $matched ) ) { 348 $friendships[ $friendship->id ] = $friendship; 349 } 350 351 } else { 352 /* 353 * This is the more typical 'AND' style of filter. 354 * If any of the filters miss, we move on. 355 */ 356 foreach ( $filters as $filter_name => $filter_value ) { 357 if ( ! isset( $friendship->{$filter_name} ) || $filter_value != $friendship->{$filter_name} ) { 358 continue 2; 359 } 360 } 361 $friendships[ $friendship->id ] = $friendship; 362 } 363 364 } 365 366 // Sort the results on a column name. 367 if ( in_array( $r['order_by'], array( 'id', 'initiator_user_id', 'friend_user_id' ) ) ) { 368 $friendships = bp_sort_by_key( $friendships, $r['order_by'], 'num', true ); 369 } 370 371 // Adjust the sort direction of the results. 372 if ( 'ASC' === bp_esc_sql_order( $r['sort_order'] ) ) { 373 // `true` to preserve keys. 374 $friendships = array_reverse( $friendships, true ); 375 } 376 377 // Paginate the results. 378 if ( $r['per_page'] && $r['page'] ) { 379 $start = ( $r['page'] - 1 ) * ( $r['per_page'] ); 380 $friendships = array_slice( $friendships, $start, $r['per_page'] ); 381 } 382 383 return $friendships; 384 } 385 386 /** 387 * Get all friendship IDs for a user. 388 * 389 * @since 2.7.0 390 * 391 * @global BuddyPress $bp The one true BuddyPress instance. 392 * @global wpdb $wpdb WordPress database object. 393 * 394 * @param int $user_id ID of the user. 395 * @return array 396 */ 397 public static function get_friendship_ids_for_user( $user_id ) { 398 global $wpdb; 399 400 $bp = buddypress(); 401 402 $friendship_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d OR friend_user_id = %d) ORDER BY date_created DESC", $user_id, $user_id ) ); 403 404 return $friendship_ids; 405 } 406 407 /** 408 * Get the IDs of a given user's friends. 409 * 410 * @since 1.0.0 411 * 412 * @param int $user_id ID of the user whose friends are being retrieved. 413 * @param bool $friend_requests_only Optional. Whether to fetch 414 * unaccepted requests only. Default: false. 415 * @param bool $assoc_arr Optional. True to receive an array of arrays 416 * keyed as 'user_id' => $user_id; false to get a one-dimensional 417 * array of user IDs. Default: false. 418 * @return array $fids IDs of friends for provided user. 419 */ 420 public static function get_friend_user_ids( $user_id, $friend_requests_only = false, $assoc_arr = false ) { 421 422 if ( ! empty( $friend_requests_only ) ) { 423 $args = array( 424 'is_confirmed' => 0, 425 'friend_user_id' => $user_id, 426 ); 427 } else { 428 $args = array( 429 'is_confirmed' => 1, 430 ); 431 } 432 433 $friendships = self::get_friendships( $user_id, $args ); 434 435 $fids = array(); 436 foreach ( $friendships as $friendship ) { 437 if ( ! empty( $assoc_arr ) ) { 438 $fids[] = array( 'user_id' => ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id ); 439 } else { 440 $fids[] = ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id; 441 } 442 } 443 444 return array_map( 'intval', $fids ); 445 } 446 447 /** 448 * Get the ID of the friendship object, if any, between a pair of users. 449 * 450 * @since 1.0.0 451 * 452 * @param int $user_id The ID of the first user. 453 * @param int $friend_id The ID of the second user. 454 * @return int|null The ID of the friendship object if found, otherwise null. 455 */ 456 public static function get_friendship_id( $user_id, $friend_id ) { 457 $friendship_id = null; 458 459 // Can't friend yourself. 460 if ( $user_id === $friend_id ) { 461 return $friendship_id; 462 } 463 464 /* 465 * Find friendships where the possible_friend_userid is the 466 * initiator or friend. 467 */ 468 $args = array( 469 'initiator_user_id' => $friend_id, 470 'friend_user_id' => $friend_id, 471 ); 472 473 $result = self::get_friendships( $user_id, $args, 'OR' ); 474 if ( $result ) { 475 $friendship_id = current( $result )->id; 476 } 477 return $friendship_id; 478 } 479 480 /** 481 * Get a list of IDs of users who have requested friendship of a given user. 482 * 483 * @since 1.2.0 484 * 485 * @param int $user_id The ID of the user who has received the 486 * friendship requests. 487 * @return array|bool An array of user IDs or false if none are found. 488 */ 489 public static function get_friendship_request_user_ids( $user_id ) { 490 $friend_requests = wp_cache_get( $user_id, 'bp_friends_requests' ); 491 492 if ( false === $friend_requests ) { 493 $friend_requests = self::get_friend_user_ids( $user_id, true ); 494 495 wp_cache_set( $user_id, $friend_requests, 'bp_friends_requests' ); 496 } 497 498 // Integer casting. 499 if ( ! empty( $friend_requests ) ) { 500 $friend_requests = array_map( 'intval', $friend_requests ); 501 } 502 503 return $friend_requests; 504 } 505 506 /** 507 * Get a total friend count for a given user. 508 * 509 * @since 1.0.0 510 * 511 * @param int $user_id Optional. ID of the user whose friendships you 512 * are counting. Default: displayed user (if any), otherwise 513 * logged-in user. 514 * @return int Friend count for the user. 515 */ 516 public static function total_friend_count( $user_id = 0 ) { 517 518 if ( empty( $user_id ) ) { 519 $user_id = ( bp_displayed_user_id() ) ? bp_displayed_user_id() : bp_loggedin_user_id(); 520 } 521 522 /* 523 * This is stored in 'total_friend_count' usermeta. 524 * This function will recalculate, update and return. 525 */ 526 527 $args = array( 'is_confirmed' => 1 ); 528 $friendships = self::get_friendships( $user_id, $args ); 529 $count = count( $friendships ); 530 531 // Do not update meta if user has never had friends. 532 if ( ! $count && ! bp_get_user_meta( $user_id, 'total_friend_count', true ) ) { 533 return 0; 534 } 535 536 bp_update_user_meta( $user_id, 'total_friend_count', (int) $count ); 537 538 return absint( $count ); 539 } 540 541 /** 542 * Search the friends of a user by a search string. 543 * 544 * @todo Optimize this function. 545 * 546 * @since 1.0.0 547 * 548 * @global BuddyPress $bp The one true BuddyPress instance. 549 * @global wpdb $wpdb WordPress database object. 550 * 551 * @param string $filter The search string, matched against xprofile 552 * fields (if available), or usermeta 'nickname' field. 553 * @param int $user_id ID of the user whose friends are being searched. 554 * @param int|null $limit Optional. Max number of friends to return. 555 * @param int|null $page Optional. The page of results to return. Default: 556 * null (no pagination - return all results). 557 * @return array|bool On success, an array: { 558 * @type array $friends IDs of friends returned by the query. 559 * @type int $count Total number of friends (disregarding 560 * pagination) who match the search. 561 * }. Returns false on failure. 562 */ 563 public static function search_friends( $filter, $user_id, $limit = null, $page = null ) { 564 global $wpdb; 565 566 $bp = buddypress(); 567 568 if ( empty( $user_id ) ) { 569 $user_id = bp_loggedin_user_id(); 570 } 571 572 // Only search for matching strings at the beginning of the 573 // name (@todo - figure out why this restriction). 574 $search_terms_like = bp_esc_like( $filter ) . '%'; 575 576 $pag_sql = ''; 577 if ( ! empty( $limit ) && ! empty( $page ) ) { 578 $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) ); 579 } 580 581 $friend_ids = self::get_friend_user_ids( $user_id ); 582 if ( ! $friend_ids ) { 583 return false; 584 } 585 586 // Get all the user ids for the current user's friends. 587 $fids = implode( ',', wp_parse_id_list( $friend_ids ) ); 588 589 if ( empty( $fids ) ) { 590 return false; 591 } 592 593 // Filter the user_ids based on the search criteria. 594 if ( bp_is_active( 'xprofile' ) ) { 595 $sql = $wpdb->prepare( "SELECT DISTINCT user_id FROM {$bp->profile->table_name_data} WHERE user_id IN ({$fids}) AND value LIKE %s {$pag_sql}", $search_terms_like ); 596 $total_sql = $wpdb->prepare( "SELECT COUNT(DISTINCT user_id) FROM {$bp->profile->table_name_data} WHERE user_id IN ({$fids}) AND value LIKE %s", $search_terms_like ); 597 } else { 598 $sql = $wpdb->prepare( "SELECT DISTINCT user_id FROM {$wpdb->usermeta} WHERE user_id IN ({$fids}) AND meta_key = 'nickname' AND meta_value LIKE %s {$pag_sql}", $search_terms_like ); 599 $total_sql = $wpdb->prepare( "SELECT COUNT(DISTINCT user_id) FROM {$wpdb->usermeta} WHERE user_id IN ({$fids}) AND meta_key = 'nickname' AND meta_value LIKE %s", $search_terms_like ); 600 } 601 602 $filtered_friend_ids = $wpdb->get_col( $sql ); 603 $total_friend_ids = $wpdb->get_var( $total_sql ); 604 605 if ( empty( $filtered_friend_ids ) ) { 606 return false; 607 } 608 609 return array( 610 'friends' => array_map( 'intval', $filtered_friend_ids ), 611 'total' => (int) $total_friend_ids, 612 ); 613 } 614 615 /** 616 * Check friendship status between two users. 617 * 618 * Note that 'pending' means that $initiator_userid has sent a friend 619 * request to $possible_friend_userid that has not yet been approved, 620 * while 'awaiting_response' is the other way around ($possible_friend_userid 621 * sent the initial request). 622 * 623 * @since 1.0.0 624 * 625 * @param int $initiator_userid The ID of the user who is the initiator 626 * of the potential friendship/request. 627 * @param int $possible_friend_userid The ID of the user who is the 628 * recipient of the potential friendship/request. 629 * @return string|false $value The friendship status, from among 'not_friends', 630 * 'is_friend', 'pending', and 'awaiting_response'. 631 */ 632 public static function check_is_friend( $initiator_userid, $possible_friend_userid ) { 633 634 if ( empty( $initiator_userid ) || empty( $possible_friend_userid ) ) { 635 return false; 636 } 637 638 // Can't friend yourself. 639 if ( $initiator_userid === $possible_friend_userid ) { 640 return 'not_friends'; 641 } 642 643 self::update_bp_friends_cache( $initiator_userid, $possible_friend_userid ); 644 645 return bp_core_get_incremented_cache( $initiator_userid . ':' . $possible_friend_userid, 'bp_friends' ); 646 } 647 648 /** 649 * Find uncached friendships between a user and one or more other users and cache them. 650 * 651 * @since 3.0.0 652 * 653 * @global BuddyPress $bp The one true BuddyPress instance. 654 * @global wpdb $wpdb WordPress database object. 655 * 656 * @param int $user_id The ID of the primary user for whom we want 657 * to check friendships statuses. 658 * @param int|array|string $possible_friend_ids The IDs of the one or more users 659 * to check friendship status with primary user. 660 */ 661 public static function update_bp_friends_cache( $user_id, $possible_friend_ids ) { 662 global $wpdb; 663 664 $bp = buddypress(); 665 $possible_friend_ids = wp_parse_id_list( $possible_friend_ids ); 666 667 $fetch = array(); 668 foreach ( $possible_friend_ids as $friend_id ) { 669 // Check for cached items in both friendship directions. 670 if ( false === bp_core_get_incremented_cache( $user_id . ':' . $friend_id, 'bp_friends' ) 671 || false === bp_core_get_incremented_cache( $friend_id . ':' . $user_id, 'bp_friends' ) ) { 672 $fetch[] = $friend_id; 673 } 674 } 675 676 if ( empty( $fetch ) ) { 677 return; 678 } 679 680 $friend_ids_sql = implode( ',', array_unique( $fetch ) ); 681 $sql = $wpdb->prepare( "SELECT initiator_user_id, friend_user_id, is_confirmed FROM {$bp->friends->table_name} WHERE (initiator_user_id = %d AND friend_user_id IN ({$friend_ids_sql}) ) OR (initiator_user_id IN ({$friend_ids_sql}) AND friend_user_id = %d )", $user_id, $user_id ); 682 $friendships = $wpdb->get_results( $sql ); 683 684 // Use $handled to keep track of all of the $possible_friend_ids we've matched. 685 $handled = array(); 686 foreach ( $friendships as $friendship ) { 687 $initiator_user_id = (int) $friendship->initiator_user_id; 688 $friend_user_id = (int) $friendship->friend_user_id; 689 if ( 1 === (int) $friendship->is_confirmed ) { 690 $status_initiator = $status_friend = 'is_friend'; 691 } else { 692 $status_initiator = 'pending'; 693 $status_friend = 'awaiting_response'; 694 } 695 bp_core_set_incremented_cache( $initiator_user_id . ':' . $friend_user_id, 'bp_friends', $status_initiator ); 696 bp_core_set_incremented_cache( $friend_user_id . ':' . $initiator_user_id, 'bp_friends', $status_friend ); 697 698 $handled[] = ( $initiator_user_id === $user_id ) ? $friend_user_id : $initiator_user_id; 699 } 700 701 // Set all those with no matching entry to "not friends" status. 702 $not_friends = array_diff( $fetch, $handled ); 703 704 foreach ( $not_friends as $not_friend_id ) { 705 bp_core_set_incremented_cache( $user_id . ':' . $not_friend_id, 'bp_friends', 'not_friends' ); 706 bp_core_set_incremented_cache( $not_friend_id . ':' . $user_id, 'bp_friends', 'not_friends' ); 707 } 708 } 709 710 /** 711 * Get the last active date of many users at once. 712 * 713 * @todo Why is this in the Friends component? 714 * 715 * @since 1.0.0 716 * 717 * @param array $user_ids IDs of users whose last_active meta is 718 * being queried. 719 * @return array $retval Array of last_active values + user_ids. 720 */ 721 public static function get_bulk_last_active( $user_ids ) { 722 $last_activities = BP_Core_User::get_last_activity( $user_ids ); 723 724 // Sort and structure as expected in legacy function. 725 usort( $last_activities, function( $a, $b ) { 726 if ( $a['date_recorded'] === $b['date_recorded'] ) { 727 return 0; 728 } 729 730 return ( strtotime( $a['date_recorded'] ) < strtotime( $b['date_recorded'] ) ) ? 1 : -1; 731 } ); 732 733 $retval = array(); 734 foreach ( $last_activities as $last_activity ) { 735 $u = new stdClass(); 736 $u->last_activity = $last_activity['date_recorded']; 737 $u->user_id = $last_activity['user_id']; 738 739 $retval[] = $u; 740 } 741 742 return $retval; 743 } 744 745 /** 746 * Mark a friendship as accepted. 747 * 748 * @since 1.0.0 749 * 750 * @global BuddyPress $bp The one true BuddyPress instance. 751 * @global wpdb $wpdb WordPress database object. 752 * 753 * @param int $friendship_id ID of the friendship to be accepted. 754 * @return int Number of database rows updated. 755 */ 756 public static function accept( $friendship_id ) { 757 global $wpdb; 758 759 $bp = buddypress(); 760 761 return $wpdb->query( $wpdb->prepare( "UPDATE {$bp->friends->table_name} SET is_confirmed = 1, date_created = %s WHERE id = %d AND friend_user_id = %d", bp_core_current_time(), $friendship_id, bp_loggedin_user_id() ) ); 762 } 763 764 /** 765 * Remove a friendship or a friendship request INITIATED BY the logged-in user. 766 * 767 * @since 1.6.0 768 * 769 * @global BuddyPress $bp The one true BuddyPress instance. 770 * @global wpdb $wpdb WordPress database object. 771 * 772 * @param int $friendship_id ID of the friendship to be withdrawn. 773 * @return int Number of database rows deleted. 774 */ 775 public static function withdraw( $friendship_id ) { 776 global $wpdb; 777 778 $bp = buddypress(); 779 780 return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE id = %d AND initiator_user_id = %d", $friendship_id, bp_loggedin_user_id() ) ); 781 } 782 783 /** 784 * Remove a friendship or a friendship request MADE OF the logged-in user. 785 * 786 * @since 1.0.0 787 * 788 * @global BuddyPress $bp The one true BuddyPress instance. 789 * @global wpdb $wpdb WordPress database object. 790 * 791 * @param int $friendship_id ID of the friendship to be rejected. 792 * @return int Number of database rows deleted. 793 */ 794 public static function reject( $friendship_id ) { 795 global $wpdb; 796 797 $bp = buddypress(); 798 799 return $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->friends->table_name} WHERE id = %d AND friend_user_id = %d", $friendship_id, bp_loggedin_user_id() ) ); 800 } 801 802 /** 803 * Search users. 804 * 805 * @todo Why does this exist, and why is it in bp-friends? 806 * 807 * @since 1.0.0 808 * 809 * @global BuddyPress $bp The one true BuddyPress instance. 810 * @global wpdb $wpdb WordPress database object. 811 * 812 * @param string $filter String to search by. 813 * @param int $user_id A user ID param that is unused. 814 * @param int|null $limit Optional. Max number of records to return. 815 * @param int|null $page Optional. Number of the page to return. Default: 816 * false (no pagination - return all results). 817 * @return array $filtered_ids IDs of users who match the query. 818 */ 819 public static function search_users( $filter, $user_id, $limit = null, $page = null ) { 820 global $wpdb; 821 822 // Only search for matching strings at the beginning of the 823 // name (@todo - figure out why this restriction). 824 $search_terms_like = bp_esc_like( $filter ) . '%'; 825 826 $usermeta_table = $wpdb->base_prefix . 'usermeta'; 827 $users_table = $wpdb->base_prefix . 'users'; 828 829 $pag_sql = ''; 830 if ( ! empty( $limit ) && ! empty( $page ) ) { 831 $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * intval( $limit ) ), intval( $limit ) ); 832 } 833 834 $bp = buddypress(); 835 836 // Filter the user_ids based on the search criteria. 837 if ( bp_is_active( 'xprofile' ) ) { 838 $sql = $wpdb->prepare( "SELECT DISTINCT d.user_id as id FROM {$bp->profile->table_name_data} d, {$users_table} u WHERE d.user_id = u.id AND d.value LIKE %s ORDER BY d.value DESC {$pag_sql}", $search_terms_like ); 839 } else { 840 $sql = $wpdb->prepare( "SELECT DISTINCT user_id as id FROM {$usermeta_table} WHERE meta_value LIKE %s ORDER BY d.value DESC {$pag_sql}", $search_terms_like ); 841 } 842 843 $filtered_fids = $wpdb->get_col( $sql ); 844 845 if ( empty( $filtered_fids ) ) { 846 return false; 847 } 848 849 return $filtered_fids; 850 } 851 852 /** 853 * Get a count of users who match a search term. 854 * 855 * @todo Why does this exist, and why is it in bp-friends? 856 * 857 * @since 1.0.0 858 * 859 * @global BuddyPress $bp The one true BuddyPress instance. 860 * @global wpdb $wpdb WordPress database object. 861 * 862 * @param string $filter Search term. 863 * @return int Count of users matching the search term. 864 */ 865 public static function search_users_count( $filter ) { 866 global $wpdb; 867 868 // Only search for matching strings at the beginning of the 869 // name (@todo - figure out why this restriction). 870 $search_terms_like = bp_esc_like( $filter ) . '%'; 871 872 $usermeta_table = $wpdb->prefix . 'usermeta'; 873 $users_table = $wpdb->base_prefix . 'users'; 874 875 $bp = buddypress(); 876 877 // Filter the user_ids based on the search criteria. 878 if ( bp_is_active( 'xprofile' ) ) { 879 $sql = $wpdb->prepare( "SELECT COUNT(DISTINCT d.user_id) FROM {$bp->profile->table_name_data} d, {$users_table} u WHERE d.user_id = u.id AND d.value LIKE %s", $search_terms_like ); 880 } else { 881 $sql = $wpdb->prepare( "SELECT COUNT(DISTINCT user_id) FROM {$usermeta_table} WHERE meta_value LIKE %s", $search_terms_like ); 882 } 883 884 $user_count = $wpdb->get_col( $sql ); 885 886 if ( empty( $user_count ) ) { 887 return false; 888 } 889 890 return $user_count[0]; 891 } 892 893 /** 894 * Sort a list of user IDs by their display names. 895 * 896 * @todo Why does this exist, and why is it in bp-friends? 897 * 898 * @since 1.0.0 899 * 900 * @global BuddyPress $bp The one true BuddyPress instance. 901 * @global wpdb $wpdb WordPress database object. 902 * 903 * @param array $user_ids Array of user IDs. 904 * @return array|bool User IDs, sorted by the associated display names. 905 * False if XProfile component is not active. 906 */ 907 public static function sort_by_name( $user_ids ) { 908 global $wpdb; 909 910 if ( ! bp_is_active( 'xprofile' ) ) { 911 return false; 912 } 913 914 $bp = buddypress(); 915 916 $user_ids = implode( ',', wp_parse_id_list( $user_ids ) ); 917 918 return $wpdb->get_results( $wpdb->prepare( "SELECT user_id FROM {$bp->profile->table_name_data} pd, {$bp->profile->table_name_fields} pf WHERE pf.id = pd.field_id AND pf.name = %s AND pd.user_id IN ( {$user_ids} ) ORDER BY pd.value ASC", bp_xprofile_fullname_field_name() ) ); 919 } 920 921 /** 922 * Get a list of random friend IDs. 923 * 924 * @since 1.0.0 925 * 926 * @global BuddyPress $bp The one true BuddyPress instance. 927 * @global wpdb $wpdb WordPress database object. 928 * 929 * @param int $user_id ID of the user whose friends are being retrieved. 930 * @param int $total_friends Optional. Number of random friends to get. 931 * Default: 5. 932 * @return array|false An array of random friend user IDs on success; 933 * false if none are found. 934 */ 935 public static function get_random_friends( $user_id, $total_friends = 5 ) { 936 global $wpdb; 937 938 $bp = buddypress(); 939 $fids = array(); 940 $sql = $wpdb->prepare( "SELECT friend_user_id, initiator_user_id FROM {$bp->friends->table_name} WHERE (friend_user_id = %d || initiator_user_id = %d) && is_confirmed = 1 ORDER BY rand() LIMIT %d", $user_id, $user_id, $total_friends ); 941 $results = $wpdb->get_results( $sql ); 942 943 for ( $i = 0, $count = count( $results ); $i < $count; ++$i ) { 944 $fids[] = ( $results[ $i ]->friend_user_id === $user_id ) ? $results[ $i ]->initiator_user_id : $results[ $i ]->friend_user_id; 945 } 946 947 // Remove duplicates. 948 if ( count( $fids ) > 0 ) { 949 return array_flip( array_flip( $fids ) ); 950 } 951 952 return false; 953 } 954 955 /** 956 * Get a count of a user's friends who can be invited to a given group. 957 * 958 * Users can invite any of their friends except: 959 * 960 * - users who are already in the group 961 * - users who have a pending invite to the group 962 * - users who have been banned from the group 963 * 964 * @todo Need to do a group component check before using group functions. 965 * 966 * @since 1.0.0 967 * 968 * @param int $user_id ID of the user whose friends are being counted. 969 * @param int $group_id ID of the group friends are being invited to. 970 * @return bool|int False if group component is not active, and friend count. 971 */ 972 public static function get_invitable_friend_count( $user_id, $group_id ) { 973 974 if ( ! bp_is_active( 'group' ) ) { 975 return false; 976 } 977 978 // Setup some data we'll use below. 979 $is_group_admin = groups_is_user_admin( $user_id, $group_id ); 980 $friend_ids = self::get_friend_user_ids( $user_id ); 981 $invitable_count = 0; 982 983 for ( $i = 0, $count = count( $friend_ids ); $i < $count; ++$i ) { 984 985 // If already a member, they cannot be invited again. 986 if ( groups_is_user_member( (int) $friend_ids[ $i ], $group_id ) ) { 987 continue; 988 } 989 990 // If user already has invite, they cannot be added. 991 if ( groups_check_user_has_invite( (int) $friend_ids[ $i ], $group_id ) ) { 992 continue; 993 } 994 995 // If user is not group admin and friend is banned, they cannot be invited. 996 if ( ( false === $is_group_admin ) && groups_is_user_banned( (int) $friend_ids[ $i ], $group_id ) ) { 997 continue; 998 } 999 1000 $invitable_count++; 1001 } 1002 1003 return $invitable_count; 1004 } 1005 1006 /** 1007 * Get friendship objects by ID (or an array of IDs). 1008 * 1009 * @since 2.7.0 1010 * 1011 * @global BuddyPress $bp The one true BuddyPress instance. 1012 * @global wpdb $wpdb WordPress database object. 1013 * 1014 * @param int|string|array $friendship_ids Single friendship ID or comma-separated/array list of friendship IDs. 1015 * @return array 1016 */ 1017 public static function get_friendships_by_id( $friendship_ids ) { 1018 global $wpdb; 1019 1020 $bp = buddypress(); 1021 1022 $friendship_ids = implode( ',', wp_parse_id_list( $friendship_ids ) ); 1023 return $wpdb->get_results( "SELECT * FROM {$bp->friends->table_name} WHERE id IN ({$friendship_ids})" ); 1024 } 1025 1026 /** 1027 * Get the friend user IDs for a given friendship. 1028 * 1029 * @since 1.0.0 1030 * 1031 * @param int $friendship_id ID of the friendship. 1032 * @return null|stdClass 1033 */ 1034 public static function get_user_ids_for_friendship( $friendship_id ) { 1035 $friendship = new BP_Friends_Friendship( $friendship_id, false, false ); 1036 1037 if ( empty( $friendship->id ) ) { 1038 return null; 1039 } 1040 1041 $retval = new StdClass(); 1042 $retval->friend_user_id = $friendship->friend_user_id; 1043 $retval->initiator_user_id = $friendship->initiator_user_id; 1044 1045 return $retval; 1046 } 1047 1048 /** 1049 * Delete all friendships and friend notifications related to a user. 1050 * 1051 * @since 1.0.0 1052 * 1053 * @global BuddyPress $bp The one true BuddyPress instance. 1054 * @global wpdb $wpdb WordPress database object. 1055 * 1056 * @param int $user_id ID of the user being expunged. 1057 */ 1058 public static function delete_all_for_user( $user_id ) { 1059 global $wpdb; 1060 1061 $bp = buddypress(); 1062 1063 // Get all friendships, of any status, for the user. 1064 $friendships = self::get_friendships( $user_id ); 1065 $friend_ids = array(); 1066 $friendship_ids = array(); 1067 foreach ( $friendships as $friendship ) { 1068 $friendship_ids[] = $friendship->id; 1069 if ( $friendship->is_confirmed ) { 1070 $friend_ids[] = ( $friendship->friend_user_id == $user_id ) ? $friendship->initiator_user_id : $friendship->friend_user_id; 1071 } 1072 } 1073 1074 // Delete the friendships from the database. 1075 if ( $friendship_ids ) { 1076 $friendship_ids_sql = implode( ',', wp_parse_id_list( $friendship_ids ) ); 1077 $wpdb->query( "DELETE FROM {$bp->friends->table_name} WHERE id IN ({$friendship_ids_sql})" ); 1078 } 1079 1080 // Delete friend request notifications for members who have a 1081 // notification from this user. 1082 if ( bp_is_active( 'notifications' ) ) { 1083 $wpdb->query( $wpdb->prepare( "DELETE FROM {$bp->notifications->table_name} WHERE component_name = 'friends' AND ( component_action = 'friendship_request' OR component_action = 'friendship_accepted' ) AND item_id = %d", $user_id ) ); 1084 } 1085 1086 // Clean up the friendships cache. 1087 foreach ( $friendship_ids as $friendship_id ) { 1088 wp_cache_delete( $friendship_id, 'bp_friends_friendships' ); 1089 } 1090 1091 // Loop through friend_ids to scrub user caches and update total count metas. 1092 foreach ( (array) $friend_ids as $friend_id ) { 1093 // Delete cached friendships. 1094 wp_cache_delete( $friend_id, 'bp_friends_friendships_for_user' ); 1095 1096 self::total_friend_count( $friend_id ); 1097 } 1098 1099 // Delete cached friendships. 1100 wp_cache_delete( $user_id, 'bp_friends_friendships_for_user' ); 1101 } 1102 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Dec 26 01:01:04 2024 | Cross-referenced by PHPXref 0.7.1 |