From f387644535dacfdb9014c775baaa20603a527835 Mon Sep 17 00:00:00 2001 From: adamsilverstein Date: Thu, 22 Oct 2026 11:17:32 -0700 Subject: [PATCH] REST API: Sanitize comment statuses in a single pass. Replace the chained array_map/array_unique/array_filter/array_values calls in sanitize_comment_statuses() with one loop, avoiding the intermediate arrays. Behavior is unchanged; add test cases covering duplicates that only collide after sanitizing, empty values inside an array, and non-scalar values. Follow-up to a review suggestion on https://github.com/WordPress/wordpress-develop/pull/9870. See #63982. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015KyhSZWbcaixA5gHomFjXT --- .../class-wp-rest-comments-controller.php | 28 +++++++++++++------ .../rest-api/rest-comments-controller.php | 21 ++++++++------ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php index 61087ef598b40..0782bcc5ab998 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php @@ -2531,17 +2531,29 @@ protected function check_is_comment_content_allowed( $prepared_comment ) { * @phpstan-return list */ public function sanitize_comment_statuses( $statuses ): array { - $statuses = array_unique( array_map( 'sanitize_key', wp_parse_list( $statuses ) ) ); + if ( ! is_array( $statuses ) ) { + $statuses = wp_parse_list( $statuses ); + } - // Only drop empty values. A literal '0' is a queryable status, as comments are held with `comment_approved` of '0'. - $statuses = array_filter( - $statuses, - static function ( $status ) { - return '' !== $status; + $sanitized = array(); + $seen = array(); + foreach ( $statuses as $status ) { + if ( ! is_scalar( $status ) ) { + continue; } - ); - return array_values( $statuses ); + $key = sanitize_key( $status ); + + // Only skip empty values. A literal '0' is a queryable status, as comments are held with `comment_approved` of '0'. + if ( '' === $key || isset( $seen[ $key ] ) ) { + continue; + } + + $seen[ $key ] = true; + $sanitized[] = $key; + } + + return $sanitized; } /** diff --git a/tests/phpunit/tests/rest-api/rest-comments-controller.php b/tests/phpunit/tests/rest-api/rest-comments-controller.php index a21defdc2338c..626160a44a1b0 100644 --- a/tests/phpunit/tests/rest-api/rest-comments-controller.php +++ b/tests/phpunit/tests/rest-api/rest-comments-controller.php @@ -358,15 +358,18 @@ public function test_sanitize_comment_statuses( $statuses, array $expected ) { */ public function data_sanitize_comment_statuses(): array { return array( - 'a single status' => array( 'approve', array( 'approve' ) ), - 'a comma-separated list' => array( 'approve,hold', array( 'approve', 'hold' ) ), - 'an array of statuses' => array( array( 'approve', 'hold' ), array( 'approve', 'hold' ) ), - 'mixed case statuses' => array( 'APPROVE,Hold', array( 'approve', 'hold' ) ), - 'duplicate statuses' => array( array( 'approve', 'approve', 'hold' ), array( 'approve', 'hold' ) ), - 'invalid characters' => array( 'howdy admin', array( 'howdynbspadmin' ) ), - 'an empty string' => array( '', array() ), - 'a literal 0 status' => array( '0', array( '0' ) ), - '0 mixed with a status' => array( '0,approve', array( '0', 'approve' ) ), + 'a single status' => array( 'approve', array( 'approve' ) ), + 'a comma-separated list' => array( 'approve,hold', array( 'approve', 'hold' ) ), + 'an array of statuses' => array( array( 'approve', 'hold' ), array( 'approve', 'hold' ) ), + 'mixed case statuses' => array( 'APPROVE,Hold', array( 'approve', 'hold' ) ), + 'duplicate statuses' => array( array( 'approve', 'approve', 'hold' ), array( 'approve', 'hold' ) ), + 'invalid characters' => array( 'howdy admin', array( 'howdynbspadmin' ) ), + 'an empty string' => array( '', array() ), + 'a literal 0 status' => array( '0', array( '0' ) ), + '0 mixed with a status' => array( '0,approve', array( '0', 'approve' ) ), + 'duplicates after sanitizing' => array( array( 'Approve', 'approve', 'APPROVE' ), array( 'approve' ) ), + 'empty values in an array' => array( array( '', 'approve', '&', 'hold' ), array( 'approve', 'hold' ) ), + 'non-scalar values' => array( array( array( 'approve' ), 'hold', null ), array( 'hold' ) ), ); }