Quick/Bulk Edit: Pre-fill category fields with their status.

Pre-fill category fields in the Quick/Bulk Edit form with their current status.

When bulk editing, if only some of the selected items are in a given category, the category's checkbox will display a line to indicate an indeterminate status.

Originally committed in [56172], but reverted due to a bug that removed all categories. Updated commit fixes the bug, adds unit tests, and improves the accessibility of the indeterminate state checkboxes.

Props pavelevap, scribu, chasedsiedu, helen, joshcanhelp, ubernaut, Cyberchicken, laumindproductscomau, SergeyBiryukov, Marcoevich, tomybyte, thinkluke, virtality-marketing-solutions, Michalooki, dmsnell, itecrs, pannelars, WHSajid, samba45, Mte90, johnbillion, tomluckies, soulseekah, francina, oglekler, ajmcfadyen, mukesh27, costdev, hellofromTonya, peterwilsoncc, joedolson, pbiron, oglekler, webcommsat, jorbin, ajmcfadyen, huzaifaalmesbah.
Fixes #11302.

git-svn-id: https://develop.svn.wordpress.org/trunk@57580 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Joe Dolson 2024-02-09 19:48:41 +00:00
parent c70eb25f44
commit 9450c577cc
4 changed files with 191 additions and 2 deletions

View File

