Ticket #6418: 6418.diff
File 6418.diff, 17.4 KB (added by , 10 years ago) |
---|
-
src/bp-core/classes/class-bp-user-query.php
diff --git src/bp-core/classes/class-bp-user-query.php src/bp-core/classes/class-bp-user-query.php index 8739266..b288460 100644
defined( 'ABSPATH' ) || exit; 38 38 * override all others; BP User objects will be constructed using these 39 39 * IDs only. Default: false. 40 40 * @type array|string $member_type Array or comma-separated list of member types to limit results to. 41 * @type array|string $member_type__in Array or comma-separated list of member types to limit results to. 42 * @type array|string $member_type__not_in Array or comma-separated list of member types that will be 43 * excluded from results. 41 44 * @type string|bool $meta_key Limit results to users that have usermeta associated with this meta_key. 42 45 * Usually used with $meta_value. Default: false. 43 46 * @type string|bool $meta_value When used with $meta_key, limits results to users whose usermeta value … … class BP_User_Query { 166 169 'exclude' => false, 167 170 'user_ids' => false, 168 171 'member_type' => '', 172 'member_type__in' => '', 173 'member_type__not_in' => '', 169 174 'meta_key' => false, 170 175 'meta_value' => false, 171 176 'xprofile_query' => false, … … class BP_User_Query { 418 423 ); 419 424 } 420 425 421 // Member type. 422 if ( ! empty( $member_type ) ) { 423 $member_types = array(); 424 425 if ( ! is_array( $member_type ) ) { 426 $member_type = preg_split( '/[,\s+]/', $member_type ); 427 } 428 429 foreach ( $member_type as $mt ) { 430 if ( ! bp_get_member_type_object( $mt ) ) { 431 continue; 432 } 433 434 $member_types[] = $mt; 435 } 436 437 if ( ! empty( $member_types ) ) { 438 $member_type_tq = new WP_Tax_Query( array( 439 array( 440 'taxonomy' => 'bp_member_type', 441 'field' => 'name', 442 'operator' => 'IN', 443 'terms' => $member_types, 444 ), 445 ) ); 446 447 // Switch to the root blog, where member type taxonomies live. 448 $switched = false; 449 if ( ! bp_is_root_blog() ) { 450 switch_to_blog( bp_get_root_blog_id() ); 451 $switched = true; 452 } 426 // Only use $member_type__in if $member_type is not set. 427 if ( empty( $member_type ) && ! empty( $member_type__in ) ) { 428 $member_type = $member_type__in; 429 } 453 430 454 $member_type_sql_clauses = $member_type_tq->get_sql( 'u', $this->uid_name ); 431 // Member types to exclude. Note that this takes precedence over inclusions. 432 if ( ! empty( $member_type__not_in ) ) { 433 $member_type_clause = $this->get_sql_clause_for_member_types( $member_type__not_in, 'NOT IN' ); 455 434 456 if ( $switched ) { 457 restore_current_blog(); 458 } 435 // Member types to include. 436 } elseif ( ! empty( $member_type ) ) { 437 $member_type_clause = $this->get_sql_clause_for_member_types( $member_type, 'IN' ); 438 } 459 439 460 // Grab the first term_relationships clause and convert to a subquery. 461 if ( preg_match( '/' . $wpdb->term_relationships . '\.term_taxonomy_id IN \([0-9, ]+\)/', $member_type_sql_clauses['where'], $matches ) ) { 462 $sql['where']['member_type'] = "u.{$this->uid_name} IN ( SELECT object_id FROM $wpdb->term_relationships WHERE {$matches[0]} )"; 463 } elseif ( false !== strpos( $member_type_sql_clauses['where'], '0 = 1' ) ) { 464 $sql['where']['member_type'] = $this->no_results['where']; 465 } 466 } 440 if ( ! empty( $member_type_clause ) ) { 441 $sql['where']['member_type'] = $member_type_clause; 467 442 } 468 443 469 444 // 'meta_key', 'meta_value' allow usermeta search … … class BP_User_Query { 774 749 } 775 750 } 776 751 } 752 753 /** 754 * Get a SQL clause representing member_type include/exclusion. 755 * 756 * @since 2.4.0 757 * 758 * @param string|array $member_types Array or comma-separated list of member types. 759 * @param string $operator 'IN' or 'NOT IN'. 760 */ 761 protected function get_sql_clause_for_member_types( $member_types, $operator ) { 762 global $wpdb; 763 764 // Sanitize. 765 if ( 'NOT IN' !== $operator ) { 766 $operator = 'IN'; 767 } 768 769 // Parse and sanitize types. 770 if ( ! is_array( $member_types ) ) { 771 $member_types = preg_split( '/[,\s+]/', $member_types ); 772 } 773 774 $types = array(); 775 foreach ( $member_types as $mt ) { 776 if ( bp_get_member_type_object( $mt ) ) { 777 $types[] = $mt; 778 } 779 } 780 781 $tax_query = new WP_Tax_Query( array( 782 array( 783 'taxonomy' => 'bp_member_type', 784 'field' => 'name', 785 'operator' => $operator, 786 'terms' => $types, 787 ), 788 ) ); 789 790 // Switch to the root blog, where member type taxonomies live. 791 $switched = false; 792 if ( ! bp_is_root_blog() ) { 793 switch_to_blog( bp_get_root_blog_id() ); 794 $switched = true; 795 } 796 797 $sql_clauses = $tax_query->get_sql( 'u', $this->uid_name ); 798 799 if ( $switched ) { 800 restore_current_blog(); 801 } 802 803 $clause = ''; 804 805 // no_results clauses are the same between IN and NOT IN. 806 if ( false !== strpos( $sql_clauses['where'], '0 = 1' ) ) { 807 $clause = $this->no_results['where']; 808 809 // The tax_query clause generated for NOT IN can be used almost as-is. We just trim the leading 'AND'. 810 } elseif ( 'NOT IN' === $operator ) { 811 $clause = preg_replace( '/^\s*AND\s*/', '', $sql_clauses['where'] ); 812 813 // IN clauses must be converted to a subquery. 814 } elseif ( preg_match( '/' . $wpdb->term_relationships . '\.term_taxonomy_id IN \([0-9, ]+\)/', $sql_clauses['where'], $matches ) ) { 815 $clause = "u.{$this->uid_name} IN ( SELECT object_id FROM $wpdb->term_relationships WHERE {$matches[0]} )"; 816 } 817 818 return $clause; 819 } 777 820 } -
src/bp-members/bp-members-functions.php
diff --git src/bp-members/bp-members-functions.php src/bp-members/bp-members-functions.php index 2f4acc9..596e83b 100644
add_action( 'bp_setup_globals', 'bp_core_define_slugs', 11 ); 85 85 * @type string $meta_key Limit to users with a meta_key. Default: false. 86 86 * @type string $meta_value Limit to users with a meta_value (with meta_key). Default: false. 87 87 * @type array|string $member_type Array or comma-separated string of member types. 88 * @type array|string $member_type__in Array or comma-separated string of member types. 89 * `$member_type` takes precedence over this parameter. 90 * @type array|string $member_type__not_in Array or comma-separated string of member types to be excluded 88 91 * @type mixed $include Limit results by user IDs. Default: false. 89 92 * @type int $per_page Results per page. Default: 20. 90 93 * @type int $page Page of results. Default: 1. … … function bp_core_get_users( $args = '' ) { 104 107 'meta_key' => false, // Limit to users who have this piece of usermeta 105 108 'meta_value' => false, // With meta_key, limit to users where usermeta matches this value 106 109 'member_type' => '', 110 'member_type__in' => '', 111 'member_type__not_in' => '', 107 112 'include' => false, // Pass comma separated list of user_ids to limit to only these users 108 113 'per_page' => 20, // The number of results to return per page 109 114 'page' => 1, // The page to return if limiting per page -
src/bp-members/bp-members-template.php
diff --git src/bp-members/bp-members-template.php src/bp-members/bp-members-template.php index 45bfcf4..8a867d3 100644
class BP_Core_Members_Template { 289 289 * @param array $page_arg Optional. The string used as a query parameter in pagination links. 290 290 * Default: 'upage'. 291 291 * @param array|string $member_type Array or comma-separated string of member types to limit results to. 292 * @param array|string $member_type__in Array or comma-separated string of member types to limit results to. 293 * @param array|string $member_type__not_in Array or comma-separated string of member types to exclude from results. 292 294 */ 293 function __construct( $type, $page_number, $per_page, $max, $user_id, $search_terms, $include, $populate_extras, $exclude, $meta_key, $meta_value, $page_arg = 'upage', $member_type = '' ) {295 function __construct( $type, $page_number, $per_page, $max, $user_id, $search_terms, $include, $populate_extras, $exclude, $meta_key, $meta_value, $page_arg = 'upage', $member_type = '', $member_type__in = '', $member_type__not_in = '' ) { 294 296 295 297 $this->pag_arg = sanitize_key( $page_arg ); 296 298 $this->pag_page = bp_sanitize_pagination_arg( $this->pag_arg, $page_number ); … … class BP_Core_Members_Template { 300 302 if ( !empty( $_REQUEST['letter'] ) ) 301 303 $this->members = BP_Core_User::get_users_by_letter( $_REQUEST['letter'], $this->pag_num, $this->pag_page, $populate_extras, $exclude ); 302 304 else 303 $this->members = bp_core_get_users( array( 'type' => $this->type, 'per_page' => $this->pag_num, 'page' => $this->pag_page, 'user_id' => $user_id, 'include' => $include, 'search_terms' => $search_terms, 'populate_extras' => $populate_extras, 'exclude' => $exclude, 'meta_key' => $meta_key, 'meta_value' => $meta_value, 'member_type' => $member_type ) );305 $this->members = bp_core_get_users( array( 'type' => $this->type, 'per_page' => $this->pag_num, 'page' => $this->pag_page, 'user_id' => $user_id, 'include' => $include, 'search_terms' => $search_terms, 'populate_extras' => $populate_extras, 'exclude' => $exclude, 'meta_key' => $meta_key, 'meta_value' => $meta_value, 'member_type' => $member_type, 'member_type__in' => $member_type__in, 'member_type__not_in' => $member_type__not_in ) ); 304 306 305 307 if ( !$max || $max >= (int) $this->members['total'] ) 306 308 $this->total_member_count = (int) $this->members['total']; … … function bp_rewind_members() { 494 496 * user. When on a user's Friends page, defaults to the ID of the 495 497 * displayed user. Otherwise defaults to 0. 496 498 * @type string|array $member_type Array or comma-separated list of member types to limit results to. 499 * @type string|array $member_type__in Array or comma-separated list of member types to limit results to. 500 * @type string|array $member_type__not_in Array or comma-separated list of member types to exclude from results. 497 501 * @type string $search_terms Limit results by a search term. Default: null. 498 502 * @type string $meta_key Limit results by the presence of a usermeta key. 499 503 * Default: false. … … function bp_has_members( $args = '' ) { 539 543 540 544 'user_id' => $user_id, // Pass a user_id to only show friends of this user 541 545 'member_type' => $member_type, 546 'member_type__in' => '', 547 'member_type__not_in' => '', 542 548 'search_terms' => null, // Pass search_terms to filter users by their profile data 543 549 544 550 'meta_key' => false, // Only return users with this usermeta … … function bp_has_members( $args = '' ) { 575 581 $r['meta_key'], 576 582 $r['meta_value'], 577 583 $r['page_arg'], 578 $r['member_type'] 584 $r['member_type'], 585 $r['member_type__in'], 586 $r['member_type__not_in'] 579 587 ); 580 588 581 589 /** -
tests/phpunit/testcases/core/class-bp-user-query.php
diff --git tests/phpunit/testcases/core/class-bp-user-query.php tests/phpunit/testcases/core/class-bp-user-query.php index 7c9aba4..2711d6c 100644
class BP_Tests_BP_User_Query_TestCases extends BP_UnitTestCase { 395 395 396 396 /** 397 397 * @group member_types 398 * @group bbg 398 399 */ 399 400 public function test_member_type_single_value() { 400 401 bp_register_member_type( 'foo' ); … … class BP_Tests_BP_User_Query_TestCases extends BP_UnitTestCase { 499 500 } 500 501 501 502 /** 503 * @group member_types 504 */ 505 public function test_member_type__in_single_value() { 506 bp_register_member_type( 'foo' ); 507 bp_register_member_type( 'bar' ); 508 $users = $this->factory->user->create_many( 3 ); 509 bp_set_member_type( $users[0], 'foo' ); 510 bp_set_member_type( $users[1], 'bar' ); 511 512 $q = new BP_User_Query( array( 513 'member_type__in' => 'bar', 514 ) ); 515 516 $found = array_values( wp_list_pluck( $q->results, 'ID' ) ); 517 $this->assertEquals( array( $users[1] ), $found ); 518 } 519 520 /** 521 * @group member_types 522 */ 523 public function test_member_type__in_array_with_single_value() { 524 bp_register_member_type( 'foo' ); 525 bp_register_member_type( 'bar' ); 526 $users = $this->factory->user->create_many( 3 ); 527 bp_set_member_type( $users[0], 'foo' ); 528 bp_set_member_type( $users[1], 'bar' ); 529 530 $q = new BP_User_Query( array( 531 'member_type__in' => array( 'bar' ), 532 ) ); 533 534 $found = array_values( wp_list_pluck( $q->results, 'ID' ) ); 535 $this->assertEquals( array( $users[1] ), $found ); 536 } 537 538 /** 539 * @group member_types 540 */ 541 public function test_member_type__in_comma_separated_values() { 542 bp_register_member_type( 'foo' ); 543 bp_register_member_type( 'bar' ); 544 $users = $this->factory->user->create_many( 3 ); 545 bp_set_member_type( $users[0], 'foo' ); 546 bp_set_member_type( $users[1], 'bar' ); 547 548 $q = new BP_User_Query( array( 549 'member_type__in' => 'foo, bar', 550 ) ); 551 552 $found = array_values( wp_list_pluck( $q->results, 'ID' ) ); 553 $this->assertEqualSets( array( $users[0], $users[1] ), $found ); 554 } 555 556 /** 557 * @group member_types 558 */ 559 public function test_member_type__in_array_with_multiple_values() { 560 bp_register_member_type( 'foo' ); 561 bp_register_member_type( 'bar' ); 562 $users = $this->factory->user->create_many( 3 ); 563 bp_set_member_type( $users[0], 'foo' ); 564 bp_set_member_type( $users[1], 'bar' ); 565 566 $q = new BP_User_Query( array( 567 'member_type__in' => array( 'foo', 'bar' ), 568 ) ); 569 570 $found = array_values( wp_list_pluck( $q->results, 'ID' ) ); 571 $this->assertEqualSets( array( $users[0], $users[1] ), $found ); 572 } 573 574 /** 575 * @group member_types 576 */ 577 public function test_member_type__in_comma_separated_values_should_discard_non_existent_taxonomies() { 578 bp_register_member_type( 'foo' ); 579 bp_register_member_type( 'bar' ); 580 $users = $this->factory->user->create_many( 3 ); 581 bp_set_member_type( $users[0], 'foo' ); 582 bp_set_member_type( $users[1], 'bar' ); 583 584 $q = new BP_User_Query( array( 585 'member_type__in' => 'foo, baz', 586 ) ); 587 588 $found = array_values( wp_list_pluck( $q->results, 'ID' ) ); 589 $this->assertEqualSets( array( $users[0] ), $found ); 590 } 591 592 /** 593 * @group member_types 594 */ 595 public function test_should_return_no_results_when_no_users_match_the_specified_member_type__in() { 596 bp_register_member_type( 'foo' ); 597 $users = $this->factory->user->create_many( 3 ); 598 599 $q = new BP_User_Query( array( 600 'member_type__in' => 'foo, baz', 601 ) ); 602 603 $this->assertEmpty( $q->results ); 604 } 605 606 /** 607 * @group member_types 608 */ 609 public function test_member_type_should_take_precedence_over_member_type__in() { 610 bp_register_member_type( 'foo' ); 611 bp_register_member_type( 'bar' ); 612 $users = $this->factory->user->create_many( 3 ); 613 bp_set_member_type( $users[0], 'foo' ); 614 bp_set_member_type( $users[1], 'bar' ); 615 616 $q = new BP_User_Query( array( 617 'member_type__in' => 'foo', 618 'member_type' => 'bar' 619 ) ); 620 621 $found = array_values( wp_list_pluck( $q->results, 'ID' ) ); 622 $this->assertEqualSets( array( $users[1] ), $found ); 623 } 624 625 /** 626 * @group member_types 627 * @group bbg 628 */ 629 public function test_member_type__not_in_returns_members_from_other_types_and_members_with_no_types() { 630 bp_register_member_type( 'foo' ); 631 bp_register_member_type( 'bar' ); 632 $users = $this->factory->user->create_many( 3 ); 633 bp_set_member_type( $users[0], 'foo' ); 634 bp_set_member_type( $users[1], 'bar' ); 635 636 $q = new BP_User_Query( array( 637 'member_type__not_in' => 'foo', 638 ) ); 639 640 $found = array_values( wp_list_pluck( $q->results, 'ID' ) ); 641 $this->assertEqualSets( array( $users[1], $users[2] ), $found ); 642 } 643 644 /** 645 * @group member_types 646 */ 647 public function test_should_return_no_results_when_all_users_match_the_specified_member_type__not_in() { 648 bp_register_member_type( 'foo' ); 649 $users = $this->factory->user->create_many( 3 ); 650 bp_set_member_type( $users[0], 'foo' ); 651 bp_set_member_type( $users[1], 'foo' ); 652 bp_set_member_type( $users[2], 'foo' ); 653 654 $q = new BP_User_Query( array( 655 'member_type__not_in' => 'foo', 656 ) ); 657 658 $this->assertEmpty( $q->results ); 659 } 660 661 /** 662 * @group member_types 663 */ 664 public function test_member_type__not_in_takes_precedence_over_member_type() { 665 bp_register_member_type( 'foo' ); 666 $users = $this->factory->user->create_many( 3 ); 667 bp_set_member_type( $users[0], 'foo' ); 668 bp_set_member_type( $users[1], 'foo' ); 669 bp_set_member_type( $users[2], 'foo' ); 670 671 $q = new BP_User_Query( array( 672 'member_type__not_in' => 'foo', 673 'member_type' => 'foo' 674 ) ); 675 676 $this->assertEmpty( $q->results ); 677 } 678 679 /** 680 * @group member_types 681 */ 682 public function test_member_type__not_in_takes_precedence_over_member_type__in() { 683 bp_register_member_type( 'foo' ); 684 $users = $this->factory->user->create_many( 3 ); 685 bp_set_member_type( $users[0], 'foo' ); 686 bp_set_member_type( $users[1], 'foo' ); 687 bp_set_member_type( $users[2], 'foo' ); 688 689 $q = new BP_User_Query( array( 690 'member_type__not_in' => 'foo', 691 'member_type__in' => 'foo' 692 ) ); 693 694 $this->assertEmpty( $q->results ); 695 } 696 697 /** 502 698 * @group cache 503 699 * @group member_types 504 700 */