diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 2c9502035705c..9d1217df20d36 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1576,6 +1576,24 @@ protected function parse_search_terms( $terms ) { continue; } + /** + * Filters a search term after it has passed the length and stopwords checks. + * + * Can be used to normalize or remove a term. Returning an empty string + * will cause the term to be skipped. This is particularly useful for + * languages such as Arabic that require stripping diacritics, Hamza + * variants, or other decorative characters before meaningful comparison. + * + * @since 6.9.0 + * + * @param string $term The search term. + */ + $term = apply_filters( 'wp_search_term', $term ); + + if ( ! $term ) { + continue; + } + $checked[] = $term; } diff --git a/tests/phpunit/tests/query/search.php b/tests/phpunit/tests/query/search.php index 7bfbdec31c87d..7bb3b0f160d99 100644 --- a/tests/phpunit/tests/query/search.php +++ b/tests/phpunit/tests/query/search.php @@ -644,4 +644,35 @@ public function test_wp_query_removes_filter_wp_allow_query_attachment_by_filena public function filter_posts_search( $sql ) { return $sql . ' /* posts_search */'; } + + /** + * @ticket 25585 + */ + public function test_wp_search_term_filter_empty_string_removes_term() { + $callback = static function ( $term ) { + return 'foo' === $term ? '' : $term; + }; + + add_filter( 'wp_search_term', $callback ); + $query = new WP_Query( array( 's' => 'foo bar' ) ); + remove_filter( 'wp_search_term', $callback ); + + $this->assertSame( array( 'bar' ), $query->get( 'search_terms' ) ); + } + + /** + * @ticket 25585 + */ + public function test_wp_search_term_filter_normalizes_arabic_characters() { + $callback = static function ( $term ) { + $term = str_replace( array( 'أ', 'إ', 'آ' ), 'ا', $term ); + return str_replace( array( 'َ', 'ً', 'ُ', 'ٌ', 'ِ', 'ٍ', 'ْ', 'ّ' ), '', $term ); + }; + + add_filter( 'wp_search_term', $callback ); + $query = new WP_Query( array( 's' => 'أَنْتَ بَيْت' ) ); + remove_filter( 'wp_search_term', $callback ); + + $this->assertSame( array( 'انت', 'بيت' ), $query->get( 'search_terms' ) ); + } }