Commit 9fa0650492 for wordpress.org

commit 9fa06504926524d2aeb454e27995d71544ad9a3d
Author: westonruter <westonruter@git.wordpress.org>
Date:   Fri Oct 9 03:01:53 2026 +0000

    Feeds: Fix feed build date for ID-only and partial queries.

    When the main query used `fields => 'ids'`, `get_feed_build_date()` passed the integer IDs to `wp_list_pluck()`, which could not read `post_modified_gmt` from them and returned an empty array, so `max()` threw a `ValueError` on PHP 8 and broke the feed. With `fields => 'id=>parent'`, the partial objects lack `post_modified_gmt`, producing a bogus build date. Post IDs and partial objects are now resolved to posts after priming the post cache in a single query, while `WP_Post` objects are read as-is so that virtual posts and in-memory changes are respected. An empty list of modified times now falls back to the last modified time of any post instead of reaching `max()`.

    The `have_posts()` check is also removed, since it has side effects: for an empty query it fires the `loop_no_results` action from the feed header before the template's own loop runs, and after a completed loop it fires `loop_end` and rewinds the posts. Comments that a `get_comment` filter returned null for are skipped. These changes also resolve the PHPStan errors that were reported in the function.

    Developed in https://github.com/WordPress/wordpress-develop/pull/11387.
    Follow-up to r44948, r46974.

    Props extrachill, westonruter, janareddy, hellofromtonya, wildworks.
    See #65817.
    Fixes #59956.

    Built from https://develop.svn.wordpress.org/trunk@64247


    git-svn-id: http://core.svn.wordpress.org/trunk@63398 1a063a9b-81f0-0310-95a4-ce76da25c4cd

diff --git a/wp-includes/feed.php b/wp-includes/feed.php
index 7f9b977656..952194c1bc 100644
--- a/wp-includes/feed.php
+++ b/wp-includes/feed.php
@@ -854,21 +854,56 @@ function get_feed_build_date( $format ) {
 	$max_modified_time = false;
 	$utc               = new DateTimeZone( 'UTC' );

-	if ( ! empty( $wp_query ) && $wp_query->have_posts() ) {
-		// Extract the post modified times from the posts.
-		$modified_times = wp_list_pluck( $wp_query->posts, 'post_modified_gmt' );
+	if ( $wp_query instanceof WP_Query && is_array( $wp_query->posts ) ) {
+		/*
+		 * Collect the post modified times. WP_Post objects are read as-is, since
+		 * passing them through get_post() would look them up again by ID, which
+		 * drops virtual posts and discards in-memory changes. Queries using
+		 * fields => 'ids' (or 'id=>parent') yield post IDs instead, which are
+		 * looked up after priming the post cache to avoid a query per post.
+		 */
+		$modified_times = array();
+		$post_ids       = array();
+		foreach ( $wp_query->posts as $post ) {
+			if ( $post instanceof WP_Post ) {
+				$modified_times[] = $post->post_modified_gmt;
+			} elseif ( is_int( $post ) ) {
+				// A post ID, from a query with fields => 'ids'.
+				$post_ids[] = $post;
+			} elseif ( is_object( $post ) && isset( $post->ID ) && is_int( $post->ID ) ) {
+				/*
+				 * A partial post object of shape object{ ID: int, post_parent: int },
+				 * from a query with fields => 'id=>parent'. It lacks post_modified_gmt,
+				 * so the post is looked up by its ID.
+				 */
+				$post_ids[] = $post->ID;
+			}
+		}

-		// If this is a comment feed, check those objects too.
-		if ( $wp_query->is_comment_feed() && $wp_query->comment_count ) {
-			// Extract the comment modified times from the comments.
-			$comment_times = wp_list_pluck( $wp_query->comments, 'comment_date_gmt' );
+		if ( $post_ids ) {
+			_prime_post_caches( $post_ids, false, false );
+			foreach ( $post_ids as $post_id ) {
+				$post = get_post( $post_id );
+				if ( $post instanceof WP_Post ) {
+					$modified_times[] = $post->post_modified_gmt;
+				}
+			}
+		}

-			// Add the comment times to the post times for comparison.
-			$modified_times = array_merge( $modified_times, $comment_times );
+		// If this is a comment feed, check those objects too.
+		if ( $wp_query->is_comment_feed() && is_array( $wp_query->comments ) ) {
+			foreach ( $wp_query->comments as $comment ) {
+				// A 'get_comment' filter may have returned null for a comment.
+				if ( $comment instanceof WP_Comment ) {
+					$modified_times[] = $comment->comment_date_gmt;
+				}
+			}
 		}

 		// Determine the maximum modified time.
-		$datetime = date_create_immutable_from_format( 'Y-m-d H:i:s', max( $modified_times ), $utc );
+		if ( $modified_times ) {
+			$datetime = date_create_immutable_from_format( 'Y-m-d H:i:s', max( $modified_times ), $utc );
+		}
 	}

 	if ( false === $datetime ) {
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 028cec25f1..201169a775 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.2-alpha-64246';
+$wp_version = '7.2-alpha-64247';

 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.