From a4b65bfca8b11f4c2b3431fff02278ba59041e05 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Tue, 17 Dec 2019 20:41:09 +0000 Subject: [PATCH] Date/Time: Ensure that `get_feed_build_date()` correctly handles a modified post object with invalid date. * Clarify in the documentation that the function returns `false` on failure. * Consistently pass the return value through the `get_feed_build_date` filter. Props Rarst, dd32, azaozz, tellyworth. Fixes #48957. git-svn-id: https://develop.svn.wordpress.org/trunk@46974 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/feed.php | 60 ++++++++++--------- tests/phpunit/tests/date/getFeedBuildDate.php | 42 +++++++++++++ 2 files changed, 74 insertions(+), 28 deletions(-) diff --git a/src/wp-includes/feed.php b/src/wp-includes/feed.php index 54f7bcdf52..c0b75016e3 100644 --- a/src/wp-includes/feed.php +++ b/src/wp-includes/feed.php @@ -648,55 +648,59 @@ function self_link() { } /** - * Get the timestamp of the most recently modified post from WP_Query. + * Get the UTC time of the most recently modified post from WP_Query. * - * If viewing a comment feed, the timestamp of the most recently modified + * If viewing a comment feed, the time of the most recently modified * comment will be returned. * * @global WP_Query $wp_query WordPress Query object. * * @since 5.2.0 * - * @param string $format Format of the timestamp to return, passed to mysql2date. - * - * @return string The timestamp. + * @param string $format Date format string to return the time in. + * @return string|false The time in requested format, or false on failure. */ function get_feed_build_date( $format ) { global $wp_query; - if ( empty( $wp_query ) || ! $wp_query->have_posts() ) { - // Fallback to last time any post was modified or published. - return get_lastpostmodified( 'GMT' ); + $datetime = false; + $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 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' ); + + // Add the comment times to the post times for comparison. + $modified_times = array_merge( $modified_times, $comment_times ); + } + + // Determine the maximum modified time. + $datetime = date_create_immutable_from_format( 'Y-m-d H:i:s', max( $modified_times ), $utc ); } - // Extract the post modified times from the posts. - $modified_times = wp_list_pluck( $wp_query->posts, 'post_modified_gmt' ); - - // 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' ); - - // Add the comment times to the post times for comparison. - $modified_times = array_merge( $modified_times, $comment_times ); + if ( false === $datetime ) { + // Fall back to last time any post was modified or published. + $datetime = date_create_immutable_from_format( 'Y-m-d H:i:s', get_lastpostmodified( 'GMT' ), $utc ); } - // Determine the maximum modified time. - $datetime = date_create_immutable_from_format( - 'Y-m-d H:i:s', - max( $modified_times ), - new DateTimeZone( 'UTC' ) - ); - - $max_modified_time = $datetime->format( $format ); + if ( false !== $datetime ) { + $max_modified_time = $datetime->format( $format ); + } /** * Filters the date the last post or comment in the query was modified. * * @since 5.2.0 * - * @param string $max_modified_time Date the last post or comment was modified in the query. - * @param string $format The date format requested in get_feed_build_date. + * @param string|false $max_modified_time Date the last post or comment was modified in the query, in UTC. + * False on failure. + * @param string $format The date format requested in get_feed_build_date(). */ return apply_filters( 'get_feed_build_date', $max_modified_time, $format ); } diff --git a/tests/phpunit/tests/date/getFeedBuildDate.php b/tests/phpunit/tests/date/getFeedBuildDate.php index 402a6b4086..455bfa0b80 100644 --- a/tests/phpunit/tests/date/getFeedBuildDate.php +++ b/tests/phpunit/tests/date/getFeedBuildDate.php @@ -37,4 +37,46 @@ class Tests_Date_Get_Feed_Build_Date extends WP_UnitTestCase { $this->assertEquals( '2018-07-23T03:13:23+00:00', get_feed_build_date( DATE_RFC3339 ) ); } + + /** + * Test that get_feed_build_date() works with invalid post dates. + * + * @ticket 48957 + */ + public function test_should_fall_back_to_last_post_modified() { + global $wp_query; + + update_option( 'timezone_string', 'Europe/Kiev' ); + $datetime = new DateTimeImmutable( 'now', wp_timezone() ); + $datetime_utc = $datetime->setTimezone( new DateTimeZone( 'UTC' ) ); + + $wp_query->posts = array(); + + $this->assertFalse( get_feed_build_date( DATE_RFC3339 ), 'False when unable to determine valid time' ); + + $this->factory->post->create( + array( + 'post_date' => $datetime->format( 'Y-m-d H:i:s' ), + ) + ); + + $this->assertEquals( + $datetime_utc->format( DATE_RFC3339 ), + get_feed_build_date( DATE_RFC3339 ), + 'Fall back to time of last post modified with no posts' + ); + + $post_id_broken = $this->factory->post->create(); + $post_broken = get_post( $post_id_broken ); + + $post_broken->post_modified_gmt = 0; + + $wp_query->posts = array( $post_broken ); + + $this->assertEquals( + $datetime_utc->format( DATE_RFC3339 ), + get_feed_build_date( DATE_RFC3339 ), + 'Fall back to time of last post modified with broken post object' + ); + } }