diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index c297864859aa4..d9059103b7802 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -5290,20 +5290,41 @@ function _wp_to_kebab_case( $input_string ) { /** * Determines if the variable is a numeric-indexed array. * + * Note! This answers a different question than {@see array_is_list()} and is + * more flexible to handle situations where some numeric array indices + * have been removed. A numeric-indexed array is only a “list” when the + * array keys form a contiguous range from zero to the highest key. + * + * Example: + * + * true === wp_is_numeric_array( array( 1, 2, 3, 4 ) ); + * false === wp_is_numeric_array( array( 'name' => 'WordPress' ) ); + * + * // All-numeric keys vs. list. + * $above_two = array_filter( array( 1, 2, 8, 9 ), fn ( $v ) => $v > 2 ); + * $above_two === array( '2' => 8, '3' => 9 ); + * true === wp_is_numeric_array( $above_two ); + * false === array_is_list( $above_two ); + * * @since 4.4.0 * * @param mixed $data Variable to check. * @return bool Whether the variable is a list. + * + * @phpstan-assert-if-true array $data */ -function wp_is_numeric_array( $data ) { +function wp_is_numeric_array( $data ): bool { if ( ! is_array( $data ) ) { return false; } - $keys = array_keys( $data ); - $string_keys = array_filter( $keys, 'is_string' ); + foreach ( $data as $key => $value ) { + if ( is_string( $key ) ) { + return false; + } + } - return count( $string_keys ) === 0; + return true; } /** diff --git a/tests/phpunit/tests/functions/wpIsNumericArray.php b/tests/phpunit/tests/functions/wpIsNumericArray.php index 4eeab0af81f2a..4bf7b0cc1695b 100644 --- a/tests/phpunit/tests/functions/wpIsNumericArray.php +++ b/tests/phpunit/tests/functions/wpIsNumericArray.php @@ -26,27 +26,34 @@ public function test_wp_is_numeric_array( $input, $expected ) { */ public function data_wp_is_numeric_array() { return array( - 'no index' => array( + 'no index' => array( 'test_array' => array( 'www', 'eee' ), 'expected' => true, ), - 'text index' => array( + 'text index' => array( 'test_array' => array( 'www' => 'eee' ), 'expected' => false, ), - 'numeric index' => array( + 'numeric index' => array( 'test_array' => array( 99 => 'eee' ), 'expected' => true, ), - '- numeric index' => array( + 'filtered list (missing numeric keys)' => array( + 'test_array' => array_filter( + array( 1, 12, 13, 15, 16, 17, 20 ), + fn ( $v ) => 0 === $v % 2 + ), + 'expected' => true, + ), + '- numeric index' => array( 'test_array' => array( -11 => 'eee' ), 'expected' => true, ), - 'numeric string index' => array( + 'numeric string index' => array( 'test_array' => array( '11' => 'eee' ), 'expected' => true, ), - 'nested number index' => array( + 'nested number index' => array( 'test_array' => array( 'next' => array( 11 => 'vvv', @@ -54,7 +61,7 @@ public function data_wp_is_numeric_array() { ), 'expected' => false, ), - 'nested string index' => array( + 'nested string index' => array( 'test_array' => array( '11' => array( 'eee' => 'vvv', @@ -62,7 +69,7 @@ public function data_wp_is_numeric_array() { ), 'expected' => true, ), - 'not an array' => array( + 'not an array' => array( 'test_array' => null, 'expected' => false, ),