WordPress.org

Make WordPress Core

Changeset 51006


Ignore:
Timestamp:
05/25/2021 05:41:11 PM (6 months ago)
Author:
joedolson
Message:

Menus: Add bulk delete for menu items.

Adds an option to bulk delete menu items from the core Navigation Menus screen, offering a considerable usability benefit when making significant changes to navigation menus.

Uses the bulk select pattern found in post and media lists for consistency with other core management screens, rather than the rapid delete pattern found in menus in the customizer.

Props wphound, welcher, melchoyce, maxpertici, audrasjb
Fixes #21603.

Location:
trunk/src
Files:
4 edited

Legend:

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

    r50547 r51006  
    4545
    4646            this.attachMenuEditListeners();
     47
     48            this.attachBulkSelectButtonListeners();
     49            this.attachMenuCheckBoxListeners();
     50            this.attachMenuItemDeleteButton();
     51            this.attachPendingMenuItemsListForDeletion();
    4752
    4853            this.attachQuickSearchListeners();
     
    863868        },
    864869
     870        /**
     871         * Handle toggling bulk selection checkboxes for menu items.
     872         *
     873         * @since 5.8.0
     874         */
     875        attachBulkSelectButtonListeners : function() {
     876            var that = this;
     877
     878            $('.bulk-select-switcher').on( 'change', function(){
     879                if( this.checked ){
     880                    $('.bulk-select-switcher').prop('checked',true);
     881                    that.enableBulkSelection();
     882                }else{
     883                    $('.bulk-select-switcher').prop('checked',false);
     884                    that.disableBulkSelection();
     885                }
     886            });
     887        },
     888
     889        /**
     890         * Enable bulk selection checkboxes for menu items.
     891         *
     892         * @since 5.8.0
     893         */
     894        enableBulkSelection : function() {
     895            $('#menu-to-edit').addClass('bulk-selection');
     896            $('#nav-menu-bulk-actions-top').addClass('bulk-selection');
     897            $('#nav-menu-bulk-actions-bottom').addClass('bulk-selection');
     898
     899            var checkbox = $('#menu-to-edit .menu-item-checkbox');
     900            $.each( checkbox, function(){
     901                $(this).prop('disabled',false);
     902            });
     903        },
     904
     905        /**
     906         * Disable bulk selection checkboxes for menu items.
     907         *
     908         * @since 5.8.0
     909         */
     910        disableBulkSelection : function() {
     911            $('#menu-to-edit').removeClass('bulk-selection');
     912            $('#nav-menu-bulk-actions-top').removeClass('bulk-selection');
     913            $('#nav-menu-bulk-actions-bottom').removeClass('bulk-selection');
     914
     915            if ( $('.menu-items-delete').is('[aria-describedby="pending-menu-items-to-delete"]') ) {
     916                $('.menu-items-delete').removeAttr( 'aria-describedby' );
     917            }
     918
     919            var checkbox = $('#menu-to-edit .menu-item-checkbox');
     920            $.each( checkbox, function(){
     921                $(this).prop('disabled',true).prop('checked',false);
     922            });
     923            $('.menu-items-delete').addClass('disabled');
     924            $('#pending-menu-items-to-delete ul').empty();
     925        },
     926
     927        /**
     928         * Listen for state changes on bulk action checkboxes.
     929         *
     930         * @since 5.8.0
     931         */
     932        attachMenuCheckBoxListeners : function() {
     933            var that = this;
     934
     935            $( '#menu-to-edit' ).on( 'change', '.menu-item-checkbox', function(){
     936                that.setRemoveSelectedButtonStatus();
     937            });
     938        },
     939
     940        /**
     941         * Create delete button to remove menu items from collection.
     942         *
     943         * @since 5.8.0
     944         */
     945        attachMenuItemDeleteButton : function() {
     946            var that = this;
     947
     948            $( document ).on('click', '.menu-items-delete', function(e){
     949                e.preventDefault();
     950
     951                if( ! $(this).hasClass('disabled') ){
     952                    $.each( $('.menu-item-checkbox:checked'), function( index, element ) {
     953                        $( element ).parents( 'li' ).find( 'a.item-delete' ).trigger( 'click' );
     954                    });
     955
     956                    $('.menu-items-delete').addClass('disabled');
     957                    $('.bulk-select-switcher').prop('checked',false);
     958
     959                    var itemsPendingDeletion = '';
     960                    var itemsPendingDeletionList = $('#pending-menu-items-to-delete ul li');
     961
     962                    $.each( itemsPendingDeletionList, function( index, element ) {
     963                        var itemName = $( element ).find( '.pending-menu-item-name' ).text();
     964                        var itemSpeech = menus.menuItemDeletion.replace( '%s', itemName );
     965                        itemsPendingDeletion += itemSpeech ;
     966                        if( ( index + 1 ) < itemsPendingDeletionList.length ){
     967                            itemsPendingDeletion += ', ' ;
     968                        }
     969                    });
     970
     971                    var deletionSpeech = menus.itemsDeleted.replace( '%s', itemsPendingDeletion );
     972                    wp.a11y.speak( deletionSpeech, 'polite' );
     973                    that.disableBulkSelection();
     974                }
     975            });
     976        },
     977
     978        /**
     979         * List menu items awaiting deletion.
     980         *
     981         * @since 5.8.0
     982         */
     983        attachPendingMenuItemsListForDeletion : function(){
     984            $('#post-body-content').on( 'change', '.menu-item-checkbox', function(){
     985
     986                if( ! $('.menu-items-delete').is('[aria-describedby="pending-menu-items-to-delete"]') ){ $('.menu-items-delete').attr( 'aria-describedby', 'pending-menu-items-to-delete' ); }
     987
     988                var menuItemName = $(this).next().text();
     989                var menuItemType = $(this).parent().next('.item-controls').find('.item-type').text();
     990                var menuItemID = $(this).attr('data-menu-item-id') ;
     991
     992                var ListedMenuItem = $('#pending-menu-items-to-delete ul').find('[data-menu-item-id=' + menuItemID + ']') ;
     993                if( ListedMenuItem.length > 0 ){
     994                    ListedMenuItem.remove();
     995                }
     996                if( this.checked === true ){
     997                    $('#pending-menu-items-to-delete ul').append( '<li data-menu-item-id="' + menuItemID + '"><span class="pending-menu-item-name">' + menuItemName + '</span> <span class="pending-menu-item-type">(' + menuItemType + ')</span><span class="separator"></span></li>' );
     998                }
     999
     1000                $('#pending-menu-items-to-delete li .separator').html(', ');
     1001                $('#pending-menu-items-to-delete li .separator').last().html('.');
     1002            });
     1003        },
     1004
     1005        /**
     1006         * Set status of bulk delete checkbox.
     1007         *
     1008         * @since 5.8.0
     1009         */
     1010        setBulkDeleteCheckboxStatus : function(){
     1011
     1012            var that = this;
     1013            var checkbox = $('#menu-to-edit .menu-item-checkbox');
     1014
     1015            $.each( checkbox, function(){
     1016
     1017                if( $(this).prop('disabled') == true ){
     1018                    $(this).prop( 'disabled', false );
     1019                }else{
     1020                    $(this).prop( 'disabled', true );
     1021                }
     1022
     1023                if( $(this).is(':checked')) {
     1024                    $(this).prop('checked',false);
     1025                }
     1026            });
     1027
     1028            that.setRemoveSelectedButtonStatus();
     1029        },
     1030
     1031        /**
     1032         * Set status of menu items removal button.
     1033         *
     1034         * @since 5.8.0
     1035         */
     1036        setRemoveSelectedButtonStatus : function(){
     1037
     1038            var button = $('.menu-items-delete');
     1039
     1040            if( $('.menu-item-checkbox:checked').length > 0 ) {
     1041                button.removeClass('disabled');
     1042            } else {
     1043                button.addClass('disabled');
     1044            }
     1045        },
     1046
    8651047        attachMenuSaveSubmitListeners : function() {
    8661048            /*
     
    9091091                searchTimer = setTimeout( function() {
    9101092                    api.updateQuickSearchResults( $this );
    911                 }, 500 );
     1093                }, 500 );
    9121094            }).on( 'blur', '.quick-search', function() {
    9131095                api.lastSearch = '';
  • trunk/src/wp-admin/css/nav-menus.css

    r50782 r51006  
    9696.menu-edit #post-body-content h3 {
    9797    margin: 1em 0 10px;
     98}
     99
     100#nav-menu-bulk-actions-top {
     101    margin: 1em 0;
     102}
     103
     104#nav-menu-bulk-actions-bottom {
     105    margin: 1em 0;
     106    margin: calc( 1em + 9px ) 0 ;
     107}
     108
     109.bulk-actions input.button {
     110    margin-right: 12px;
     111}
     112
     113.bulk-select-button {
     114    position: relative;
     115    display: inline-block;
     116    padding: 0 10px;
     117    font-size: 13px;
     118    line-height: 2.15384615;
     119    height: auto;
     120    min-height: 30px;
     121    background: #f6f7f7;
     122    vertical-align: top;
     123    border: 1px solid #dcdcde;
     124    margin: 0;
     125    cursor: pointer;
     126    border-radius: 3px;
     127    white-space: nowrap;
     128    box-sizing: border-box;
     129}
     130
     131.bulk-selection .bulk-select-button {
     132    color: #2271b1;
     133    border-color: #2271b1;
     134    background: #f6f7f7;
     135    vertical-align: top;
     136}
     137
     138#pending-menu-items-to-delete {
     139    display: none;
     140}
     141
     142.bulk-selection #pending-menu-items-to-delete {
     143    display: block;
     144    margin-top: 1em;
     145}
     146
     147#pending-menu-items-to-delete p {
     148    margin-bottom: 0;
     149}
     150
     151#pending-menu-items-to-delete ul {
     152    margin-top: 0;
     153    list-style: none;
     154}
     155
     156#pending-menu-items-to-delete ul li {
     157    display: inline;
     158}
     159
     160input.bulk-select-switcher + .bulk-select-button-label {
     161    vertical-align: inherit;
     162}
     163
     164label.bulk-select-button:hover,
     165label.bulk-select-button:active,
     166label.bulk-select-button:focus-within {
     167    background: #f0f0f1;
     168    border-color: #0a4b78;
     169    color: #0a4b78;
     170}
     171
     172input.bulk-select-switcher:focus + .bulk-select-button-label{
     173    color: #0a4b78;
     174}
     175
     176.bulk-actions input.menu-items-delete {
     177    -webkit-appearance: none;
     178    appearance: none;
     179    font-size: inherit;
     180    border: 0;
     181    line-height: 2.1em;
     182    background: none;
     183    cursor: pointer;
     184    text-decoration: underline;
     185    color: #b32d2e;
     186}
     187
     188.bulk-actions input.menu-items-delete:hover {
     189    color: #b32d2e;
     190    border: none;
     191}
     192
     193.bulk-actions input.menu-items-delete.disabled {
     194    cursor: default;
     195    color: #a7aaad;
     196    box-shadow: none;
    98197}
    99198
     
    480579    /* @todo: responsive view. */
    481580    margin-right: 13em;
     581}
     582
     583.menu-item-handle .menu-item-checkbox {
     584    display: none;
     585}
     586
     587.bulk-selection .menu-item-handle .menu-item-checkbox {
     588    display: inline-block;
     589    margin-right: 6px;
    482590}
    483591
  • trunk/src/wp-admin/includes/class-walker-nav-menu-edit.php

    r50767 r51006  
    119119            <div class="menu-item-bar">
    120120                <div class="menu-item-handle">
    121                     <span class="item-title"><span class="menu-item-title"><?php echo esc_html( $title ); ?></span> <span class="is-submenu" <?php echo $submenu_text; ?>><?php _e( 'sub item' ); ?></span></span>
     121                    <label class="item-title" for="menu-item-checkbox-<?php echo $item_id; ?>"><input id="menu-item-checkbox-<?php echo $item_id; ?>" type="checkbox" class="menu-item-checkbox" data-menu-item-id="<?php echo $item_id; ?>" disabled="disabled"/><span class="menu-item-title"><?php echo esc_html( $title ); ?></span> <span class="is-submenu" <?php echo $submenu_text; ?>><?php _e( 'sub item' ); ?></span></label>
    122122                    <span class="item-controls">
    123123                        <span class="item-type"><?php echo esc_html( $item->type_label ); ?></span>
  • trunk/src/wp-admin/nav-menus.php

    r50938 r51006  
    486486    /* translators: 1: Item name, 2: Item position, 3: Parent item name. */
    487487    'subMenuFocus'            => __( '%1$s. Sub item number %2$d under %3$s.' ),
     488    /* translators: %s: Item name. */
     489    'menuItemDeletion'        => __( 'item %s' ),
     490    /* translators: %s: Item name. */
     491    'itemsDeleted'            => __( 'Deleted menu item: %s.' ),
    488492);
    489493wp_localize_script( 'nav-menu', 'menus', $nav_menus_l10n );
     
    962966                        <div id="post-body-content" class="wp-clearfix">
    963967                            <?php if ( ! $add_new_screen ) : ?>
    964 
    965968                                <?php
    966969                                $hide_style = '';
     
    979982                                    <p><?php echo $starter_copy; ?></p>
    980983                                </div>
    981 
     984                                <div id="nav-menu-bulk-actions-top" class="bulk-actions">
     985                                    <label class="bulk-select-button" for="bulk-select-switcher-top">
     986                                        <input type="checkbox" id="bulk-select-switcher-top" name="bulk-select-switcher-top" class="bulk-select-switcher">
     987                                        <span class="bulk-select-button-label"><?php echo __( 'Bulk Select' ) ; ?></span>
     988                                    </label>
     989                                </div>
    982990                                <?php
    983991                                if ( isset( $edit_markup ) && ! is_wp_error( $edit_markup ) ) {
     
    10051013                            }
    10061014                            ?>
     1015                            <div id="nav-menu-bulk-actions-bottom" class="bulk-actions">
     1016                                <label class="bulk-select-button" for="bulk-select-switcher-bottom">
     1017                                    <input type="checkbox" id="bulk-select-switcher-bottom" name="bulk-select-switcher-top" class="bulk-select-switcher">
     1018                                    <span class="bulk-select-button-label"><?php echo __( 'Bulk Select' ); ?></span>
     1019                                </label>
     1020                                <input type="button" class="deletion menu-items-delete disabled" value="<?php _e( 'Remove Selected Items' ) ; ?>">
     1021                                <div id="pending-menu-items-to-delete">
     1022                                    <p><?php _e( 'List of menu items selected for deletion:' ) ; ?></p>
     1023                                    <ul></ul>
     1024                                </div>
     1025                            </div>
    10071026                            <div class="menu-settings" <?php echo $no_menus_style; ?>>
    10081027                                <h3><?php _e( 'Menu Settings' ); ?></h3>
Note: See TracChangeset for help on using the changeset viewer.