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.
Built from https://develop.svn.wordpress.org/trunk@51006


git-svn-id: http://core.svn.wordpress.org/trunk@50615 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
joedolson 2021-05-25 17:42:58 +00:00
parent a07a6490ab
commit 212f532d4c
9 changed files with 425 additions and 8 deletions

View File

@ -98,6 +98,105 @@ ul.add-menu-item-tabs li {
margin: 1em 0 10px;
}
#nav-menu-bulk-actions-top {
margin: 1em 0;
}
#nav-menu-bulk-actions-bottom {
margin: 1em 0;
margin: calc( 1em + 9px ) 0 ;
}
.bulk-actions input.button {
margin-left: 12px;
}
.bulk-select-button {
position: relative;
display: inline-block;
padding: 0 10px;
font-size: 13px;
line-height: 2.15384615;
height: auto;
min-height: 30px;
background: #f6f7f7;
vertical-align: top;
border: 1px solid #dcdcde;
margin: 0;
cursor: pointer;
border-radius: 3px;
white-space: nowrap;
box-sizing: border-box;
}
.bulk-selection .bulk-select-button {
color: #2271b1;
border-color: #2271b1;
background: #f6f7f7;
vertical-align: top;
}
#pending-menu-items-to-delete {
display: none;
}
.bulk-selection #pending-menu-items-to-delete {
display: block;
margin-top: 1em;
}
#pending-menu-items-to-delete p {
margin-bottom: 0;
}
#pending-menu-items-to-delete ul {
margin-top: 0;
list-style: none;
}
#pending-menu-items-to-delete ul li {
display: inline;
}
input.bulk-select-switcher + .bulk-select-button-label {
vertical-align: inherit;
}
label.bulk-select-button:hover,
label.bulk-select-button:active,
label.bulk-select-button:focus-within {
background: #f0f0f1;
border-color: #0a4b78;
color: #0a4b78;
}
input.bulk-select-switcher:focus + .bulk-select-button-label{
color: #0a4b78;
}
.bulk-actions input.menu-items-delete {
-webkit-appearance: none;
appearance: none;
font-size: inherit;
border: 0;
line-height: 2.1em;
background: none;
cursor: pointer;
text-decoration: underline;
color: #b32d2e;
}
.bulk-actions input.menu-items-delete:hover {
color: #b32d2e;
border: none;
}
.bulk-actions input.menu-items-delete.disabled {
cursor: default;
color: #a7aaad;
box-shadow: none;
}
.menu-settings {
border-top: 1px solid #f0f0f1;
margin-top: 2em;
@ -482,6 +581,15 @@ ul.add-menu-item-tabs li {
margin-left: 13em;
}
.menu-item-handle .menu-item-checkbox {
display: none;
}
.bulk-selection .menu-item-handle .menu-item-checkbox {
display: inline-block;
margin-left: 6px;
}
.menu-item-handle .menu-item-title.no-title {
color: #646970;
}

File diff suppressed because one or more lines are too long

View File

@ -97,6 +97,105 @@ ul.add-menu-item-tabs li {
margin: 1em 0 10px;
}
#nav-menu-bulk-actions-top {
margin: 1em 0;
}
#nav-menu-bulk-actions-bottom {
margin: 1em 0;
margin: calc( 1em + 9px ) 0 ;
}
.bulk-actions input.button {
margin-right: 12px;
}
.bulk-select-button {
position: relative;
display: inline-block;
padding: 0 10px;
font-size: 13px;
line-height: 2.15384615;
height: auto;
min-height: 30px;
background: #f6f7f7;
vertical-align: top;
border: 1px solid #dcdcde;
margin: 0;
cursor: pointer;
border-radius: 3px;
white-space: nowrap;
box-sizing: border-box;
}
.bulk-selection .bulk-select-button {
color: #2271b1;
border-color: #2271b1;
background: #f6f7f7;
vertical-align: top;
}
#pending-menu-items-to-delete {
display: none;
}
.bulk-selection #pending-menu-items-to-delete {
display: block;
margin-top: 1em;
}
#pending-menu-items-to-delete p {
margin-bottom: 0;
}
#pending-menu-items-to-delete ul {
margin-top: 0;
list-style: none;
}
#pending-menu-items-to-delete ul li {
display: inline;
}
input.bulk-select-switcher + .bulk-select-button-label {
vertical-align: inherit;
}
label.bulk-select-button:hover,
label.bulk-select-button:active,
label.bulk-select-button:focus-within {
background: #f0f0f1;
border-color: #0a4b78;
color: #0a4b78;
}
input.bulk-select-switcher:focus + .bulk-select-button-label{
color: #0a4b78;
}
.bulk-actions input.menu-items-delete {
-webkit-appearance: none;
appearance: none;
font-size: inherit;
border: 0;
line-height: 2.1em;
background: none;
cursor: pointer;
text-decoration: underline;
color: #b32d2e;
}
.bulk-actions input.menu-items-delete:hover {
color: #b32d2e;
border: none;
}
.bulk-actions input.menu-items-delete.disabled {
cursor: default;
color: #a7aaad;
box-shadow: none;
}
.menu-settings {
border-top: 1px solid #f0f0f1;
margin-top: 2em;
@ -481,6 +580,15 @@ ul.add-menu-item-tabs li {
margin-right: 13em;
}
.menu-item-handle .menu-item-checkbox {
display: none;
}
.bulk-selection .menu-item-handle .menu-item-checkbox {
display: inline-block;
margin-right: 6px;
}
.menu-item-handle .menu-item-title.no-title {
color: #646970;
}

File diff suppressed because one or more lines are too long

View File

@ -118,7 +118,7 @@ class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
<li id="menu-item-<?php echo $item_id; ?>" class="<?php echo implode( ' ', $classes ); ?>">
<div class="menu-item-bar">
<div class="menu-item-handle">
<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>
<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>
<span class="item-controls">
<span class="item-type"><?php echo esc_html( $item->type_label ); ?></span>
<span class="item-order hide-if-js">

View File

@ -45,6 +45,11 @@
this.attachMenuEditListeners();
this.attachBulkSelectButtonListeners();
this.attachMenuCheckBoxListeners();
this.attachMenuItemDeleteButton();
this.attachPendingMenuItemsListForDeletion();
this.attachQuickSearchListeners();
this.attachThemeLocationsListeners();
this.attachMenuSaveSubmitListeners();
@ -862,6 +867,183 @@
});
},
/**
* Handle toggling bulk selection checkboxes for menu items.
*
* @since 5.8.0
*/
attachBulkSelectButtonListeners : function() {
var that = this;
$('.bulk-select-switcher').on( 'change', function(){
if( this.checked ){
$('.bulk-select-switcher').prop('checked',true);
that.enableBulkSelection();
}else{
$('.bulk-select-switcher').prop('checked',false);
that.disableBulkSelection();
}
});
},
/**
* Enable bulk selection checkboxes for menu items.
*
* @since 5.8.0
*/
enableBulkSelection : function() {
$('#menu-to-edit').addClass('bulk-selection');
$('#nav-menu-bulk-actions-top').addClass('bulk-selection');
$('#nav-menu-bulk-actions-bottom').addClass('bulk-selection');
var checkbox = $('#menu-to-edit .menu-item-checkbox');
$.each( checkbox, function(){
$(this).prop('disabled',false);
});
},
/**
* Disable bulk selection checkboxes for menu items.
*
* @since 5.8.0
*/
disableBulkSelection : function() {
$('#menu-to-edit').removeClass('bulk-selection');
$('#nav-menu-bulk-actions-top').removeClass('bulk-selection');
$('#nav-menu-bulk-actions-bottom').removeClass('bulk-selection');
if ( $('.menu-items-delete').is('[aria-describedby="pending-menu-items-to-delete"]') ) {
$('.menu-items-delete').removeAttr( 'aria-describedby' );
}
var checkbox = $('#menu-to-edit .menu-item-checkbox');
$.each( checkbox, function(){
$(this).prop('disabled',true).prop('checked',false);
});
$('.menu-items-delete').addClass('disabled');
$('#pending-menu-items-to-delete ul').empty();
},
/**
* Listen for state changes on bulk action checkboxes.
*
* @since 5.8.0
*/
attachMenuCheckBoxListeners : function() {
var that = this;
$( '#menu-to-edit' ).on( 'change', '.menu-item-checkbox', function(){
that.setRemoveSelectedButtonStatus();
});
},
/**
* Create delete button to remove menu items from collection.
*
* @since 5.8.0
*/
attachMenuItemDeleteButton : function() {
var that = this;
$( document ).on('click', '.menu-items-delete', function(e){
e.preventDefault();
if( ! $(this).hasClass('disabled') ){
$.each( $('.menu-item-checkbox:checked'), function( index, element ) {
$( element ).parents( 'li' ).find( 'a.item-delete' ).trigger( 'click' );
});
$('.menu-items-delete').addClass('disabled');
$('.bulk-select-switcher').prop('checked',false);
var itemsPendingDeletion = '';
var itemsPendingDeletionList = $('#pending-menu-items-to-delete ul li');
$.each( itemsPendingDeletionList, function( index, element ) {
var itemName = $( element ).find( '.pending-menu-item-name' ).text();
var itemSpeech = menus.menuItemDeletion.replace( '%s', itemName );
itemsPendingDeletion += itemSpeech ;
if( ( index + 1 ) < itemsPendingDeletionList.length ){
itemsPendingDeletion += ', ' ;
}
});
var deletionSpeech = menus.itemsDeleted.replace( '%s', itemsPendingDeletion );
wp.a11y.speak( deletionSpeech, 'polite' );
that.disableBulkSelection();
}
});
},
/**
* List menu items awaiting deletion.
*
* @since 5.8.0
*/
attachPendingMenuItemsListForDeletion : function(){
$('#post-body-content').on( 'change', '.menu-item-checkbox', function(){
if( ! $('.menu-items-delete').is('[aria-describedby="pending-menu-items-to-delete"]') ){ $('.menu-items-delete').attr( 'aria-describedby', 'pending-menu-items-to-delete' ); }
var menuItemName = $(this).next().text();
var menuItemType = $(this).parent().next('.item-controls').find('.item-type').text();
var menuItemID = $(this).attr('data-menu-item-id') ;
var ListedMenuItem = $('#pending-menu-items-to-delete ul').find('[data-menu-item-id=' + menuItemID + ']') ;
if( ListedMenuItem.length > 0 ){
ListedMenuItem.remove();
}
if( this.checked === true ){
$('#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>' );
}
$('#pending-menu-items-to-delete li .separator').html(', ');
$('#pending-menu-items-to-delete li .separator').last().html('.');
});
},
/**
* Set status of bulk delete checkbox.
*
* @since 5.8.0
*/
setBulkDeleteCheckboxStatus : function(){
var that = this;
var checkbox = $('#menu-to-edit .menu-item-checkbox');
$.each( checkbox, function(){
if( $(this).prop('disabled') == true ){
$(this).prop( 'disabled', false );
}else{
$(this).prop( 'disabled', true );
}
if( $(this).is(':checked')) {
$(this).prop('checked',false);
}
});
that.setRemoveSelectedButtonStatus();
},
/**
* Set status of menu items removal button.
*
* @since 5.8.0
*/
setRemoveSelectedButtonStatus : function(){
var button = $('.menu-items-delete');
if( $('.menu-item-checkbox:checked').length > 0 ) {
button.removeClass('disabled');
} else {
button.addClass('disabled');
}
},
attachMenuSaveSubmitListeners : function() {
/*
* When a navigation menu is saved, store a JSON representation of all form data
@ -908,7 +1090,7 @@
searchTimer = setTimeout( function() {
api.updateQuickSearchResults( $this );
}, 500 );
}, 500 );
}).on( 'blur', '.quick-search', function() {
api.lastSearch = '';
});

File diff suppressed because one or more lines are too long

View File

@ -485,6 +485,10 @@ $nav_menus_l10n = array(
'menuFocus' => __( '%1$s. Menu item %2$d of %3$d.' ),
/* translators: 1: Item name, 2: Item position, 3: Parent item name. */
'subMenuFocus' => __( '%1$s. Sub item number %2$d under %3$s.' ),
/* translators: %s: Item name. */
'menuItemDeletion' => __( 'item %s' ),
/* translators: %s: Item name. */
'itemsDeleted' => __( 'Deleted menu item: %s.' ),
);
wp_localize_script( 'nav-menu', 'menus', $nav_menus_l10n );
@ -961,7 +965,6 @@ require_once ABSPATH . 'wp-admin/admin-header.php';
<div id="post-body">
<div id="post-body-content" class="wp-clearfix">
<?php if ( ! $add_new_screen ) : ?>
<?php
$hide_style = '';
@ -978,7 +981,12 @@ require_once ABSPATH . 'wp-admin/admin-header.php';
<div class="drag-instructions post-body-plain" <?php echo $hide_style; ?>>
<p><?php echo $starter_copy; ?></p>
</div>
<div id="nav-menu-bulk-actions-top" class="bulk-actions">
<label class="bulk-select-button" for="bulk-select-switcher-top">
<input type="checkbox" id="bulk-select-switcher-top" name="bulk-select-switcher-top" class="bulk-select-switcher">
<span class="bulk-select-button-label"><?php echo __( 'Bulk Select' ) ; ?></span>
</label>
</div>
<?php
if ( isset( $edit_markup ) && ! is_wp_error( $edit_markup ) ) {
echo $edit_markup;
@ -1004,6 +1012,17 @@ require_once ABSPATH . 'wp-admin/admin-header.php';
$no_menus_style = 'style="display: none;"';
}
?>
<div id="nav-menu-bulk-actions-bottom" class="bulk-actions">
<label class="bulk-select-button" for="bulk-select-switcher-bottom">
<input type="checkbox" id="bulk-select-switcher-bottom" name="bulk-select-switcher-top" class="bulk-select-switcher">
<span class="bulk-select-button-label"><?php echo __( 'Bulk Select' ); ?></span>
</label>
<input type="button" class="deletion menu-items-delete disabled" value="<?php _e( 'Remove Selected Items' ) ; ?>">
<div id="pending-menu-items-to-delete">
<p><?php _e( 'List of menu items selected for deletion:' ) ; ?></p>
<ul></ul>
</div>
</div>
<div class="menu-settings" <?php echo $no_menus_style; ?>>
<h3><?php _e( 'Menu Settings' ); ?></h3>
<?php

View File

@ -13,7 +13,7 @@
*
* @global string $wp_version
*/
$wp_version = '5.8-alpha-51005';
$wp_version = '5.8-alpha-51006';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.