diff --git a/src/wp-includes/class-wp-locale.php b/src/wp-includes/class-wp-locale.php index 841007f15a6c1..20931182e5b39 100644 --- a/src/wp-includes/class-wp-locale.php +++ b/src/wp-includes/class-wp-locale.php @@ -318,8 +318,6 @@ public function get_weekday_abbrev( $weekday_name ) { * * @param string|int $month_number '01' through '12'. * @return string Translated full month name. If the month number is not found, an empty string is returned. - * - * @phpstan-param int<1, 12>|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'10'|'11'|'12'|'01'|'02'|'03'|'04'|'05'|'06'|'07'|'08'|'09' $month_number */ public function get_month( $month_number ) { $month_number = zeroise( $month_number, 2 ); diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 3b9e247fd44fd..afa066aa8c8a7 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -258,6 +258,11 @@ function wp_date( $format, $timestamp = null, $timezone = null ) { } $datetime = date_create( '@' . $timestamp ); + + if ( false === $datetime ) { + return false; + } + $datetime->setTimezone( $timezone ); if ( empty( $wp_locale->month ) || empty( $wp_locale->weekday ) ) { @@ -269,7 +274,7 @@ function wp_date( $format, $timestamp = null, $timezone = null ) { $new_format = ''; $format_length = strlen( $format ); $month = $wp_locale->get_month( $datetime->format( 'm' ) ); - $weekday = $wp_locale->get_weekday( $datetime->format( 'w' ) ); + $weekday = $wp_locale->get_weekday( (int) $datetime->format( 'w' ) ); for ( $i = 0; $i < $format_length; $i++ ) { switch ( $format[ $i ] ) { diff --git a/src/wp-includes/general-template.php b/src/wp-includes/general-template.php index 5d6786db99bc8..df15e864e8c44 100644 --- a/src/wp-includes/general-template.php +++ b/src/wp-includes/general-template.php @@ -2666,7 +2666,7 @@ function get_calendar( $args = array() ) { } // week_begins = 0 stands for Sunday. - $week_begins = (int) get_option( 'start_of_week' ); + $week_begins = clamp( (int) get_option( 'start_of_week' ), 0, 6 ); // Read the current date. list( $current_year, $current_month, $current_day ) = array_map( 'intval', explode( '-', current_time( 'Y-m-j' ) ) ); @@ -3181,7 +3181,21 @@ function get_the_time( $format = '', $post = null ) { * @return string|int|false Formatted date string or Unix timestamp if `$format` is 'U' or 'G'. * False on failure. * - * @phpstan-return ( $format is 'U'|'G' ? int|false : string|false ) + * @phpstan-return ( + * $format is 'U'|'G' ? int|false : ( + * $format is 'w' ? '0'|'1'|'2'|'3'|'4'|'5'|'6'|false : ( + * $format is 'N' ? '1'|'2'|'3'|'4'|'5'|'6'|'7'|false : ( + * $format is 'L'|'I' ? '0'|'1'|false : ( + * $format is 't' ? '28'|'29'|'30'|'31'|false : ( + * $format is 'm'|'h' ? '01'|'02'|'03'|'04'|'05'|'06'|'07'|'08'|'09'|'10'|'11'|'12'|false : ( + * $format is 'n'|'g' ? '1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'10'|'11'|'12'|false : ( + * $format is 'H' ? '00'|'01'|'02'|'03'|'04'|'05'|'06'|'07'|'08'|'09'|'10'|'11'|'12'|'13'|'14'|'15'|'16'|'17'|'18'|'19'|'20'|'21'|'22'|'23'|false : ( + * $format is 'd' ? '01'|'02'|'03'|'04'|'05'|'06'|'07'|'08'|'09'|'10'|'11'|'12'|'13'|'14'|'15'|'16'|'17'|'18'|'19'|'20'|'21'|'22'|'23'|'24'|'25'|'26'|'27'|'28'|'29'|'30'|'31'|false : ( + * $format is 'j' ? '1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'10'|'11'|'12'|'13'|'14'|'15'|'16'|'17'|'18'|'19'|'20'|'21'|'22'|'23'|'24'|'25'|'26'|'27'|'28'|'29'|'30'|'31'|false : ( + * $format is 'z'|'W'|'o'|'Y'|'y'|'B'|'i'|'s'|'u'|'v'|'Z' ? numeric-string|false : + * string|false + * ) ) ) ) ) ) ) ) ) ) + * ) */ function get_post_time( $format = 'U', $gmt = false, $post = null, $translate = false ) { $post = get_post( $post ); @@ -3436,7 +3450,13 @@ function the_weekday() { return; } - $the_weekday = $wp_locale->get_weekday( get_post_time( 'w', false, $post ) ); + $weekday_number = get_post_time( 'w', false, $post ); + + if ( false === $weekday_number ) { + return; + } + + $the_weekday = $wp_locale->get_weekday( (int) $weekday_number ); /** * Filters the localized weekday of the post, for display. @@ -3473,10 +3493,11 @@ function the_weekday_date( $before = '', $after = '' ) { } $the_weekday_date = ''; + $weekday_number = get_post_time( 'w', false, $post ); - if ( $currentday !== $previousweekday ) { + if ( false !== $weekday_number && $currentday !== $previousweekday ) { $the_weekday_date .= $before; - $the_weekday_date .= $wp_locale->get_weekday( get_post_time( 'w', false, $post ) ); + $the_weekday_date .= $wp_locale->get_weekday( (int) $weekday_number ); $the_weekday_date .= $after; $previousweekday = $currentday; } diff --git a/tests/phpstan/baselines/argument.type.neon b/tests/phpstan/baselines/argument.type.neon index df374a6cd9c83..03306758d5130 100644 --- a/tests/phpstan/baselines/argument.type.neon +++ b/tests/phpstan/baselines/argument.type.neon @@ -903,11 +903,6 @@ parameters: identifier: argument.type count: 2 path: ../../../src/wp-includes/functions.php - - - message: '#^Parameter \#1 \$weekday_number of method WP_Locale\:\:get_weekday\(\) expects int\<0, 6\>, ''0''\|''1''\|''2''\|''3''\|''4''\|''5''\|''6'' given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/functions.php - message: '#^Parameter \#2 \$fallback_url of function wp_validate_redirect expects string, false given\.$#' identifier: argument.type @@ -953,11 +948,6 @@ parameters: identifier: argument.type count: 2 path: ../../../src/wp-includes/general-template.php - - - message: '#^Parameter \#1 \$weekday_number of method WP_Locale\:\:get_weekday\(\) expects int\<0, 6\>, string\|false given\.$#' - identifier: argument.type - count: 2 - path: ../../../src/wp-includes/general-template.php - message: '#^Parameter \#2 \$replace of function str_replace expects array\\|string, int\<1, max\> given\.$#' identifier: argument.type diff --git a/tests/phpunit/tests/date/wpDate.php b/tests/phpunit/tests/date/wpDate.php index cff2f11967f3b..ef051fe8bd058 100644 --- a/tests/phpunit/tests/date/wpDate.php +++ b/tests/phpunit/tests/date/wpDate.php @@ -34,6 +34,32 @@ public function test_should_return_false_on_invalid_timestamp() { $this->assertFalse( wp_date( DATE_RFC3339, 'invalid' ) ); } + /** + * Tests that a numeric timestamp which {@see date_create()} cannot parse returns false. + * + * @dataProvider data_should_return_false_on_unparsable_numeric_timestamp + * + * @param int|float|string $timestamp Numeric timestamp. + */ + public function test_should_return_false_on_unparsable_numeric_timestamp( $timestamp ): void { + $this->assertTrue( is_numeric( $timestamp ), 'Expected the timestamp to pass the is_numeric() check.' ); + $this->assertFalse( wp_date( DATE_RFC3339, $timestamp ) ); // @phpstan-ignore argument.type (Intentionally invalid input.) + } + + /** + * Data provider for {@see self::test_should_return_false_on_unparsable_numeric_timestamp()}. + * + * @return array + */ + public static function data_should_return_false_on_unparsable_numeric_timestamp(): array { + return array( + 'exponent notation' => array( '1e3' ), + 'out-of-range float' => array( 1e20 ), + 'leading whitespace' => array( ' 5' ), + 'leading decimal' => array( '.5' ), + ); + } + /** * @ticket 48319 */