Skip to content
Open
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
5 changes: 5 additions & 0 deletions src/wp-admin/css/list-tables.css
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,11 @@ td.plugin-title p {
margin: 6px 0;
}

.trimmed-post-excerpt {
font-weight: 400;
padding-left: 4px;
}
Comment on lines +366 to +369

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I want the lighter font-weight when it is still part of the link, but I like having a small amount of padding to offset the excerpt.

Posts list with published and draft posts, in Compact view, with excerpts for titleless posts

And the title is not linked in Trash:

post without a title, showing trimmed excerpt in Trash


/* Media file column */
table.media .column-title .media-icon {
float: left;
Expand Down
26 changes: 24 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 @@ -1018,9 +1018,13 @@ private function _page_rows( &$children_pages, &$count, $parent_page, $level, $p
* @since 4.3.0
* @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support.
*

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For both changed methods, I think it's worth a version annotation, e.g.,

* @since 7.1.0 Includes a trimmed excerpt for untitled posts in Compact view.

* @global string $mode List table view mode.
*
* @param WP_Post $item The current WP_Post object.
*/
public function column_cb( $item ) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The checkbox label should include the same text as the link (with 'Select').

The locked icon text might not require the same, but I updated that anyway.

global $mode;

// Restores the more descriptive, specific name for use within this method.
$post = $item;

Expand All @@ -1037,13 +1041,23 @@ public function column_cb( $item ) {
* @param WP_Post $post The current WP_Post object.
*/
if ( apply_filters( 'wp_list_table_show_post_checkbox', $show, $post ) ) :

$post_title = _draft_or_post_title();

// If the post has no title, try adding part of the excerpt.
if ( 'excerpt' !== $mode && '' === get_the_title( $post ) && ! post_password_required( $post ) ) {
$excerpt = get_the_excerpt( $post );
if ( '' !== $excerpt && is_string( $excerpt ) ) {
$post_title .= ' ' . esc_html( wp_trim_words( $excerpt, 15, '…' ) );

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests_Admin_wpPostsListTable already tests output in some way.

Worth adding a small test here?

Codex came up with this quick example, but worth testing whether it fails first
/**
 * @ticket 65022
 *
 * @dataProvider data_should_show_trimmed_excerpt_for_untitled_posts_only_in_compact_view
 *
 * @covers WP_Posts_List_Table::column_cb
 * @covers WP_Posts_List_Table::column_title
 */
public function test_should_show_trimmed_excerpt_for_untitled_posts_only_in_compact_view( $list_mode, $should_show_excerpt ) {
	global $mode;

	wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );

	$mode = $list_mode;

	$post = self::factory()->post->create_and_get(
		array(
			'post_title'   => '',
			'post_excerpt' => 'One two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen.',
			'post_status'  => 'publish',
		)
	);

	$table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => 'edit-post' ) );

	ob_start();
	$table->single_row( $post );
	$output = ob_get_clean();

	$expected_excerpt = 'One two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen…';

	if ( $should_show_excerpt ) {
		$this->assertStringContainsString(
			'<span class="trimmed-post-excerpt">' . $expected_excerpt . '</span>',
			$output
		);

		$this->assertStringContainsString(
			'Select (no title) ' . $expected_excerpt,
			$output
		);
	} else {
		$this->assertStringNotContainsString( 'class="trimmed-post-excerpt"', $output );
		$this->assertStringNotContainsString( 'Select (no title) ' . $expected_excerpt, $output );
	}
}

/**
 * Data provider.
 *
 * @return array
 */
public function data_should_show_trimmed_excerpt_for_untitled_posts_only_in_compact_view() {
	return array(
		'compact view' => array( 'list', true ),
		'extended view' => array( 'excerpt', false ),
	);
}

}
}
?>
<input id="cb-select-<?php the_ID(); ?>" type="checkbox" name="post[]" value="<?php the_ID(); ?>" />
<label for="cb-select-<?php the_ID(); ?>">
<span class="screen-reader-text">
<?php
/* translators: %s: Post title. */
printf( __( 'Select %s' ), _draft_or_post_title() );
printf( __( 'Select %s' ), $post_title );

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this might make it more confusing for users with screen readers or not. Visual users have the luxury of styling to differentiate "(no title)" (bold) from the trimmed excerpt (regular weight).

Should we rearrange the output for screen readers? Otherwise it'll look like this:

<span class="screen-reader-text">Select (no title) Lorem ipsum dolor sit amet</span>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joedolson mind taking a look here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value of changing the font-weight is debatable.

However, I do not agree about rearranging the order of "(no title)" and the excerpt.

  • I thought I had seen a similar discussion, either on Trac or Slack, about matching invisible label text to the visible text. The closest I found was Trac 63620, where both the invisible label and visible text are exactly the same. In the posts list table, the invisible label includes "Select", and most languages have that before the title.
  • When the link's accessible name and visible text are "(no title) Lorem ipsum", the label can include the same text in the same order. Technique G211 mentions matching label text to adjacent visible text that "serves as its label". The link technically does not serve as the checkbox's label, but it can serve a similar purpose in addition to being a link on its own.

Ultimately, I do not think these new links and labels can be as accessible as having real, unique titles for every post.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Select (no title) some excerpt... is strange 🤔

I'm no expert, but a couple of options come to mind:

  1. Visible separator Select (no title): some excerpt...
  2. Word cue: Select (no title), excerpt: some excerpt...
  3. Add aria-describedby="post-excerpt-123" ?

I'm not sure!

?>
</span>
</label>
Expand All @@ -1054,7 +1068,7 @@ public function column_cb( $item ) {
printf(
/* translators: Hidden accessibility text. %s: Post title. */
__( '&#8220;%s&#8221; is locked' ),
_draft_or_post_title()
$post_title
);
?>
</span>
Expand Down Expand Up @@ -1142,6 +1156,14 @@ public function column_title( $post ) {

$title = _draft_or_post_title();

// If the post has no title, try adding part of the excerpt.
if ( 'excerpt' !== $mode && '' === get_the_title( $post ) && ! post_password_required( $post ) ) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have a read_post guard similar to the one below. Both expose excerpt/content-derived text.

E.g.,

if ( 'excerpt' !== $mode
	&& '' === get_the_title( $post )
	&& ! post_password_required( $post )
	&& current_user_can( 'read_post', $post->ID )
) {
	$excerpt = get_the_excerpt( $post );
	// ...
}

This applies to both instances I think.

$excerpt = get_the_excerpt( $post );
if ( '' !== $excerpt && is_string( $excerpt ) ) {
$title .= ' <span class="trimmed-post-excerpt">' . esc_html( wp_trim_words( $excerpt, 15, '&hellip;' ) ) . '</span>';
}
}

if ( $can_edit_post && 'trash' !== $post->post_status ) {
printf(
'<a class="row-title" href="%s">%s%s</a>',
Expand Down
Loading