Make WordPress Core

Changeset 57580


Ignore:
Timestamp:
02/09/2024 07:48:41 PM (2 months ago)
Author:
joedolson
Message:

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.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/js/_enqueues/admin/inline-edit-post.js

    r57093 r57580  
    179179    setBulk : function(){
    180180        var te = '', type = this.type, c = true;
     181        var checkedPosts = $( 'tbody th.check-column input[type="checkbox"]:checked' );
     182        var categories = {};
    181183        this.revert();
    182184
     
    217219        // Populate the list of items to bulk edit.
    218220        $( '#bulk-titles' ).html( '<ul id="bulk-titles-list" role="list">' + te + '</ul>' );
     221
     222        // Gather up some statistics on which of these checked posts are in which categories.
     223        checkedPosts.each( function() {
     224            var id      = $( this ).val();
     225            var checked = $( '#category_' + id ).text().split( ',' );
     226
     227            checked.map( function( cid ) {
     228                categories[ cid ] || ( categories[ cid ] = 0 );
     229                // Just record that this category is checked.
     230                categories[ cid ]++;
     231            } );
     232        } );
     233
     234        // Compute initial states.
     235        $( '.inline-edit-categories input[name="post_category[]"]' ).each( function() {
     236            if ( categories[ $( this ).val() ] == checkedPosts.length ) {
     237                // If the number of checked categories matches the number of selected posts, then all posts are in this category.
     238                $( this ).prop( 'checked', true );
     239            } else if ( categories[ $( this ).val() ] > 0 ) {
     240                // If the number is less than the number of selected posts, then it's indeterminate.
     241                $( this ).prop( 'indeterminate', true );
     242                if ( ! $( this ).parent().find( 'input[name="indeterminate_post_category[]"]' ).length ) {
     243                    // Get the term label text.
     244                    var label = $( this ).parent().text();
     245                    // Set indeterminate states for the backend. Add accessible text for indeterminate inputs.
     246                    $( 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' ) );
     247                }
     248            }
     249        } );
     250
     251        $( '.inline-edit-categories input[name="post_category[]"]:indeterminate' ).on( 'change', function() {
     252            // Remove accessible label text. Remove the indeterminate flags as there was a specific state change.
     253            $( this ).removeAttr( 'aria-label' ).parent().find( 'input[name="indeterminate_post_category[]"]' ).remove();
     254        } );
     255
     256        $( '.inline-edit-save button' ).on( 'click', function() {
     257            $( '.inline-edit-categories input[name="post_category[]"]' ).prop( 'indeterminate', false );
     258        } );
    219259
    220260        /**
  • trunk/src/wp-admin/css/list-tables.css

    r57553 r57580  
    11501150}
    11511151
     1152ul.cat-checklist input[name="post_category[]"]:indeterminate::before {
     1153    content: '';
     1154    border-top: 2px solid grey;
     1155    width: 65%;
     1156    height: 2px;
     1157    position: absolute;
     1158    top: calc( 50% + 1px );
     1159    left: 50%;
     1160    transform: translate( -50%, -50% );
     1161}
     1162
    11521163#bulk-titles .ntdelbutton,
    11531164#bulk-titles .ntdeltitle,
  • trunk/src/wp-admin/includes/post.php

    r57521 r57580  
    650650
    651651        if ( isset( $new_cats ) && in_array( 'category', $tax_names, true ) ) {
    652             $cats                       = (array) wp_get_post_categories( $post_id );
    653             $post_data['post_category'] = array_unique( array_merge( $cats, $new_cats ) );
     652            $cats = (array) wp_get_post_categories( $post_id );
     653
     654            if (
     655                isset( $post_data['indeterminate_post_category'] )
     656                && is_array( $post_data['indeterminate_post_category'] )
     657            ) {
     658                $indeterminate_post_category = $post_data['indeterminate_post_category'];
     659            } else {
     660                $indeterminate_post_category = array();
     661            }
     662
     663            $indeterminate_cats         = array_intersect( $cats, $indeterminate_post_category );
     664            $determinate_cats           = array_diff( $new_cats, $indeterminate_post_category );
     665            $post_data['post_category'] = array_unique( array_merge( $indeterminate_cats, $determinate_cats ) );
     666
    654667            unset( $post_data['tax_input']['category'] );
    655668        }
  • trunk/tests/phpunit/tests/admin/includesPost.php

    r57068 r57580  
    383383            $this->assertSame( 'aside', get_post_format( $post_id ) );
    384384        }
     385    }
     386
     387    /**
     388     * @ticket 11302
     389     */
     390    public function test_bulk_edit_if_categories_unchanged() {
     391        wp_set_current_user( self::$admin_id );
     392
     393        $post_ids = self::factory()->post->create_many( 3 );
     394
     395        wp_set_post_categories( $post_ids[0], array( 'test1', 'test2' ) );
     396        wp_set_post_categories( $post_ids[1], array( 'test2', 'test3' ) );
     397        wp_set_post_categories( $post_ids[2], array( 'test1', 'test3' ) );
     398
     399        $terms1 = wp_get_post_categories( $post_ids[0] );
     400        $terms2 = wp_get_post_categories( $post_ids[1] );
     401        $terms3 = wp_get_post_categories( $post_ids[2] );
     402
     403        $indeterminate_categories = array_merge( $terms1, $terms2, $terms3 );
     404
     405        $request = array(
     406            '_status'                     => -1,
     407            'post'                        => $post_ids,
     408            'indeterminate_post_category' => $indeterminate_categories,
     409        );
     410
     411        bulk_edit_posts( $request );
     412
     413        $updated_terms1 = wp_get_post_categories( $post_ids[0] );
     414        $updated_terms2 = wp_get_post_categories( $post_ids[1] );
     415        $updated_terms3 = wp_get_post_categories( $post_ids[2] );
     416
     417        $this->assertSame( $terms1, $updated_terms1, 'Post 1 should have terms 1 and 2.' );
     418        $this->assertSame( $terms2, $updated_terms2, 'Post 2 should have terms 2 and 3.' );
     419        $this->assertSame( $terms3, $updated_terms3, 'Post 3 should have terms 1 and 3.' );
     420    }
     421
     422    /**
     423     * @ticket 11302
     424     */
     425    public function test_bulk_edit_if_some_categories_added() {
     426        wp_set_current_user( self::$admin_id );
     427
     428        $post_ids = self::factory()->post->create_many( 3 );
     429        $term1    = wp_create_category( 'test1' );
     430        $term2    = wp_create_category( 'test2' );
     431        $term3    = wp_create_category( 'test3' );
     432        $term4    = wp_create_category( 'test4' );
     433
     434        wp_set_post_categories( $post_ids[0], array( $term1, $term2 ) );
     435        wp_set_post_categories( $post_ids[1], array( $term2, $term3 ) );
     436        wp_set_post_categories( $post_ids[2], array( $term1, $term3 ) );
     437
     438        $terms1 = wp_get_post_categories( $post_ids[0], array( 'fields' => 'ids' ) );
     439        $terms2 = wp_get_post_categories( $post_ids[1], array( 'fields' => 'ids' ) );
     440        $terms3 = wp_get_post_categories( $post_ids[2], array( 'fields' => 'ids' ) );
     441        // All existing categories are indeterminate.
     442        $indeterminate = array_unique( array_merge( $terms1, $terms2, $terms3 ) );
     443        // Add new category.
     444        $categories[] = $term4;
     445
     446        $request = array(
     447            '_status'                     => -1,
     448            'post'                        => $post_ids,
     449            'post_category'               => $categories,
     450            'indeterminate_post_category' => $indeterminate,
     451        );
     452
     453        bulk_edit_posts( $request );
     454
     455        $updated_terms1 = wp_get_post_categories( $post_ids[0], array( 'fields' => 'ids' ) );
     456        $updated_terms2 = wp_get_post_categories( $post_ids[1], array( 'fields' => 'ids' ) );
     457        $updated_terms3 = wp_get_post_categories( $post_ids[2], array( 'fields' => 'ids' ) );
     458
     459        // Each post should have the same categories as before and add term 4.
     460        $this->assertSame( array( $term1, $term2, $term4 ), $updated_terms1, 'Post should have terms 1, 2, and 4.' );
     461        $this->assertSame( array( $term2, $term3, $term4 ), $updated_terms2, 'Post should have terms 2, 3, and 4.' );
     462        $this->assertSame( array( $term1, $term3, $term4 ), $updated_terms3, 'Post should have terms 1, 3, and 4.' );
     463    }
     464
     465    /**
     466     * @ticket 11302
     467     */
     468    public function test_bulk_edit_if_some_categories_removed() {
     469        wp_set_current_user( self::$admin_id );
     470
     471        $post_ids = self::factory()->post->create_many( 3 );
     472        $term1    = wp_create_category( 'test1' );
     473        $term2    = wp_create_category( 'test2' );
     474        $term3    = wp_create_category( 'test3' );
     475
     476        wp_set_post_categories( $post_ids[0], array( $term1, $term2 ) );
     477        wp_set_post_categories( $post_ids[1], array( $term2, $term3 ) );
     478        wp_set_post_categories( $post_ids[2], array( $term1, $term3 ) );
     479
     480        $terms1 = wp_get_post_categories( $post_ids[0], array( 'fields' => 'ids' ) );
     481        $terms2 = wp_get_post_categories( $post_ids[1], array( 'fields' => 'ids' ) );
     482        $terms3 = wp_get_post_categories( $post_ids[2], array( 'fields' => 'ids' ) );
     483
     484        // Terms 2 and 3 are in indeterminate state.
     485        $indeterminate = array( $term2, $term3 );
     486        // Remove term 1 from selected categories.
     487        $categories = array_unique( array_merge( $terms1, $terms2, $terms3 ) );
     488        $remove_key = array_search( $term1, $categories, true );
     489        unset( $categories[ $remove_key ] );
     490
     491        $request = array(
     492            '_status'                     => -1,
     493            'post'                        => $post_ids,
     494            'post_category'               => $categories,
     495            'indeterminate_post_category' => $indeterminate,
     496        );
     497
     498        bulk_edit_posts( $request );
     499
     500        $updated_terms1 = wp_get_post_categories( $post_ids[0], array( 'fields' => 'ids' ) );
     501        $updated_terms2 = wp_get_post_categories( $post_ids[1], array( 'fields' => 'ids' ) );
     502        $updated_terms3 = wp_get_post_categories( $post_ids[2], array( 'fields' => 'ids' ) );
     503
     504        // Post 1 should only have term 2.
     505        $this->assertSame( $updated_terms1, array( $term2 ), 'Post 1 should only have term 2.' );
     506        // Post 2 should be unchanged.
     507        $this->assertSame( $terms2, $updated_terms2, 'Post 2 should be unchanged.' );
     508        // Post 3 should only have term 3.
     509        $this->assertSame( $updated_terms3, array( $term3 ), 'Post 3 should only have term 3.' );
    385510    }
    386511
Note: See TracChangeset for help on using the changeset viewer.