diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php
index e39739883e..b154ff0320 100644
--- a/src/wp-admin/includes/ajax-actions.php
+++ b/src/wp-admin/includes/ajax-actions.php
@@ -2994,7 +2994,7 @@ function wp_ajax_query_attachments() {
 
 	// Filter query clauses to include filenames.
 	if ( isset( $query['s'] ) ) {
-		add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
+		add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
 	}
 
 	/**
diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php
index f3300fcf1e..bc034869af 100644
--- a/src/wp-admin/includes/post.php
+++ b/src/wp-admin/includes/post.php
@@ -1302,7 +1302,7 @@ function wp_edit_attachments_query_vars( $q = false ) {
 
 	// Filter query clauses to include filenames.
 	if ( isset( $q['s'] ) ) {
-		add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
+		add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
 	}
 
 	return $q;
diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php
index e7eda7bab7..edf6799cb6 100644
--- a/src/wp-includes/class-wp-query.php
+++ b/src/wp-includes/class-wp-query.php
@@ -444,6 +444,14 @@ class WP_Query {
 	 */
 	public $thumbnails_cached = false;
 
+	/**
+	 * Controls whether an attachment query should include filenames or not.
+	 *
+	 * @since 6.0.3
+	 * @var bool
+	 */
+	protected $allow_query_attachment_by_filename = false;
+
 	/**
 	 * Cached list of search stopwords.
 	 *
@@ -1414,8 +1422,13 @@ class WP_Query {
 				$q['search_orderby_title'][] = $wpdb->prepare( "{$wpdb->posts}.post_title LIKE %s", $like );
 			}
 
-			$like      = $n . $wpdb->esc_like( $term ) . $n;
-			$search   .= $wpdb->prepare( "{$searchand}(({$wpdb->posts}.post_title $like_op %s) $andor_op ({$wpdb->posts}.post_excerpt $like_op %s) $andor_op ({$wpdb->posts}.post_content $like_op %s))", $like, $like, $like );
+			$like = $n . $wpdb->esc_like( $term ) . $n;
+
+			if ( ! empty( $this->allow_query_attachment_by_filename ) ) {
+				$search .= $wpdb->prepare( "{$searchand}(({$wpdb->posts}.post_title $like_op %s) $andor_op ({$wpdb->posts}.post_excerpt $like_op %s) $andor_op ({$wpdb->posts}.post_content $like_op %s) $andor_op (sq1.meta_value $like_op %s))", $like, $like, $like, $like );
+			} else {
+				$search .= $wpdb->prepare( "{$searchand}(({$wpdb->posts}.post_title $like_op %s) $andor_op ({$wpdb->posts}.post_excerpt $like_op %s) $andor_op ({$wpdb->posts}.post_content $like_op %s))", $like, $like, $like );
+			}
 			$searchand = ' AND ';
 		}
 
@@ -1810,6 +1823,16 @@ class WP_Query {
 		// Fill again in case 'pre_get_posts' unset some vars.
 		$q = $this->fill_query_vars( $q );
 
+		/**
+		 * Filters whether an attachment query should include filenames or not.
+		 *
+		 * @since 6.0.3
+		 *
+		 * @param bool $allow_query_attachment_by_filename Whether or not to include filenames.
+		 */
+		$this->allow_query_attachment_by_filename = apply_filters( 'wp_allow_query_attachment_by_filename', false );
+		remove_all_filters( 'wp_allow_query_attachment_by_filename' );
+
 		// Parse meta query.
 		$this->meta_query = new WP_Meta_Query();
 		$this->meta_query->parse_query_vars( $q );
@@ -2241,7 +2264,7 @@ class WP_Query {
 			}
 		}
 
