WordPress.org

Make WordPress Core

Ticket #48556: 48556.2.diff

File 48556.2.diff, 11.2 KB (added by boonebgorges, 9 months ago)
  • src/wp-includes/class-wp-query.php

    diff --git src/wp-includes/class-wp-query.php src/wp-includes/class-wp-query.php
    index 2f0dd53558..8305e03a2c 100644
    class WP_Query { 
    24202420                        $where .= $wpdb->prepare( " AND {$wpdb->posts}.ping_status = %s ", $q['ping_status'] );
    24212421                }
    24222422
     2423                $skip_post_status = false;
    24232424                if ( 'any' === $post_type ) {
    24242425                        $in_search_post_types = get_post_types( array( 'exclude_from_search' => false ) );
    24252426                        if ( empty( $in_search_post_types ) ) {
    2426                                 $where .= ' AND 1=0 ';
     2427                                $post_type_where  = ' AND 1=0 ';
     2428                                $skip_post_status = true;
    24272429                        } else {
    2428                                 $where .= " AND {$wpdb->posts}.post_type IN ('" . implode( "', '", array_map( 'esc_sql', $in_search_post_types ) ) . "')";
     2430                                $post_type_where = " AND {$wpdb->posts}.post_type IN ('" . implode( "', '", array_map( 'esc_sql', $in_search_post_types ) ) . "')";
    24292431                        }
    24302432                } elseif ( ! empty( $post_type ) && is_array( $post_type ) ) {
    2431                         $where .= " AND {$wpdb->posts}.post_type IN ('" . implode( "', '", esc_sql( $post_type ) ) . "')";
     2433                        $post_type_where = " AND {$wpdb->posts}.post_type IN ('" . implode( "', '", esc_sql( $post_type ) ) . "')";
    24322434                } elseif ( ! empty( $post_type ) ) {
    2433                         $where           .= $wpdb->prepare( " AND {$wpdb->posts}.post_type = %s", $post_type );
     2435                        $post_type_where  = $wpdb->prepare( " AND {$wpdb->posts}.post_type = %s", $post_type );
    24342436                        $post_type_object = get_post_type_object( $post_type );
    24352437                } elseif ( $this->is_attachment ) {
    2436                         $where           .= " AND {$wpdb->posts}.post_type = 'attachment'";
     2438                        $post_type_where  = " AND {$wpdb->posts}.post_type = 'attachment'";
    24372439                        $post_type_object = get_post_type_object( 'attachment' );
    24382440                } elseif ( $this->is_page ) {
    2439                         $where           .= " AND {$wpdb->posts}.post_type = 'page'";
     2441                        $post_type_where  = " AND {$wpdb->posts}.post_type = 'page'";
    24402442                        $post_type_object = get_post_type_object( 'page' );
    24412443                } else {
    2442                         $where           .= " AND {$wpdb->posts}.post_type = 'post'";
     2444                        $post_type_where  = " AND {$wpdb->posts}.post_type = 'post'";
    24432445                        $post_type_object = get_post_type_object( 'post' );
    24442446                }
    24452447
    class WP_Query { 
    24572459                $user_id = get_current_user_id();
    24582460
    24592461                $q_status = array();
    2460                 if ( ! empty( $q['post_status'] ) ) {
     2462                if ( $skip_post_status ) {
     2463                        $where .= $post_type_where;
     2464                } elseif ( ! empty( $q['post_status'] ) ) {
     2465
     2466                        $where .= $post_type_where;
     2467
    24612468                        $statuswheres = array();
    24622469                        $q_status     = $q['post_status'];
    24632470                        if ( ! is_array( $q_status ) ) {
    class WP_Query { 
    25162523                        if ( ! empty( $where_status ) ) {
    25172524                                $where .= " AND ($where_status)";
    25182525                        }
     2526
    25192527                } elseif ( ! $this->is_singular ) {
    2520                         $where .= " AND ({$wpdb->posts}.post_status = 'publish'";
    25212528
    2522                         // Add public states.
    2523                         $public_states = get_post_stati( array( 'public' => true ) );
    2524                         foreach ( (array) $public_states as $state ) {
    2525                                 if ( 'publish' === $state ) { // Publish is hard-coded above.
    2526                                         continue;
    2527                                 }
    2528                                 $where .= " OR {$wpdb->posts}.post_status = '$state'";
     2529                        if ( 'any' == $post_type ) {
     2530                                $queried_post_types = get_post_types( array( 'exclude_from_search' => false ) );
     2531                        } elseif ( is_array( $post_type ) ) {
     2532                                $queried_post_types = $post_type;
     2533                        } elseif ( ! empty( $post_type ) ) {
     2534                                $queried_post_types = array( $post_type );
     2535                        } else {
     2536                                $queried_post_types = array( 'post' );
    25292537                        }
    25302538
    2531                         if ( $this->is_admin ) {
    2532                                 // Add protected states that should show in the admin all list.
    2533                                 $admin_all_states = get_post_stati(
    2534                                         array(
    2535                                                 'protected'              => true,
    2536                                                 'show_in_admin_all_list' => true,
    2537                                         )
    2538                                 );
    2539                                 foreach ( (array) $admin_all_states as $state ) {
    2540                                         $where .= " OR {$wpdb->posts}.post_status = '$state'";
     2539                        if ( ! empty( $queried_post_types ) ) {
     2540
     2541                                $status_type_clauses = array();
     2542
     2543                                foreach ( $queried_post_types as $queried_post_type ) {
     2544
     2545                                        $queried_post_type_object = get_post_type_object( $queried_post_type );
     2546                                        if ( ! $queried_post_type_object instanceof \WP_Post_Type ) {
     2547                                                continue;
     2548                                        }
     2549
     2550                                        $type_where = '(' . $wpdb->prepare( "{$wpdb->posts}.post_type = %s AND (", $queried_post_type );
     2551
     2552                                        // Public statuses.
     2553                                        $public_statuses = get_post_stati( array( 'public' => true ) );
     2554                                        $status_clauses  = [];
     2555                                        foreach ( (array) $public_statuses as $public_status ) {
     2556                                                $status_clauses[] = "{$wpdb->posts}.post_status = '$public_status'";
     2557                                        }
     2558                                        $type_where .= implode( ' OR ', $status_clauses );
     2559
     2560                                        // Add protected states that should show in the admin all list.
     2561                                        if ( $this->is_admin ) {
     2562                                                $admin_all_statuses = get_post_stati(
     2563                                                        array(
     2564                                                                'protected'              => true,
     2565                                                                'show_in_admin_all_list' => true,
     2566                                                        )
     2567                                                );
     2568                                                foreach ( (array) $admin_all_statuses as $admin_all_status ) {
     2569                                                        $type_where .= " OR {$wpdb->posts}.post_status = '$admin_all_status'";
     2570                                                }
     2571                                        }
     2572
     2573                                        // Add private states that are visible to current user.
     2574                                        if ( is_user_logged_in() ) {
     2575                                                $read_private_cap = $queried_post_type_object->cap->read_private_posts;
     2576                                                $private_statuses = get_post_stati( array( 'private' => true ) );
     2577                                                foreach ( (array) $private_statuses as $private_status ) {
     2578                                                        $type_where .= current_user_can( $read_private_cap ) ? " \nOR {$wpdb->posts}.post_status = '$private_status'" : " \nOR ({$wpdb->posts}.post_author = $user_id AND {$wpdb->posts}.post_status = '$private_status')";
     2579                                                }
     2580                                        }
     2581
     2582                                        $type_where .= '))';
     2583
     2584                                        $status_type_clauses[] = $type_where;
    25412585                                }
    2542                         }
    25432586
    2544                         if ( is_user_logged_in() ) {
    2545                                 // Add private states that are limited to viewing by the author of a post or someone who has caps to read private states.
    2546                                 $private_states = get_post_stati( array( 'private' => true ) );
    2547                                 foreach ( (array) $private_states as $state ) {
    2548                                         $where .= current_user_can( $read_private_cap ) ? " OR {$wpdb->posts}.post_status = '$state'" : " OR {$wpdb->posts}.post_author = $user_id AND {$wpdb->posts}.post_status = '$state'";
     2587                                if ( ! empty( $status_type_clauses ) ) {
     2588                                        $where .= ' AND (' . implode( ' OR ', $status_type_clauses ) . ')';
    25492589                                }
     2590                        } else {
     2591                                $where .= ' AND 1=0 ';
    25502592                        }
    25512593
    2552                         $where .= ')';
     2594                } else {
     2595                        $where .= $post_type_where;
    25532596                }
    25542597
    25552598                /*
  • tests/phpunit/tests/query/postStatus.php

    diff --git tests/phpunit/tests/query/postStatus.php tests/phpunit/tests/query/postStatus.php
    index 7d4a236b50..244bfdc9e8 100644
     
    66class Tests_Query_PostStatus extends WP_UnitTestCase {
    77        public static $editor_user_id;
    88        public static $author_user_id;
     9        public static $subscriber_user_id;
    910        public static $editor_private_post;
    1011        public static $author_private_post;
    1112        public static $editor_privatefoo_post;
    1213        public static $author_privatefoo_post;
    1314
    1415        public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
    15                 self::$editor_user_id = $factory->user->create( array( 'role' => 'editor' ) );
    16                 self::$author_user_id = $factory->user->create( array( 'role' => 'author' ) );
     16                self::$editor_user_id     = $factory->user->create( array( 'role' => 'editor' ) );
     17                self::$author_user_id     = $factory->user->create( array( 'role' => 'author' ) );
     18                self::$subscriber_user_id = $factory->user->create( array( 'role' => 'subscriber' ) );
    1719
    1820                self::$editor_private_post = $factory->post->create(
    1921                        array(
    class Tests_Query_PostStatus extends WP_UnitTestCase { 
    457459
    458460                $this->assertContains( $p1, wp_list_pluck( $q->posts, 'ID' ) );
    459461        }
     462
     463        /**
     464         * @ticket 48556
     465         * @ticket 13509
     466         */
     467        public function test_non_singular_queries_using_post_type_any_should_respect_post_type_read_private_posts_cap() {
     468                register_post_type(
     469                        'wptests_pt1',
     470                        array(
     471                                'exclude_from_search' => false,
     472                                'capabilities'        => [
     473                                        'read_private_posts' => 'read_private_pt1s',
     474                                ],
     475                        )
     476                );
     477
     478                register_post_type(
     479                        'wptests_pt2',
     480                        array(
     481                                'exclude_from_search' => false,
     482                        )
     483                );
     484
     485                $post_ids = array();
     486
     487                $post_ids['wptests_pt1_p1'] = $this->factory->post->create(
     488                        array(
     489                                'post_type'   => 'wptests_pt1',
     490                                'post_status' => 'private',
     491                                'post_author' => self::$editor_user_id,
     492                        )
     493                );
     494
     495                $post_ids['wptests_pt1_p2'] = $this->factory->post->create(
     496                        array(
     497                                'post_type'   => 'wptests_pt1',
     498                                'post_status' => 'publish',
     499                                'post_author' => self::$editor_user_id,
     500                        )
     501                );
     502
     503                $post_ids['wptests_pt2_p1'] = $this->factory->post->create(
     504                        array(
     505                                'post_type'   => 'wptests_pt2',
     506                                'post_status' => 'private',
     507                                'post_author' => self::$editor_user_id,
     508                        )
     509                );
     510
     511                $post_ids['wptests_pt2_p2'] = $this->factory->post->create(
     512                        array(
     513                                'post_type'   => 'wptests_pt2',
     514                                'post_status' => 'publish',
     515                                'post_author' => self::$editor_user_id,
     516                        )
     517                );
     518
     519                wp_set_current_user( 0 );
     520
     521                $q = new WP_Query(
     522                        array(
     523                                'post_type' => 'any',
     524                        )
     525                );
     526
     527                $this->assertSameSets( array( $post_ids['wptests_pt1_p2'], $post_ids['wptests_pt2_p2'] ), wp_list_pluck( $q->posts, 'ID' ) );
     528
     529                wp_set_current_user( self::$subscriber_user_id );
     530                $GLOBALS['current_user']->add_cap( 'read_private_pt1s' );
     531
     532                $q = new WP_Query(
     533                        array(
     534                                'post_type' => 'any',
     535                        )
     536                );
     537
     538                $this->assertSameSets( array( $post_ids['wptests_pt1_p1'], $post_ids['wptests_pt1_p2'], $post_ids['wptests_pt2_p2'] ), wp_list_pluck( $q->posts, 'ID' ) );
     539        }
     540
     541        /**
     542         * @ticket 48556
     543         * @ticket 13509
     544         */
     545        public function test_non_singular_queries_using_multiple_post_type_should_respect_post_type_read_private_posts_cap() {
     546                wp_set_current_user( 0 );
     547
     548                register_post_type(
     549                        'wptests_pt1',
     550                        array(
     551                                'exclude_from_search' => false,
     552                                'capabilities'        => [
     553                                        'read_private_posts' => 'read_private_pt1s',
     554                                ],
     555                        )
     556                );
     557
     558                register_post_type(
     559                        'wptests_pt2',
     560                        array(
     561                                'exclude_from_search' => false,
     562                        )
     563                );
     564
     565                $post_ids = array();
     566
     567                $post_ids['wptests_pt1_p1'] = $this->factory->post->create(
     568                        array(
     569                                'post_type'   => 'wptests_pt1',
     570                                'post_status' => 'private',
     571                                'post_author' => self::$editor_user_id,
     572                        )
     573                );
     574
     575                $post_ids['wptests_pt1_p2'] = $this->factory->post->create(
     576                        array(
     577                                'post_type'   => 'wptests_pt1',
     578                                'post_status' => 'publish',
     579                                'post_author' => self::$editor_user_id,
     580                        )
     581                );
     582
     583                $post_ids['wptests_pt2_p1'] = $this->factory->post->create(
     584                        array(
     585                                'post_type'   => 'wptests_pt2',
     586                                'post_status' => 'private',
     587                                'post_author' => self::$editor_user_id,
     588                        )
     589                );
     590
     591                $post_ids['wptests_pt2_p2'] = $this->factory->post->create(
     592                        array(
     593                                'post_type'   => 'wptests_pt2',
     594                                'post_status' => 'publish',
     595                                'post_author' => self::$editor_user_id,
     596                        )
     597                );
     598
     599                $q = new WP_Query(
     600                        array(
     601                                'post_type' => 'any',
     602                        )
     603                );
     604
     605                $this->assertSameSets( array( $post_ids['wptests_pt1_p2'], $post_ids['wptests_pt2_p2'] ), wp_list_pluck( $q->posts, 'ID' ) );
     606
     607                $u = $this->factory->user->create();
     608
     609                wp_set_current_user( self::$subscriber_user_id );
     610                $GLOBALS['current_user']->add_cap( 'read_private_pt1s' );
     611
     612                $q = new WP_Query(
     613                        array(
     614                                'post_type' => [ 'wptests_pt1', 'wptests_pt2' ],
     615                        )
     616                );
     617
     618                $this->assertSameSets( array( $post_ids['wptests_pt1_p1'], $post_ids['wptests_pt1_p2'], $post_ids['wptests_pt2_p2'] ), wp_list_pluck( $q->posts, 'ID' ) );
     619        }
    460620}