Make WordPress Core


Ignore:
Timestamp:
09/21/2025 05:25:49 AM (12 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.