Make WordPress Core

Changeset 60991


Ignore:
Timestamp:
10/20/2025 08:29:54 PM (5 weeks ago)
Author:
joedolson
Message:

Menus: Improve usability and accessibility of menu quick search.

Change the admin menu quick search to limit to searching post titles. Add filter wp_ajax_menu_quick_search_args to support customizing post columns in query. Clear quick search results when search query is cleared. Send announcements about search status via wp.a11y.speak().

Props diebombe, afercia, audrasjb, nickjbedford, kevinlearynet, mukesh27, joedolson.
Fixes #48655.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/js/_enqueues/lib/nav-menu.js

    r60815 r60991  
    14071407        updateQuickSearchResults : function(input) {
    14081408            var panel, params,
    1409                 minSearchLength = 2,
    1410                 q = input.val();
     1409                minSearchLength = 1,
     1410                q = input.val(),
     1411                pageSearchChecklist = $( '#page-search-checklist' );
    14111412
    14121413            /*
    1413              * Minimum characters for a search. Also avoid a new Ajax search when
    1414              * the pressed key (e.g. arrows) doesn't change the searched term.
     1414             * Avoid a new Ajax search when the pressed key (e.g. arrows)
     1415             * doesn't change the searched term.
    14151416             */
    1416             if ( q.length < minSearchLength || api.lastSearch == q ) {
     1417            if ( api.lastSearch == q ) {
     1418                return;
     1419            }
     1420
     1421            /*
     1422             * Reset results when search is less than or equal to
     1423             * minimum characters for searched term.
     1424             */
     1425            if ( q.length <= minSearchLength ) {
     1426                pageSearchChecklist.empty();
     1427                wp.a11y.speak( wp.i18n.__( 'Search results cleared' ) );
    14171428                return;
    14181429            }
     
    17711782
    17721783            if( ! $items.length ) {
     1784                let noResults = wp.i18n.__( 'No results found.' );
    17731785                const li = $( '<li>' );
    1774                 const p = $( '<p>', { text: wp.i18n.__( 'No results found.' ) } );
     1786                const p = $( '<p>', { text: noResults } );
    17751787                li.append( p );
    17761788                $('.categorychecklist', panel).empty().append( li );
    17771789                $( '.spinner', panel ).removeClass( 'is-active' );
    17781790                wrapper.addClass( 'has-no-menu-item' );
     1791                wp.a11y.speak( noResults, 'assertive' );
    17791792                return;
    17801793            }
     
    18031816
    18041817            $('.categorychecklist', panel).html( $items );
     1818            wp.a11y.speak( wp.i18n.sprintf( wp.i18n.__( '%d Search Results Found' ), $items.length ), 'assertive' );
    18051819            $( '.spinner', panel ).removeClass( 'is-active' );
    18061820            wrapper.removeClass( 'has-no-menu-item' );
  • trunk/src/wp-admin/includes/nav-menu.php

    r60980 r60991  
    8484        if ( 'posttype' === $matches[1] && get_post_type_object( $matches[2] ) ) {
    8585            $post_type_obj = _wp_nav_menu_meta_box_object( get_post_type_object( $matches[2] ) );
    86             $args          = array_merge(
    87                 $args,
    88                 array(
    89                     'no_found_rows'          => true,
    90                     'update_post_meta_cache' => false,
    91                     'update_post_term_cache' => false,
    92                     'posts_per_page'         => 10,
    93                     'post_type'              => $matches[2],
    94                     's'                      => $query,
    95                 )
     86            $query_args    = array(
     87                'no_found_rows'          => true,
     88                'update_post_meta_cache' => false,
     89                'update_post_term_cache' => false,
     90                'posts_per_page'         => 10,
     91                'post_type'              => $matches[2],
     92                's'                      => $query,
     93                'search_columns'         => array( 'post_title' ),
    9694            );
     95            /**
     96             * Filter the menu quick search arguments.
     97             *
     98             * @since 6.9.0
     99             *
     100             * @param array $args {
     101             *     Menu quick search arguments.
     102             *
     103             *     @type boolean      $no_found_rows          Whether to return found rows data. Default true.
     104             *     @type boolean      $update_post_meta_cache Whether to update post meta cache. Default false.
     105             *     @type boolean      $update_post_term_cache Whether to update post term cache. Default false.
     106             *     @type int          $posts_per_page         Number of posts to return. Default 10.
     107             *     @type string       $post_type              Type of post to return.
     108             *     @type string       $s                      Search query.
     109             *     @type array        $search_columns         Which post table columns to query.
     110             * }
     111            */
     112            $query_args = apply_filters( 'wp_ajax_menu_quick_search_args', $query_args );
     113            $args       = array_merge( $args, $query_args );
    97114
    98115            if ( isset( $post_type_obj->_default_query ) ) {
  • trunk/tests/phpunit/tests/menu/wpAjaxMenuQuickSearch.php

    r60775 r60991  
    1919                'post_type'    => 'page',
    2020                'post_content' => 'foo',
     21                'post_title'   => 'foo title',
    2122            )
    2223        );
     
    2526                'post_type'    => 'page',
    2627                'post_content' => 'bar',
     28                'post_title'   => 'bar title',
    2729            )
    2830        );
     
    4244
    4345    /**
     46     * Test that search only returns results for posts with term in title.
     47     *
     48     * @ticket 48655
     49     */
     50    public function test_search_only_returns_results_for_posts_with_term_in_title() {
     51        require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
     52
     53        // This will make sure that WP_Query sets is_admin to true.
     54        set_current_screen( 'nav-menu.php' );
     55
     56        self::factory()->post->create(
     57            array(
     58                'post_type'    => 'post',
     59                'post_status'  => 'publish',
     60                'post_title'   => 'Publish FOO',
     61                'post_content' => 'FOO',
     62            )
     63        );
     64        self::factory()->post->create(
     65            array(
     66                'post_type'    => 'post',
     67                'post_status'  => 'publish',
     68                'post_title'   => 'Publish without search term',
     69                'post_content' => 'FOO',
     70            )
     71        );
     72
     73        $request = array(
     74            'type' => 'quick-search-posttype-post',
     75            'q'    => 'FOO',
     76        );
     77        $output  = get_echo( '_wp_ajax_menu_quick_search', array( $request ) );
     78
     79        $this->assertNotEmpty( $output );
     80        $results = explode( "\n", trim( $output ) );
     81        $this->assertCount( 1, $results );
     82    }
     83
     84    /**
    4485     * Test that search only returns results for published posts.
    4586     *
     
    5697                'post_type'    => 'post',
    5798                'post_status'  => 'publish',
    58                 'post_title'   => 'Publish',
     99                'post_title'   => 'Publish FOO',
    59100                'post_content' => 'FOO',
    60101            )
     
    64105                'post_type'    => 'post',
    65106                'post_status'  => 'draft',
    66                 'post_title'   => 'Draft',
     107                'post_title'   => 'Draft FOO',
    67108                'post_content' => 'FOO',
    68109            )
     
    72113                'post_type'    => 'post',
    73114                'post_status'  => 'pending',
    74                 'post_title'   => 'Pending',
     115                'post_title'   => 'Pending FOO',
    75116                'post_content' => 'FOO',
    76117            )
     
    80121                'post_type'    => 'post',
    81122                'post_status'  => 'future',
    82                 'post_title'   => 'Future',
     123                'post_title'   => 'Future FOO',
    83124                'post_content' => 'FOO',
    84125                'post_date'    => gmdate( 'Y-m-d H:i:s', strtotime( '+1 month' ) ),
     
    133174        self::factory()->post->create(
    134175            array(
    135                 'post_title'   => 'Post Title 123',
     176                'post_title'   => 'Post Title 123 FOO',
    136177                'post_type'    => 'wptests_123',
    137178                'post_status'  => 'publish',
Note: See TracChangeset for help on using the changeset viewer.