-		if ( ! empty( $this->tax_query->queries ) || ! empty( $this->meta_query->queries ) ) {
+		if ( ! empty( $this->tax_query->queries ) || ! empty( $this->meta_query->queries ) || ! empty( $this->allow_query_attachment_by_filename ) ) {
 			$groupby = "{$wpdb->posts}.ID";
 		}
 
@@ -2318,6 +2341,10 @@ class WP_Query {
 		}
 		$where .= $search . $whichauthor . $whichmimetype;
 
+		if ( ! empty( $this->allow_query_attachment_by_filename ) ) {
+			$join .= " LEFT JOIN {$wpdb->postmeta} AS sq1 ON ( {$wpdb->posts}.ID = sq1.post_id AND sq1.meta_key = '_wp_attached_file' )";
+		}
+
 		if ( ! empty( $this->meta_query->queries ) ) {
 			$clauses = $this->meta_query->get_sql( 'post', $wpdb->posts, 'ID', $this );
 			$join   .= $clauses['join'];
diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php
index ec4c4678f5..013694391c 100644
--- a/src/wp-includes/deprecated.php
+++ b/src/wp-includes/deprecated.php
@@ -4311,3 +4311,20 @@ function wp_skip_spacing_serialization( $block_type ) {
 function wp_add_iframed_editor_assets_html() {
 	_deprecated_function( __FUNCTION__, '6.0.0' );
 }
+
+/**
+ * Filter the SQL clauses of an attachment query to include filenames.
+ *
+ * @since 4.7.0
+ * @deprecated 6.0.3
+ * @access private
+ *
+ * @param array $clauses An array including WHERE, GROUP BY, JOIN, ORDER BY,
+ *                       DISTINCT, fields (SELECT), and LIMITS clauses.
+ * @return array The unmodified clauses.
+ */
+function _filter_query_attachment_filenames( $clauses ) {
+	_deprecated_function( __FUNCTION__, '4.9.9', 'add_filter( "wp_allow_query_attachment_by_filename", "__return_true" )' );
+	remove_filter( 'posts_clauses', __FUNCTION__ );
+	return $clauses;
+}
\ No newline at end of file
diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php
index 288704c66d..e7abb6feda 100644
--- a/src/wp-includes/post.php
+++ b/src/wp-includes/post.php
@@ -7918,36 +7918,6 @@ function wp_add_trashed_suffix_to_post_name_for_post( $post ) {
 	return $post_name;
 }
 
-/**
- * Filters the SQL clauses of an attachment query to include filenames.
- *
- * @since 4.7.0
- * @access private
- *
- * @global wpdb $wpdb WordPress database abstraction object.
- *
- * @param string[] $clauses An array including WHERE, GROUP BY, JOIN, ORDER BY,
- *                          DISTINCT, fields (SELECT), and LIMITS clauses.
- * @return string[] The modified array of clauses.
- */
-function _filter_query_attachment_filenames( $clauses ) {
-	global $wpdb;
-	remove_filter( 'posts_clauses', __FUNCTION__ );
-
-	// Add a LEFT JOIN of the postmeta table so we don't trample existing JOINs.
-	$clauses['join'] .= " LEFT JOIN {$wpdb->postmeta} AS sq1 ON ( {$wpdb->posts}.ID = sq1.post_id AND sq1.meta_key = '_wp_attached_file' )";
-
-	$clauses['groupby'] = "{$wpdb->posts}.ID";
-
-	$clauses['where'] = preg_replace(
-		"/\({$wpdb->posts}.post_content (NOT LIKE|LIKE) (\'[^']+\')\)/",
-		'$0 OR ( sq1.meta_value $1 $2 )',
-		$clauses['where']
-	);
-
-	return $clauses;
-}
-
 /**
  * Sets the last changed time for the 'posts' cache group.
  *
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
index 423347a721..ff3c1dc42f 100644
--- a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
@@ -97,7 +97,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
 
 		// Filter query clauses to include filenames.
 		if ( isset( $query_args['s'] ) ) {
-			add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
+			add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
 		}
 
 		return $query_args;
diff --git a/tests/phpunit/tests/query/search.php b/tests/phpunit/tests/query/search.php
index 418acbfc85..5a7eab28c0 100644
--- a/tests/phpunit/tests/query/search.php
+++ b/tests/phpunit/tests/query/search.php
@@ -454,7 +454,7 @@ class Tests_Query_Search extends WP_UnitTestCase {
 		);
 
 		add_post_meta( $attachment, '_wp_attached_file', 'some-image1.png', true );
-		add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
+		add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
 
 		// Pass post_type a string value.
 		$q = new WP_Query(
@@ -484,7 +484,7 @@ class Tests_Query_Search extends WP_UnitTestCase {
 		);
 
 		add_post_meta( $attachment, '_wp_attached_file', 'some-image2.png', true );
-		add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
+		add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
 
 		// Pass post_type an array value.
 		$q = new WP_Query(
@@ -543,7 +543,7 @@ class Tests_Query_Search extends WP_UnitTestCase {
 
 		add_post_meta( $attachment, '_wp_attached_file', 'some-image4.png', true );
 		add_post_meta( $attachment, '_test_meta_key', 'value', true );
-		add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
+		add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
 
 		// Pass post_type a string value.
 		$q = new WP_Query(
@@ -583,7 +583,7 @@ class Tests_Query_Search extends WP_UnitTestCase {
 		wp_set_post_terms( $attachment, 'test', 'post_tag' );
 
 		add_post_meta( $attachment, '_wp_attached_file', 'some-image5.png', true );
-		add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
+		add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
 
 		// Pass post_type a string value.
 		$q = new WP_Query(
@@ -608,25 +608,37 @@ class Tests_Query_Search extends WP_UnitTestCase {
 	/**
 	 * @ticket 22744
 	 */
-	public function test_filter_query_attachment_filenames_unhooks_itself() {
-		add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
-
-		apply_filters(
-			'posts_clauses',
+	public function test_wp_query_removes_filter_wp_allow_query_attachment_by_filename() {
+		$attachment = self::factory()->post->create(
 			array(
-				'where'    => '',
-				'groupby'  => '',
-				'join'     => '',
-				'orderby'  => '',
-				'distinct' => '',
-				'fields'   => '',
-				'limit'    => '',
+				'post_type'    => 'attachment',
+				'post_status'  => 'publish',
+				'post_title'   => 'bar foo',
+				'post_content' => 'foo bar',
+				'post_excerpt' => 'This post has foo',
 			)
 		);
 
-		$result = has_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
+		add_post_meta( $attachment, '_wp_attached_file', 'some-image1.png', true );
+		add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
 
-		$this->assertFalse( $result );
+		$q = new WP_Query(
+			array(
+				's'           => 'image1',
+				'fields'      => 'ids',
+				'post_type'   => 'attachment',
+				'post_status' => 'inherit',
+			)
+		);
+
+		$this->assertSame( array( $attachment ), $q->posts );
+
+		/*
+		 * WP_Query should have removed the wp_allow_query_attachment_by_filename filter
+		 * and thus not match the attachment created above.
+		 */
+		$q->get_posts();
+		$this->assertEmpty( $q->posts );
 	}
 
 	public function filter_posts_search( $sql ) {