Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/wp-admin/css/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -514,13 +514,15 @@ code {
}

.widefat th,
.widefat tbody td.check-column,
.widefat thead td,
.widefat tfoot td {
text-align: left;
line-height: 1.3em;
font-size: 14px;
}

.widefat td.check-column input,
.widefat th input,
.updates-table td input,
.widefat thead td input,
Expand All @@ -536,12 +538,14 @@ code {
vertical-align: top;
}

.widefat tbody th.check-column {
.widefat tbody th.check-column,
.widefat tbody td.check-column {
padding: 9px 0 22px;
}

.widefat thead td.check-column,
.widefat tbody th.check-column,
.widefat tbody td.check-column,
.updates-table tbody td.check-column,
.widefat tfoot td.check-column {
padding: 11px 0 0 3px;
Expand Down
3 changes: 2 additions & 1 deletion src/wp-admin/css/forms.css
Original file line number Diff line number Diff line change
Expand Up @@ -1967,7 +1967,8 @@ table.form-table td .updated p {
margin-left: 0;
}

.wp-list-table.privacy_requests tr:not(.inline-edit-row):not(.no-items) td.column-primary:not(.check-column) {
.wp-list-table.privacy_requests tr:not(.inline-edit-row):not(.no-items) td.column-primary:not(.check-column),
.wp-list-table.privacy_requests tr:not(.inline-edit-row):not(.no-items) th.column-primary:not(.check-column) {
display: table-cell;
}

Expand Down
37 changes: 26 additions & 11 deletions src/wp-admin/css/list-tables.css
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,13 @@
background-color: #fcf9e8;
}

#the-comment-list .unapproved th.check-column {
#the-comment-list .unapproved th.check-column,
#the-comment-list .unapproved td.check-column {
border-left: 4px solid #d63638;
}

#the-comment-list .unapproved th.check-column input {
#the-comment-list .unapproved th.check-column input,
#the-comment-list .unapproved td.check-column input {
margin-left: 4px;
}