@ -178,6 +178,8 @@ window.wp = window.wp || {};
*/
setBulk : function(){
var te = '', type = this.type, c = true;
var checkedPosts = $( 'tbody th.check-column input[type="checkbox"]:checked' );
var categories = {};
this.revert();
$( '#bulk-edit td' ).attr( 'colspan', $( 'th:visible, td:visible', '.widefat:first thead' ).length );
@ -217,6 +219,44 @@ window.wp = window.wp || {};
// Populate the list of items to bulk edit.
$( '#bulk-titles' ).html( '<ul id="bulk-titles-list" role="list">' + te + '</ul>' );
// Gather up some statistics on which of these checked posts are in which categories.
checkedPosts.each( function() {
var id = $( this ).val();
var checked = $( '#category_' + id ).text().split( ',' );
checked.map( function( cid ) {
categories[ cid ] || ( categories[ cid ] = 0 );
// Just record that this category is checked.
categories[ cid ]++;
} );
} );
// Compute initial states.
$( '.inline-edit-categories input[name="post_category[]"]' ).each( function() {
if ( categories[ $( this ).val() ] == checkedPosts.length ) {
// If the number of checked categories matches the number of selected posts, then all posts are in this category.
$( this ).prop( 'checked', true );
} else if ( categories[ $( this ).val() ] > 0 ) {
// If the number is less than the number of selected posts, then it's indeterminate.
$( this ).prop( 'indeterminate', true );
if ( ! $( this ).parent().find( 'input[name="indeterminate_post_category[]"]' ).length ) {
// Get the term label text.
var label = $( this ).parent().text();
// Set indeterminate states for the backend. Add accessible text for indeterminate inputs.
$( this ).after( '<input type="hidden" name="indeterminate_post_category[]" value="' + $( this ).val() + '">' ).attr( 'aria-label', label.trim() + ': ' + wp.i18n.__( 'Some selected posts have this category' ) );
}
}
} );
$( '.inline-edit-categories input[name="post_category[]"]:indeterminate' ).on( 'change', function() {
// Remove accessible label text. Remove the indeterminate flags as there was a specific state change.
$( this ).removeAttr( 'aria-label' ).parent().find( 'input[name="indeterminate_post_category[]"]' ).remove();
} );
$( '.inline-edit-save button' ).on( 'click', function() {
$( '.inline-edit-categories input[name="post_category[]"]' ).prop( 'indeterminate', false );
} );
/**
* Binds on click events to handle the list of items to bulk edit.
*

View File

@ -1149,6 +1149,17 @@ ul.cat-checklist {
overflow-y: scroll;
}
ul.cat-checklist input[name="post_category[]"]:indeterminate::before {
content: '';
border-top: 2px solid grey;
width: 65%;
height: 2px;
position: absolute;
top: calc( 50% + 1px );
left: 50%;
transform: translate( -50%, -50% );
}
#bulk-titles .ntdelbutton,
#bulk-titles .ntdeltitle,
.inline-edit-row fieldset ul.cat-checklist label {

View File

@ -649,8 +649,21 @@ function bulk_edit_posts( $post_data = null ) {
}
if ( isset( $new_cats ) && in_array( 'category', $tax_names, true ) ) {
$cats = (array) wp_get_post_categories( $post_id );
$post_data['post_category'] = array_unique( array_merge( $cats, $new_cats ) );
$cats = (array) wp_get_post_categories( $post_id );
if (
isset( $post_data['indeterminate_post_category'] )
&& is_array( $post_data['indeterminate_post_category'] )
) {
$indeterminate_post_category = $post_data['indeterminate_post_category'];
} else {
$indeterminate_post_category = array();
}
$indeterminate_cats = array_intersect( $cats, $indeterminate_post_category );
$determinate_cats = array_diff( $new_cats, $indeterminate_post_category );
$post_data['post_category'] = array_unique( array_merge( $indeterminate_cats, $determinate_cats ) );
unset( $post_data['tax_input']['category'] );
}

View File

@ -384,6 +384,131 @@ class Tests_Admin_IncludesPost extends WP_UnitTestCase {
}
}
/**
* @ticket 11302
*/
public function test_bulk_edit_if_categories_unchanged() {
wp_set_current_user( self::$admin_id );
$post_ids = self::factory()->post->create_many( 3 );
wp_set_post_categories( $post_ids[0], array( 'test1', 'test2' ) );
wp_set_post_categories( $post_ids[1], array( 'test2', 'test3' ) );
wp_set_post_categories( $post_ids[2], array( 'test1', 'test3' ) );
$terms1 = wp_get_post_categories( $post_ids[0] );
$terms2 = wp_get_post_categories( $post_ids[1] );
$terms3 = wp_get_post_categories( $post_ids[2] );
$indeterminate_categories = array_merge( $terms1, $terms2, $terms3 );
$request = array(
'_status' => -1,
'post' => $post_ids,
'indeterminate_post_category' => $indeterminate_categories,
);
bulk_edit_posts( $request );
$updated_terms1 = wp_get_post_categories( $post_ids[0] );
$updated_terms2 = wp_get_post_categories( $post_ids[1] );
$updated_terms3 = wp_get_post_categories( $post_ids[2] );
$this->assertSame( $terms1, $updated_terms1, 'Post 1 should have terms 1 and 2.' );
$this->assertSame( $terms2, $updated_terms2, 'Post 2 should have terms 2 and 3.' );
$this->assertSame( $terms3, $updated_terms3, 'Post 3 should have terms 1 and 3.' );
}
/**
* @ticket 11302
*/
public function test_bulk_edit_if_some_categories_added() {
wp_set_current_user( self::$admin_id );
$post_ids = self::factory()->post->create_many( 3 );
$term1 = wp_create_category( 'test1' );
$term2 = wp_create_category( 'test2' );
$term3 = wp_create_category( 'test3' );
$term4 = wp_create_category( 'test4' );
wp_set_post_categories( $post_ids[0], array( $term1, $term2 ) );
wp_set_post_categories( $post_ids[1], array( $term2, $term3 ) );
wp_set_post_categories( $post_ids[2], array( $term1, $term3 ) );
$terms1 = wp_get_post_categories( $post_ids[0], array( 'fields' => 'ids' ) );
$terms2 = wp_get_post_categories( $post_ids[1], array( 'fields' => 'ids' ) );
$terms3 = wp_get_post_categories( $post_ids[2], array( 'fields' => 'ids' ) );
// All existing categories are indeterminate.
$indeterminate = array_unique( array_merge( $terms1, $terms2, $terms3 ) );
// Add new category.
$categories[] = $term4;
$request = array(
'_status' => -1,
'post' => $post_ids,
'post_category' => $categories,
'indeterminate_post_category' => $indeterminate,
);
bulk_edit_posts( $request );
$updated_terms1 = wp_get_post_categories( $post_ids[0], array( 'fields' => 'ids' ) );
$updated_terms2 = wp_get_post_categories( $post_ids[1], array( 'fields' => 'ids' ) );
$updated_terms3 = wp_get_post_categories( $post_ids[2], array( 'fields' => 'ids' ) );
// Each post should have the same categories as before and add term 4.
$this->assertSame( array( $term1, $term2, $term4 ), $updated_terms1, 'Post should have terms 1, 2, and 4.' );
$this->assertSame( array( $term2, $term3, $term4 ), $updated_terms2, 'Post should have terms 2, 3, and 4.' );
$this->assertSame( array( $term1, $term3, $term4 ), $updated_terms3, 'Post should have terms 1, 3, and 4.' );
}
/**
* @ticket 11302
*/
public function test_bulk_edit_if_some_categories_removed() {
wp_set_current_user( self::$admin_id );
$post_ids = self::factory()->post->create_many( 3 );
$term1 = wp_create_category( 'test1' );
$term2 = wp_create_category( 'test2' );
$term3 = wp_create_category( 'test3' );
wp_set_post_categories( $post_ids[0], array( $term1, $term2 ) );
wp_set_post_categories( $post_ids[1], array( $term2, $term3 ) );
wp_set_post_categories( $post_ids[2], array( $term1, $term3 ) );
$terms1 = wp_get_post_categories( $post_ids[0], array( 'fields' => 'ids' ) );
$terms2 = wp_get_post_categories( $post_ids[1], array( 'fields' => 'ids' ) );
$terms3 = wp_get_post_categories( $post_ids[2], array( 'fields' => 'ids' ) );
// Terms 2 and 3 are in indeterminate state.
$indeterminate = array( $term2, $term3 );
// Remove term 1 from selected categories.
$categories = array_unique( array_merge( $terms1, $terms2, $terms3 ) );
$remove_key = array_search( $term1, $categories, true );
unset( $categories[ $remove_key ] );
$request = array(
'_status' => -1,
'post' => $post_ids,
'post_category' => $categories,
'indeterminate_post_category' => $indeterminate,
);
bulk_edit_posts( $request );
$updated_terms1 = wp_get_post_categories( $post_ids[0], array( 'fields' => 'ids' ) );
$updated_terms2 = wp_get_post_categories( $post_ids[1], array( 'fields' => 'ids' ) );
$updated_terms3 = wp_get_post_categories( $post_ids[2], array( 'fields' => 'ids' ) );
// Post 1 should only have term 2.
$this->assertSame( $updated_terms1, array( $term2 ), 'Post 1 should only have term 2.' );
// Post 2 should be unchanged.
$this->assertSame( $terms2, $updated_terms2, 'Post 2 should be unchanged.' );
// Post 3 should only have term 3.
$this->assertSame( $updated_terms3, array( $term3 ), 'Post 3 should only have term 3.' );
}
/**
* Tests that `bulk_edit_posts()` fires the 'bulk_edit_posts' action.
*