diff --git a/src/js/_enqueues/lib/nav-menu.js b/src/js/_enqueues/lib/nav-menu.js index 666780a9e399b..79917c8447f1a 100644 --- a/src/js/_enqueues/lib/nav-menu.js +++ b/src/js/_enqueues/lib/nav-menu.js @@ -1406,14 +1406,25 @@ updateQuickSearchResults : function(input) { var panel, params, - minSearchLength = 2, - q = input.val(); + minSearchLength = 1, + q = input.val(), + pageSearchChecklist = $( '#page-search-checklist' ); /* - * Minimum characters for a search. Also avoid a new Ajax search when - * the pressed key (e.g. arrows) doesn't change the searched term. + * Avoid a new Ajax search when the pressed key (e.g. arrows) + * doesn't change the searched term. */ - if ( q.length < minSearchLength || api.lastSearch == q ) { + if ( api.lastSearch == q ) { + return; + } + + /* + * Reset results when search is less than or equal to + * minimum characters for searched term. + */ + if ( q.length <= minSearchLength ) { + pageSearchChecklist.empty(); + wp.a11y.speak( wp.i18n.__( 'Search results cleared' ) ); return; } @@ -1770,12 +1781,14 @@ $item; if( ! $items.length ) { + let noResults = wp.i18n.__( 'No results found.' ); const li = $( '
', { text: wp.i18n.__( 'No results found.' ) } ); + const p = $( '
', { text: noResults } ); li.append( p ); $('.categorychecklist', panel).empty().append( li ); $( '.spinner', panel ).removeClass( 'is-active' ); wrapper.addClass( 'has-no-menu-item' ); + wp.a11y.speak( noResults, 'assertive' ); return; } @@ -1802,6 +1815,7 @@ }); $('.categorychecklist', panel).html( $items ); + wp.a11y.speak( wp.i18n.sprintf( wp.i18n.__( '%d Search Results Found' ), $items.length ), 'assertive' ); $( '.spinner', panel ).removeClass( 'is-active' ); wrapper.removeClass( 'has-no-menu-item' ); diff --git a/src/wp-admin/includes/nav-menu.php b/src/wp-admin/includes/nav-menu.php index d63f10100752b..15d39dc6a9cd2 100644 --- a/src/wp-admin/includes/nav-menu.php +++ b/src/wp-admin/includes/nav-menu.php @@ -83,17 +83,34 @@ function _wp_ajax_menu_quick_search( $request = array() ) { } elseif ( preg_match( '/quick-search-(posttype|taxonomy)-([a-zA-Z0-9_-]*\b)/', $type, $matches ) ) { if ( 'posttype' === $matches[1] && get_post_type_object( $matches[2] ) ) { $post_type_obj = _wp_nav_menu_meta_box_object( get_post_type_object( $matches[2] ) ); - $args = array_merge( - $args, - array( - 'no_found_rows' => true, - 'update_post_meta_cache' => false, - 'update_post_term_cache' => false, - 'posts_per_page' => 10, - 'post_type' => $matches[2], - 's' => $query, - ) + $query_args = array( + 'no_found_rows' => true, + 'update_post_meta_cache' => false, + 'update_post_term_cache' => false, + 'posts_per_page' => 10, + 'post_type' => $matches[2], + 's' => $query, + 'search_columns' => array( 'post_title' ), ); + /** + * Filter the menu quick search arguments. + * + * @since 6.9.0 + * + * @param array $args { + * Menu quick search arguments. + * + * @type boolean $no_found_rows Whether to return found rows data. Default true. + * @type boolean $update_post_meta_cache Whether to update post meta cache. Default false. + * @type boolean $update_post_term_cache Whether to update post term cache. Default false. + * @type int $posts_per_page Number of posts to return. Default 10. + * @type string $post_type Type of post to return. + * @type string $s Search query. + * @type array $search_columns Which post table columns to query. + * } + */ + $query_args = apply_filters( 'wp_ajax_menu_quick_search_args', $query_args ); + $args = array_merge( $args, $query_args ); if ( isset( $post_type_obj->_default_query ) ) { $args = array_merge( $args, (array) $post_type_obj->_default_query ); diff --git a/tests/phpunit/tests/menu/wpAjaxMenuQuickSearch.php b/tests/phpunit/tests/menu/wpAjaxMenuQuickSearch.php index f1ada20719e91..f687fc4b069c9 100644 --- a/tests/phpunit/tests/menu/wpAjaxMenuQuickSearch.php +++ b/tests/phpunit/tests/menu/wpAjaxMenuQuickSearch.php @@ -18,12 +18,14 @@ public function test_search_returns_results_for_pages() { array( 'post_type' => 'page', 'post_content' => 'foo', + 'post_title' => 'foo title', ) ); self::factory()->post->create( array( 'post_type' => 'page', 'post_content' => 'bar', + 'post_title' => 'bar title', ) ); @@ -40,6 +42,45 @@ public function test_search_returns_results_for_pages() { $this->assertCount( 3, $results ); } + /** + * Test that search only returns results for posts with term in title. + * + * @ticket 48655 + */ + public function test_search_only_returns_results_for_posts_with_term_in_title() { + require_once ABSPATH . 'wp-admin/includes/nav-menu.php'; + + // This will make sure that WP_Query sets is_admin to true. + set_current_screen( 'nav-menu.php' ); + + self::factory()->post->create( + array( + 'post_type' => 'post', + 'post_status' => 'publish', + 'post_title' => 'Publish FOO', + 'post_content' => 'FOO', + ) + ); + self::factory()->post->create( + array( + 'post_type' => 'post', + 'post_status' => 'publish', + 'post_title' => 'Publish without search term', + 'post_content' => 'FOO', + ) + ); + + $request = array( + 'type' => 'quick-search-posttype-post', + 'q' => 'FOO', + ); + $output = get_echo( '_wp_ajax_menu_quick_search', array( $request ) ); + + $this->assertNotEmpty( $output ); + $results = explode( "\n", trim( $output ) ); + $this->assertCount( 1, $results ); + } + /** * Test that search only returns results for published posts. * @@ -55,7 +96,7 @@ public function test_search_returns_results_for_published_posts() { array( 'post_type' => 'post', 'post_status' => 'publish', - 'post_title' => 'Publish', + 'post_title' => 'Publish FOO', 'post_content' => 'FOO', ) ); @@ -63,7 +104,7 @@ public function test_search_returns_results_for_published_posts() { array( 'post_type' => 'post', 'post_status' => 'draft', - 'post_title' => 'Draft', + 'post_title' => 'Draft FOO', 'post_content' => 'FOO', ) ); @@ -71,7 +112,7 @@ public function test_search_returns_results_for_published_posts() { array( 'post_type' => 'post', 'post_status' => 'pending', - 'post_title' => 'Pending', + 'post_title' => 'Pending FOO', 'post_content' => 'FOO', ) ); @@ -79,7 +120,7 @@ public function test_search_returns_results_for_published_posts() { array( 'post_type' => 'post', 'post_status' => 'future', - 'post_title' => 'Future', + 'post_title' => 'Future FOO', 'post_content' => 'FOO', 'post_date' => gmdate( 'Y-m-d H:i:s', strtotime( '+1 month' ) ), ) @@ -132,7 +173,7 @@ public function test_search_returns_post_types_with_numeric_slugs() { self::factory()->post->create( array( - 'post_title' => 'Post Title 123', + 'post_title' => 'Post Title 123 FOO', 'post_type' => 'wptests_123', 'post_status' => 'publish', 'post_content' => 'FOO',