Make WordPress Core


Ignore:
Timestamp:
09/21/2025 05:25:49 AM (8 months ago)
Author:
westonruter
Message:

Posts, Post Types: Improve wp_count_posts() query performance for users who cannot read_private_posts.

The query is refactored to use two subqueries which can leverage DB indexes.

Props rcorrales, snehapatil02, sirlouen, sajjad67, pbearne, johnbillion, westonruter.
Fixes #61097.

File:
1 edited

Legend:

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

    r60724 r60788  
    34013401    }
    34023402
    3403     $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
    3404 
    3405     if ( 'readable' === $perm && is_user_logged_in() ) {
    3406         $post_type_object = get_post_type_object( $type );
    3407         if ( ! current_user_can( $post_type_object->cap->read_private_posts ) ) {
    3408             $query .= $wpdb->prepare(
    3409                 " AND (post_status != 'private' OR ( post_author = %d AND post_status = 'private' ))",
    3410                 get_current_user_id()
    3411             );
    3412         }
    3413     }
    3414 
    3415     $query .= ' GROUP BY post_status';
    3416 
    3417     $results = (array) $wpdb->get_results( $wpdb->prepare( $query, $type ), ARRAY_A );
     3403    if (
     3404        'readable' === $perm &&
     3405        is_user_logged_in() &&
     3406        ! current_user_can( get_post_type_object( $type )->cap->read_private_posts )
     3407    ) {
     3408        // Optimized query uses subqueries which can leverage DB indexes for better performance. See #61097.
     3409        $query = $wpdb->prepare(
     3410            "
     3411            SELECT post_status, COUNT(*) AS num_posts
     3412            FROM (
     3413                SELECT post_status
     3414                FROM {$wpdb->posts}
     3415                WHERE post_type = %s AND post_status != 'private'
     3416                UNION ALL
     3417                SELECT post_status
     3418                FROM {$wpdb->posts}
     3419                WHERE post_type = %s AND post_status = 'private' AND post_author = %d
     3420            ) AS filtered_posts
     3421            ",
     3422            $type,
     3423            $type,
     3424            get_current_user_id()
     3425        );
     3426    } else {
     3427        $query = $wpdb->prepare(
     3428            "
     3429            SELECT post_status, COUNT(*) AS num_posts
     3430            FROM {$wpdb->posts}
     3431            WHERE post_type = %s
     3432            ",
     3433            $type
     3434        );
     3435    }
     3436
     3437    $query  .= ' GROUP BY post_status';
     3438    $results = (array) $wpdb->get_results( $query, ARRAY_A );
    34183439    $counts  = array_fill_keys( get_post_stati(), 0 );
    34193440
Note: See TracChangeset for help on using the changeset viewer.