Make WordPress Core


Ignore:
Timestamp:
03/16/2025 10:55:11 PM (13 months ago)
Author:
peterwilsoncc
Message:

Query: Fix performance regression starting the loop for all fields.

Fixes a performance regression starting the loop after calling WP_Query( [ 'fields' => 'all' ] ). This changes how WP_Query::the_post() determines whether there is a need to traverse the posts for cache warming.

If IDs are queried, WP_Query::$posts is assumed to be an array of post IDs. If all fields are queried, WP_Query::$posts is assumed to be an array of fully populated post objects.

Follow up to [59919], [59937].

Props joemcgill, peterwilsoncc, SirLouen.
Fixes #56992.

File:
1 edited

Legend:

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

    r59976 r59993  
    20682068                $fields = "{$wpdb->posts}.ID, {$wpdb->posts}.post_parent";
    20692069                break;
     2070            case '':
     2071                /*
     2072                 * Set the default to 'all'.
     2073                 *
     2074                 * This is used in `WP_Query::the_post` to determine if the
     2075                 * entire post object has been queried.
     2076                 */
     2077                $q['fields'] = 'all';
     2078                // Falls through.
    20702079            default:
    20712080                $fields = "{$wpdb->posts}.*";
     
    37403749
    37413750        if ( ! $this->in_the_loop ) {
    3742             // Get post IDs to prime incomplete post objects.
    3743             $post_ids = array_reduce(
    3744                 $this->posts,
    3745                 function ( $carry, $post ) {
    3746                     if ( is_numeric( $post ) && $post > 0 ) {
    3747                         // Query for post ID.
    3748                         $carry[] = $post;
    3749                     }
    3750 
    3751                     if ( is_object( $post ) && isset( $post->ID ) ) {
    3752                         // Query for object, either WP_Post or stdClass.
    3753                         $carry[] = $post->ID;
    3754                     }
    3755 
    3756                     return $carry;
    3757                 },
    3758                 array()
    3759             );
    3760             if ( $post_ids ) {
     3751            if ( 'all' === $this->query_vars['fields'] ) {
     3752                // Full post objects queried.
     3753                $post_objects = $this->posts;
     3754            } else {
     3755                if ( 'ids' === $this->query_vars['fields'] ) {
     3756                    // Post IDs queried.
     3757                    $post_ids = $this->posts;
     3758                } else {
     3759                    // Only partial objects queried, need to prime the cache for the loop.
     3760                    $post_ids = array_reduce(
     3761                        $this->posts,
     3762                        function ( $carry, $post ) {
     3763                            if ( isset( $post->ID ) ) {
     3764                                $carry[] = $post->ID;
     3765                            }
     3766
     3767                            return $carry;
     3768                        },
     3769                        array()
     3770                    );
     3771                }
    37613772                _prime_post_caches( $post_ids, $this->query_vars['update_post_term_cache'], $this->query_vars['update_post_meta_cache'] );
    3762             }
    3763             $post_objects = array_map( 'get_post', $post_ids );
     3773                $post_objects = array_map( 'get_post', $post_ids );
     3774            }
    37643775            update_post_author_caches( $post_objects );
    37653776        }
     
    37823793
    37833794        // Ensure a full post object is available.
    3784         if ( $post instanceof stdClass ) {
    3785             // stdClass indicates that a partial post object was queried.
    3786             $post = get_post( $post->ID );
    3787         } elseif ( is_numeric( $post ) ) {
    3788             // Numeric indicates that only post IDs were queried.
    3789             $post = get_post( $post );
     3795        if ( 'all' !== $this->query_vars['fields'] ) {
     3796            if ( 'ids' === $this->query_vars['fields'] ) {
     3797                // Post IDs queried.
     3798                $post = get_post( $post );
     3799            } elseif ( isset( $post->ID ) ) {
     3800                /*
     3801                 * Partial objecct queried.
     3802                 *
     3803                 * The post object was queried with a partial set of
     3804                 * fields, populate the entire object for the loop.
     3805                 */
     3806                $post = get_post( $post->ID );
     3807            }
    37903808        }
    37913809
Note: See TracChangeset for help on using the changeset viewer.