Make WordPress Core


Ignore:
Timestamp:
06/30/2021 04:59:10 AM (3 years ago)
Author:
peterwilsoncc
Message:

Query: Check each post-type's capabilities when querying multiple post-types.

When querying multiple post types, check the read_private_posts capability for each post type when determining which post statuses to return. This ensures private posts appear in search results and archives for users permitted to read them.

Props leogermani, hellofromTonya, jeffpaul, peterwilsoncc.
Fixes #48556.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-query.php

    r50576 r51276  
    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        }
     
    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'];
     
    25182525            }
    25192526        } elseif ( ! $this->is_singular ) {
    2520             $where .= " AND ({$wpdb->posts}.post_status = 'publish'";
    2521 
    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             }
    2530 
    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'";
    2541                 }
    2542             }
    2543 
    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'";
    2549                 }
    2550             }
    2551 
    2552             $where .= ')';
     2527            if ( 'any' === $post_type ) {
     2528                $queried_post_types = get_post_types( array( 'exclude_from_search' => false ) );
     2529            } elseif ( is_array( $post_type ) ) {
     2530                $queried_post_types = $post_type;
     2531            } elseif ( ! empty( $post_type ) ) {
     2532                $queried_post_types = array( $post_type );
     2533            } else {
     2534                $queried_post_types = array( 'post' );
     2535            }
     2536
     2537            if ( ! empty( $queried_post_types ) ) {
     2538
     2539                $status_type_clauses = array();
     2540
     2541                foreach ( $queried_post_types as $queried_post_type ) {
     2542
     2543                    $queried_post_type_object = get_post_type_object( $queried_post_type );
     2544
     2545                    $type_where = '(' . $wpdb->prepare( "{$wpdb->posts}.post_type = %s AND (", $queried_post_type );
     2546
     2547                    // Public statuses.
     2548                    $public_statuses = get_post_stati( array( 'public' => true ) );
     2549                    $status_clauses  = array();
     2550                    foreach ( (array) $public_statuses as $public_status ) {
     2551                        $status_clauses[] = "{$wpdb->posts}.post_status = '$public_status'";
     2552                    }
     2553                    $type_where .= implode( ' OR ', $status_clauses );
     2554
     2555                    // Add protected states that should show in the admin all list.
     2556                    if ( $this->is_admin ) {
     2557                        $admin_all_statuses = get_post_stati(
     2558                            array(
     2559                                'protected'              => true,
     2560                                'show_in_admin_all_list' => true,
     2561                            )
     2562                        );
     2563                        foreach ( (array) $admin_all_statuses as $admin_all_status ) {
     2564                            $type_where .= " OR {$wpdb->posts}.post_status = '$admin_all_status'";
     2565                        }
     2566                    }
     2567
     2568                    // Add private states that are visible to current user.
     2569                    if ( is_user_logged_in() && $queried_post_type_object instanceof WP_Post_Type ) {
     2570                        $read_private_cap = $queried_post_type_object->cap->read_private_posts;
     2571                        $private_statuses = get_post_stati( array( 'private' => true ) );
     2572                        foreach ( (array) $private_statuses as $private_status ) {
     2573                            $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')";
     2574                        }
     2575                    }
     2576
     2577                    $type_where .= '))';
     2578
     2579                    $status_type_clauses[] = $type_where;
     2580                }
     2581
     2582                if ( ! empty( $status_type_clauses ) ) {
     2583                    $where .= ' AND (' . implode( ' OR ', $status_type_clauses ) . ')';
     2584                }
     2585            } else {
     2586                $where .= ' AND 1=0 ';
     2587            }
     2588        } else {
     2589            $where .= $post_type_where;
    25532590        }
    25542591
Note: See TracChangeset for help on using the changeset viewer.