Expand Down Expand Up @@ -1221,11 +1223,13 @@ ul.cat-checklist input[name="post_category[]"]:indeterminate::before {
------------------------------------------------------------------------------*/

.plugins tbody th.check-column,
.plugins tbody td.check-column,
.plugins tbody {
padding: 8px 0 0 2px;
}

.plugins tbody th.check-column input[type=checkbox] {
.plugins tbody th.check-column input[type=checkbox],
.plugins tbody td.check-column input[type=checkbox] {
margin-top: 4px;
}

Expand All @@ -1235,7 +1239,8 @@ ul.cat-checklist input[name="post_category[]"]:indeterminate::before {

.plugins thead td.check-column,
.plugins tfoot td.check-column,
.plugins .inactive th.check-column {
.plugins .inactive th.check-column,
.plugins .inactive td.check-column {
padding-left: 6px;
}

Expand Down Expand Up @@ -1325,6 +1330,7 @@ ul.cat-checklist input[name="post_category[]"]:indeterminate::before {
}

.plugins .active th.check-column,
.plugins .active td.check-column,
.plugin-update-tr.active td {
border-left: 4px solid var(--wp-admin-theme-color);
}
Expand Down Expand Up @@ -1410,7 +1416,8 @@ ul.cat-checklist input[name="post_category[]"]:indeterminate::before {
text-decoration: underline;
}

.plugins tr.paused th.check-column {
.plugins tr.paused th.check-column,
.plugins tr.paused td.check-column {
border-left: 4px solid #b32d2e;
}

Expand Down Expand Up @@ -1909,7 +1916,8 @@ div.action-links,
}

.wp-list-table th.column-primary ~ th,
.wp-list-table tr:not(.inline-edit-row):not(.no-items) td.column-primary ~ td:not(.check-column) {
.wp-list-table tr:not(.inline-edit-row):not(.no-items) td.column-primary ~ td:not(.check-column),
.wp-list-table tr:not(.inline-edit-row):not(.no-items) th.column-primary ~ td:not(.check-column) {
display: none;
}

Expand All @@ -1918,7 +1926,8 @@ div.action-links,
}

/* Checkboxes need to show */
.wp-list-table tr th.check-column {
.wp-list-table tr th.check-column,
.wp-list-table tr td.check-column {
display: table-cell;
}

Expand All @@ -1936,11 +1945,13 @@ div.action-links,
width: auto !important; /* needs to override some columns that are more specifically targeted */
}

.wp-list-table td.column-primary {
.wp-list-table td.column-primary,
.wp-list-table th.column-primary {
padding-right: 50px; /* space for toggle button */
}

.wp-list-table tr:not(.inline-edit-row):not(.no-items) td.column-primary ~ td:not(.check-column) {
.wp-list-table tr:not(.inline-edit-row):not(.no-items) td.column-primary ~ td:not(.check-column),
.wp-list-table tr:not(.inline-edit-row):not(.no-items) th.column-primary ~ td:not(.check-column) {
padding: 3px 8px 3px 35%;
}

Expand Down Expand Up @@ -2269,12 +2280,14 @@ div.action-links,
}

.plugins tr.active + tr.inactive th.check-column,
.plugins tr.active + tr.inactive td.check-column,
.plugins tr.active + tr.inactive td.column-description,
.plugins .plugin-update-tr:before {
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1);
}

.plugins tr.active + tr.inactive th.check-column,
.plugins tr.active + tr.inactive td.check-column,
.plugins tr.active + tr.inactive td {
border-top: none;
}
Expand Down Expand Up @@ -2309,13 +2322,15 @@ div.action-links,
line-height: 1.5;
}

.plugins tbody th.check-column {
.plugins tbody th.check-column,
.plugins tbody td.check-column {
padding: 8px 0 0 5px;
}

.plugins thead td.check-column,
.plugins tfoot td.check-column,
.plugins .inactive th.check-column {
.plugins .inactive th.check-column,
.plugins .inactive td.check-column {
padding-left: 9px;
}

Expand Down
53 changes: 43 additions & 10 deletions src/wp-admin/includes/class-wp-list-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,26 @@ protected function column_default( $item, $column_name ) {}
*/
protected function column_cb( $item ) {}

/**
* Returns a clean, human-readable label for the primary column's row header.
*
* Used as the `aria-label` attribute value on the `<th scope="row">` element,
* giving screen readers a concise cell name instead of computing it from
* the full cell content (which may include row action links, excerpts, etc.).
*
* Subclasses should override this method to return the item's primary
* identifier (e.g. post title, plugin name, username). Return an empty string
* to omit the attribute.
*
* @since 6.9.0
*
* @param object|array $item The current item.
* @return string The aria-label value, or an empty string.
*/
protected function get_primary_column_aria_label( $item ) {
return '';
}

/**
* Generates the columns for a single row of the table.
*
Expand Down Expand Up @@ -1796,9 +1816,9 @@ protected function single_row_columns( $item ) {
$attributes = "class='$classes' $data";

if ( 'cb' === $column_name ) {
echo '<th scope="row" class="check-column">';
echo '<td class="check-column">';
echo $this->column_cb( $item );
echo '</th>';
echo '</td>';
} elseif ( method_exists( $this, '_column_' . $column_name ) ) {
echo call_user_func(
array( $this, '_column_' . $column_name ),
Expand All @@ -1807,16 +1827,29 @@ protected function single_row_columns( $item ) {
$data,
$primary
);
} elseif ( method_exists( $this, 'column_' . $column_name ) ) {
echo "<td $attributes>";
echo call_user_func( array( $this, 'column_' . $column_name ), $item );
echo $this->handle_row_actions( $item, $column_name, $primary );
echo '</td>';
} else {
echo "<td $attributes>";
echo $this->column_default( $item, $column_name );
$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 ) . '"';
}
}

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 '</td>';
echo "</$tag>";
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/wp-admin/includes/class-wp-ms-themes-list-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -940,11 +940,11 @@ public function single_row_columns( $item ) {

switch ( $column_name ) {
case 'cb':
echo '<th scope="row" class="check-column">';
echo '<td class="check-column">';

$this->column_cb( $item );

echo '</th>';
echo '</td>';
break;

case 'name':
Expand All @@ -966,11 +966,11 @@ public function single_row_columns( $item ) {
}
}

echo "<td class='theme-title column-primary{$extra_classes}'><strong>" . $item->display( 'Name' ) . $active_theme_label . '</strong>';
echo "<th scope='row' class='theme-title column-primary{$extra_classes}' aria-label='" . esc_attr( $item->display( 'Name' ) ) . "'><strong>" . $item->display( 'Name' ) . $active_theme_label . '</strong>';

$this->column_name( $item );

echo '</td>';
echo '</th>';
break;

case 'description':
Expand Down
6 changes: 3 additions & 3 deletions src/wp-admin/includes/class-wp-plugins-list-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -1233,12 +1233,12 @@ public function single_row( $item ) {

switch ( $column_name ) {
case 'cb':
echo "<th scope='row' class='check-column'>$checkbox</th>";
echo "<td class='check-column'>$checkbox</td>";
break;
case 'name':
echo "<td class='plugin-title column-primary'><strong>$plugin_name</strong>";
echo "<th scope='row' class='plugin-title column-primary' aria-label='" . esc_attr( $plugin_name ) . "'><strong>$plugin_name</strong>";
echo $this->row_actions( $actions, true );
echo '</td>';
echo '</th>';
break;
case 'description':
$classes = 'column-description desc';
Expand Down
22 changes: 20 additions & 2 deletions src/wp-admin/includes/class-wp-posts-list-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -1114,10 +1114,28 @@ public function column_cb( $item ) {
* @param string $primary
*/
protected function _column_title( $post, $classes, $data, $primary ) {
echo '<td class="' . $classes . ' page-title" ', $data, '>';
$aria_label = $this->get_primary_column_aria_label( $post );
$aria_attr = ( '' !== $aria_label ) ? ' aria-label="' . esc_attr( $aria_label ) . '"' : '';
echo '<th scope="row" class="' . $classes . ' page-title" ', $data, $aria_attr, '>';
echo $this->column_title( $post );
echo $this->handle_row_actions( $post, 'title', $primary );
echo '</td>';
echo '</th>';
}

/**
* Returns a clean label for the primary (title) column's row header `aria-label`.
*
* Provides screen readers with just the post title as the row header name,
* preventing them from computing the name from the full cell content
* (which includes row action links, post states, and possibly an excerpt).
*
* @since 6.9.0
*
* @param WP_Post $item The current post object.
* @return string The post title, or 'no title' if no title.
*/
protected function get_primary_column_aria_label( $item ) {
return isset( $item->post_title ) && ! empty( $item->post_title ) ? $item->post_title : __( 'no title' );
}

/**
Expand Down
14 changes: 11 additions & 3 deletions src/wp-admin/includes/class-wp-users-list-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -563,9 +563,16 @@ public function single_row( $user_object, $style = '', $role = '', $numposts = 0
$attributes = "class='$classes' $data";

if ( 'cb' === $column_name ) {
$row .= "<th scope='row' class='check-column'>$checkbox</th>";
$row .= "<td class='check-column'>$checkbox</td>";
} else {
$row .= "<td $attributes>";
$is_primary = ( $primary === $column_name );
$tag = $is_primary ? 'th' : 'td';
$scope = $is_primary ? ' scope="row"' : '';
$aria_label = '';
if ( $is_primary ) {
$aria_label = ' aria-label="' . esc_attr( $user_object->user_login ) . '"';
}
$row .= "<$tag $attributes$scope$aria_label>";
switch ( $column_name ) {
case 'username':
$row .= "$avatar $edit";
Expand Down Expand Up @@ -628,7 +635,8 @@ public function single_row( $user_object, $style = '', $role = '', $numposts = 0
if ( $primary === $column_name ) {
$row .= $this->row_actions( $actions );
}
$row .= '</td>';
$tag = ( $primary === $column_name ) ? 'th' : 'td';
$row .= "</$tag>";
}
}
$row .= '</tr>';
Expand Down
Loading