Changeset 60941
- Timestamp:
- 10/15/2025 11:56:57 PM (2 months ago)
- Location:
- trunk
- Files:
-
- 2 edited
-
src/wp-includes/user.php (modified) (3 diffs)
-
tests/phpunit/tests/user.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/user.php
r60712 r60941 650 650 * 651 651 * @since 3.0.0 652 * @since 6.9.0 The results are now cached. 652 653 * 653 654 * @global wpdb $wpdb WordPress database abstraction object. … … 656 657 * @param string|string[] $post_type Optional. Single post type or array of post types to check. Defaults to 'post'. 657 658 * @param bool $public_only Optional. Only return counts for public posts. Defaults to false. 658 * @return string[]Amount of posts each user has written, as strings, keyed by user ID.659 * @return array<int, string> Amount of posts each user has written, as strings, keyed by user ID. 659 660 */ 660 661 function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) { … … 683 684 } 684 685 685 $userlist = implode( ',', array_map( 'absint', $users ) ); 686 $where = get_posts_by_author_sql( $post_type, true, null, $public_only ); 687 688 $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N ); 689 690 $count = array_fill_keys( $users, 0 ); 691 foreach ( $result as $row ) { 692 $count[ $row[0] ] = $row[1]; 686 // Cleanup the users array. Remove duplicates and sort for consistent ordering. 687 $users = array_unique( array_filter( array_map( 'intval', $users ) ) ); 688 sort( $users ); 689 690 // Cleanup the post type argument. Remove duplicates and sort for consistent ordering. 691 $post_type = array_unique( (array) $post_type ); 692 sort( $post_type ); 693 694 $userlist = implode( ',', $users ); 695 $where = get_posts_by_author_sql( $post_type, true, null, $public_only ); 696 $query = "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author"; 697 $cache_key = 'count_many_users_posts:' . md5( $query ); 698 $cache_salts = array( wp_cache_get_last_changed( 'posts' ), wp_cache_get_last_changed( 'users' ) ); 699 $count = wp_cache_get_salted( $cache_key, 'post-queries', $cache_salts ); 700 701 if ( false === $count ) { 702 $where = get_posts_by_author_sql( $post_type, true, null, $public_only ); 703 $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N ); 704 705 $count = array_fill_keys( $users, 0 ); 706 foreach ( $result as $row ) { 707 $count[ $row[0] ] = $row[1]; 708 } 709 710 wp_cache_set_salted( $cache_key, $count, 'post-queries', $cache_salts, HOUR_IN_SECONDS ); 693 711 } 694 712 -
trunk/tests/phpunit/tests/user.php
r60634 r60941 574 574 /** 575 575 * @ticket 21431 576 * 577 * @covers ::count_many_users_posts 576 578 */ 577 579 public function test_count_many_users_posts() { … … 603 605 $this->assertSame( '1', $counts[ self::$author_id ] ); 604 606 $this->assertSame( '1', $counts[ $user_id_b ] ); 607 } 608 609 /** 610 * Ensure the second and subsequent calls to count_many_users_posts() are cached. 611 * 612 * @ticket 63045 613 * 614 * @covers ::count_many_users_posts 615 */ 616 public function test_count_many_users_posts_is_cached() { 617 $user_1 = self::$user_ids[0]; 618 $user_2 = self::$user_ids[1]; 619 620 // Create posts for both users. 621 self::factory()->post->create( array( 'post_author' => $user_1 ) ); 622 self::factory()->post->create( array( 'post_author' => $user_2 ) ); 623 624 // Warm the cache. 625 $count1 = count_many_users_posts( array( $user_1, $user_2 ), 'post', false ); 626 627 // Ensure cache is hit for second call. 628 $start_queries = get_num_queries(); 629 $count2 = count_many_users_posts( array( $user_1, $user_2 ), 'post', false ); 630 $end_queries = get_num_queries(); 631 $this->assertSame( 0, $end_queries - $start_queries, 'No database queries expected for second call to count_many_users_posts()' ); 632 $this->assertSameSetsWithIndex( $count1, $count2, 'Expected same results from both calls to count_many_users_posts()' ); 633 } 634 635 /** 636 * Ensure equivalent arguments hit the same cache in count_many_users_posts(). 637 * 638 * @ticket 63045 639 * 640 * @covers ::count_many_users_posts 641 * 642 * @dataProvider data_count_many_users_posts_cached_for_equivalent_arguments 643 * 644 * @param array $first_args First set of arguments to pass to count_many_users_posts(). 645 * @param array $second_args Second set of arguments to pass to count_many_users_posts(). 646 */ 647 public function test_count_many_users_posts_cached_for_equivalent_arguments( $first_args, $second_args ) { 648 // Replace placeholder user IDs with real ones. 649 $first_args[0] = array_map( 650 static function ( $user ) { 651 return self::$user_ids[ $user ]; 652 }, 653 $first_args[0] 654 ); 655 $second_args[0] = array_map( 656 static function ( $user ) { 657 return self::$user_ids[ $user ]; 658 }, 659 $second_args[0] 660 ); 661 662 // Warm the cache with the first set of arguments. 663 $count1 = count_many_users_posts( ...$first_args ); 664 665 // Ensure the cache is hit for the second set of equivalent arguments. 666 $start_queries = get_num_queries(); 667 $count2 = count_many_users_posts( ...$second_args ); 668 $end_queries = get_num_queries(); 669 $this->assertSame( 0, $end_queries - $start_queries, 'No database queries expected for second call to count_many_users_posts() with equivalent arguments' ); 670 $this->assertSameSetsWithIndex( $count1, $count2, 'Expected same results from both calls to count_many_users_posts()' ); 671 } 672 673 /** 674 * Data provider for test_count_many_users_posts_cached_for_equivalent_arguments(). 675 * 676 * @return array[] Data provider. 677 */ 678 public function data_count_many_users_posts_cached_for_equivalent_arguments(): array { 679 return array( 680 'single post string vs array' => array( 681 array( array( 0 ), 'post' ), 682 array( array( 0 ), array( 'post' ) ), 683 ), 684 'duplicate post type in array' => array( 685 array( array( 0 ), array( 'post', 'post' ) ), 686 array( array( 0 ), array( 'post' ) ), 687 ), 688 'different post type order' => array( 689 array( array( 0 ), array( 'post', 'page' ) ), 690 array( array( 0 ), array( 'page', 'post' ) ), 691 ), 692 'duplicate user IDs in array' => array( 693 array( array( 0, 1, 1 ), 'post' ), 694 array( array( 0, 1 ), 'post' ), 695 ), 696 'different user order' => array( 697 array( array( 0, 1 ), 'post' ), 698 array( array( 1, 0 ), 'post' ), 699 ), 700 'integer vs string user IDs' => array( 701 array( array( 0, 1 ), 'post' ), 702 array( array( '0', '1' ), 'post' ), 703 ), 704 ); 705 } 706 707 /** 708 * Test cache invalidation for count_many_users_posts(). 709 * 710 * @ticket 63045 711 * 712 * @covers ::count_many_users_posts 713 */ 714 public function test_count_many_users_posts_cache_invalidation() { 715 $user_1 = self::$user_ids[0]; 716 $user_2 = self::$user_ids[1]; 717 718 // Create posts for both users. 719 self::factory()->post->create( array( 'post_author' => $user_1 ) ); 720 self::factory()->post->create( array( 'post_author' => $user_2 ) ); 721 722 $counts1 = count_many_users_posts( array( $user_1, $user_2 ), 'post', false ); 723 $this->assertSame( 724 array( 725 $user_1 => '1', 726 $user_2 => '1', 727 ), 728 $counts1, 729 'Initial call is expected to have one post for each user.' 730 ); 731 732 // Create another post for user 1. 733 self::factory()->post->create( array( 'post_author' => $user_1 ) ); 734 735 $counts2 = count_many_users_posts( array( $user_1, $user_2 ), 'post', false ); 736 $this->assertSame( 737 array( 738 $user_1 => '2', 739 $user_2 => '1', 740 ), 741 $counts2, 742 'Second call is expected to have two posts for user 1 and one post for user 2.' 743 ); 744 } 745 746 /** 747 * Ensure different post types use different caches in count_many_users_posts(). 748 * 749 * @ticket 63045 750 * 751 * @covers ::count_many_users_posts 752 */ 753 public function test_different_post_types_use_different_caches() { 754 $user_id = self::$user_ids[0]; 755 756 // Create one post and two pages for the user. 757 self::factory()->post->create( 758 array( 759 'post_author' => $user_id, 760 'post_type' => 'post', 761 ) 762 ); 763 self::factory()->post->create( 764 array( 765 'post_author' => $user_id, 766 'post_type' => 'page', 767 ) 768 ); 769 self::factory()->post->create( 770 array( 771 'post_author' => $user_id, 772 'post_type' => 'page', 773 ) 774 ); 775 776 $start_queries = get_num_queries(); 777 $count1 = count_many_users_posts( array( $user_id ), 'post', false ); 778 $end_queries = get_num_queries(); 779 $this->assertSame( 1, $end_queries - $start_queries, 'Expected to hit database for first call to count_many_users_posts() with post type "post".' ); 780 $this->assertSame( '1', $count1[ $user_id ], 'Expected to have one post for user with post type "post".' ); 781 782 $start_queries = get_num_queries(); 783 $count2 = count_many_users_posts( array( $user_id ), 'page', false ); 784 $end_queries = get_num_queries(); 785 $this->assertSame( 1, $end_queries - $start_queries, 'Expected to hit database for first call to count_many_users_posts() with post type "page".' ); 786 $this->assertSame( '2', $count2[ $user_id ], 'Expected to have two pages for user with post type "page".' ); 787 } 788 789 /** 790 * Ensure different users use different caches in count_many_users_posts(). 791 * 792 * @ticket 63045 793 * 794 * @covers ::count_many_users_posts 795 */ 796 public function test_different_users_use_different_caches() { 797 $user_1 = self::$user_ids[0]; 798 $user_2 = self::$user_ids[1]; 799 800 // Create one post for user 1, two for user 2. 801 self::factory()->post->create( 802 array( 803 'post_author' => $user_1, 804 'post_type' => 'post', 805 ) 806 ); 807 self::factory()->post->create( 808 array( 809 'post_author' => $user_2, 810 'post_type' => 'post', 811 ) 812 ); 813 self::factory()->post->create( 814 array( 815 'post_author' => $user_2, 816 'post_type' => 'post', 817 ) 818 ); 819 820 $start_queries = get_num_queries(); 821 $count1 = count_many_users_posts( array( $user_1 ), 'post', false ); 822 $end_queries = get_num_queries(); 823 $this->assertSame( 1, $end_queries - $start_queries, 'Expected to hit database for first call to count_many_users_posts() with user 1.' ); 824 $this->assertSame( '1', $count1[ $user_1 ], 'Expected to have one post for user 1 with post type "post".' ); 825 826 $start_queries = get_num_queries(); 827 $count2 = count_many_users_posts( array( $user_2 ), 'post', false ); 828 $end_queries = get_num_queries(); 829 $this->assertSame( 1, $end_queries - $start_queries, 'Expected to hit database for first call to count_many_users_posts() with user 2.' ); 830 $this->assertSame( '2', $count2[ $user_2 ], 'Expected to have two posts for user 2 with post type "post".' ); 605 831 } 606 832
Note: See TracChangeset
for help on using the changeset viewer.