Make WordPress Core

Opened 23 hours ago

Last modified 17 hours ago

#65968 new defect (bug)

Hidden check box (checkbox) column in the `WP_List_Table` is not hide.

Reported by: okvee Owned by:
Priority: normal Milestone: Awaiting Review
Component: General Version: 7.1
Severity: normal Keywords: has-patch has-unit-tests
Cc: Focuses:

Description

On the source of WP_List_Table ( https://github.com/WordPress/wordpress-develop/blob/3f5fdc537810c3b11f8084f3d35398edad5f8f35/src/wp-admin/includes/class-wp-list-table.php#L1383 ), the hidden columns can be set to _column_headers property.

The hidden columns can hide properly on another columns except on the check box column.

From my example ( https://github.com/Rundiz-WP/demo-listtable-ajax/blob/f6691a114414cd16d0911518e55d8592b91b23cf/App/DB/CustomersListTableHideCb.php#L238-L242 ), I was set the hidden column as check box column.

<?php
$this->_column_headers = [
    $this->get_columns(),
    ['cb'],
    $this->get_sortable_columns(),
];

By default, WordPress did not hide this column (as seen in the method single_row_columns() https://github.com/WordPress/wordpress-develop/blob/3f5fdc537810c3b11f8084f3d35398edad5f8f35/src/wp-admin/includes/class-wp-list-table.php#L1824-L1827 )
This happens on WP 7.0, 7.1 and not sure that the older versions too or not.

I tried to override the method single_row_column and it seems to work but next problem is, it (check box column) is not hidden properly on small screen of WordPress 7.0- (or older).

I am not sure is this the main purpose of WP_List_Table class to always display checkbox column. Or not?
If it is, then this ticket will be end here.

(If this is main purpose of this column, it still weird that checkbox column only hide on <thead> and <tfoot> except <tbody>.)


Step to re-produce:

  1. Create some simple extended of list table class with hidden column as cb.
  2. Create display page to display the list table.
  3. Open this list table page.

Expect: List table hide the column checkbox completely.
Actual: Only checkbox column header, footer is hide. Not in <tbody>.

Fix 1: override single_row_columns() method.

    protected function single_row_columns( $item ) 
    {
        global $wp_version;
        if (version_compare($wp_version, '7.1', '>=')) {
            $wp7_1 = true;
        } else {
            $wp7_1 = false;
        }


        list($columns, $hidden, $sortable, $primary) = $this->get_column_info();


        foreach ($columns as $column_name => $column_display_name) {
            $classes = "$column_name column-$column_name";
            if ($primary === $column_name) {
                $classes .= ' has-row-actions column-primary';
            }


            if (in_array($column_name, $hidden, true)) {
                $classes .= ' hidden';
            }


            /*
             * Comments column uses HTML in the display name with screen reader text.
             * Strip tags to get closer to a user-friendly string.
             */
            $data = 'data-colname="' . esc_attr(wp_strip_all_tags($column_display_name)) . '"';


            $attributes = "class='$classes' $data";


            if ('cb' === $column_name) {
                $tag = (true === $wp7_1 ? 'td' : 'th');
                $cb_attributes = (false === $wp7_1 ? ' scope="row"' : '');
                $cb_classes = 'check-column';
                if (in_array($column_name, $hidden, true)) {
                    $cb_classes .= ' hidden demo-listtable-ajax-hidecb-column';
                }
                echo '<' . $tag . $cb_attributes . ' class="' . esc_attr($cb_classes) . '">';
                echo $this->column_cb($item);
                echo '</' . $tag . '>';
            } elseif (method_exists($this, '_column_' . $column_name)) {
                echo call_user_func(
                    array($this, '_column_' . $column_name),
                    $item,
                    $classes,
                    $data,
                    $primary
                );
            } else {
                if (true === $wp7_1) {
                    $is_primary = ($primary === $column_name);
                    $tag = $is_primary ? 'th' : 'td';
                    $scope = $is_primary ? ' scope="row"' : '';


                    $aria_label = '';
                    if ($is_primary) {
                        $label = $this->get_primary_column_aria_label($item);
                        if ('' !== $label) {
                            $aria_label = ' aria-label="' . esc_attr($label) . '"';
                        }
                    }
                } else {
                    $aria_label = '';
                    $scope = '';
                    $tag = 'td';
                }


                echo "<$tag $attributes$scope$aria_label>";


                if (method_exists($this, 'column_' . $column_name)) {
                    echo call_user_func(array($this, 'column_' . $column_name), $item);
                } else {
                    echo $this->column_default($item, $column_name);
                }


                echo $this->handle_row_actions($item, $column_name, $primary);
                echo "</$tag>";
            }
        }// endforeach;
    }// single_row_columns

Result: Only fixed on WordPress 7.1+ or newer. But WordPress 7.0.x or older still has a problem on small screen that checkbox column is not hide.

Fix2: Enqueue this CSS for WordPress 7.0.x or older.

@media (max-width: 782px) {
    .demo-listtable-ajax-hidecb-column {
        display: none !important;/* On small screen with hidden check box column, the column not really hidden due to `display: table-cell;` by WP core. */
    }
}

Result: The checkbox column is now completely hide on small and large screen, based on WordPress 7.0.x.

Change History (2)

#1 @iamchitti
22 hours ago

Thanks for the report, @okvee - reproduced on trunk.

print_column_headers() honours $hidden for every column including cb, but single_row_columns() short-circuits the cb case before $classes is used, so <thead>/<tfoot> hide and <tbody> does not. Looks unintentional. $hidden is already available in the method:

<?php
if ( 'cb' === $column_name ) {
      $cb_classes = 'check-column';

      if ( in_array( $column_name, $hidden, true ) ) {
              $cb_classes .= ' hidden';
      }

      echo '<td class="' . $cb_classes . '">';
      echo $this->column_cb( $item );
      echo '</td>';
}

Verified in the browser: the body cell now computes to display: none at both 1400px and 600px, and Posts/Plugins/Users are unchanged where cb is not hidden. I will open a PR with this change and a unit test.

Fix 2 should not be needed on trunk - the display: table-cell on .check-column that beat .hidden is gone since [62958] / #65743. A backport to older branches would need the CSS looked at separately.

This ticket was mentioned in PR #13284 on WordPress/wordpress-develop by @iamchitti.


17 hours ago
#2

  • Keywords has-patch has-unit-tests added

Trac ticket: https://core.trac.wordpress.org/ticket/65968

## What

When cb is included in a list table's hidden columns, <thead> and <tfoot> hide it but <tbody> does not, so every row still renders a checkbox cell.

WP_List_Table::print_column_headers() honours $hidden for every column including cb, but single_row_columns() short-circuits the cb case before $classes is used and always emits <td class="check-column">.

On a wide screen the still-visible body cell also absorbs the width freed by the hidden header, so it renders ~330px wide instead of ~35px and pushes the remaining columns out of alignment.

## How

Apply the hidden class to the checkbox cell when cb is in $hidden. $hidden is already available from the get_column_info() call at the top of the method.

## Test

  1. Create a list table with a cb column that sets $this->_column_headers = array( $this->get_columns(), array( 'cb' ), array() ); and render it on an admin page.
  2. Before: the header and footer hide the checkbox column, but every body row shows an empty checkbox cell and the columns are misaligned.
  3. After: the checkbox column is hidden in the body too, at both desktop and sub-782px widths, and the columns line up.
  4. Confirm Posts, Plugins and Users are unchanged, since cb is not hidden there.

## Screenshots

Before -

https://github.com/user-attachments/assets/0367159a-535f-42b5-8161-8f023303e93a

After -

https://github.com/user-attachments/assets/d975180c-f481-4b9a-a522-442394ea90cd

No regression -

https://github.com/user-attachments/assets/8f148e47-e3e9-48d2-b649-6f0d3390f631

## AI Usage

AI assistance: Yes
Tool(s): Claude Code
Model(s): Opus 5
Used for: drafting the fix and unit tests

Note: See TracTickets for help on using tickets.