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
37 changes: 34 additions & 3 deletions src/wp-admin/includes/dashboard-on-this-day.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,33 @@ function wp_dashboard_on_this_day_postbox_classes( $classes ) {
return $classes;
}

/**
* Gets a trimmed excerpt to display in place of a missing post title.
*
* Only returns text for posts that have no title and do not require a password.
*
* @since 7.1.0
* @access private
*
* @param WP_Post $post The current WP_Post object.
* @return string The trimmed excerpt, or an empty string.
*/
function _wp_dashboard_on_this_day_get_no_title_excerpt( $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.

Core introduced get_no_title_excerpt() for the upcoming WordPress 7.1 release. See:

protected function get_no_title_excerpt( $post ) {

It looks like this duplicates the functionality we're adding here.

@alshakero alshakero Jul 17, 2026

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.

Yes I actually copied that, but it's protected inside a class. Do you think we should make a util and use it in both places?

@alshakero alshakero Jul 17, 2026

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.

So I checked once more and I think these two functions are only slightly similar to each other.

  • WP_Posts_List_Table::get_no_title_excerpt() is list-table-specific, it checks compact mode, current_user_can, and returns already-escaped text.
  • The On This Day widget does not need compact mode nor the current_user_can check and it escapes at render time.

if ( '' !== get_the_title( $post )
|| post_password_required( $post )
) {
return '';
}

$excerpt = get_the_excerpt( $post );

if ( '' === $excerpt || ! is_string( $excerpt ) ) {
return '';
}

return wp_trim_words( $excerpt, 15 );
}

/**
* Renders the On This Day dashboard widget.
*
Expand Down Expand Up @@ -114,18 +141,22 @@ function wp_dashboard_on_this_day() {
<ul>
<?php foreach ( $year_posts as $year_post ) : ?>
<?php
$title = get_the_title( $year_post );
$title = get_the_title( $year_post );
$no_title_excerpt = '';

if ( '' === trim( $title ) ) {
$title = __( '(no title)' );
$title = __( '(no title)' );
$no_title_excerpt = _wp_dashboard_on_this_day_get_no_title_excerpt( $year_post );
}

$author_id = (int) $year_post->post_author;
$author_name = $author_id > 0 ? (string) get_the_author_meta( 'display_name', $author_id ) : '';
$show_author = '' !== trim( $author_name ) && get_current_user_id() !== $author_id;
?>
<li>
<a href="<?php echo esc_url( get_permalink( $year_post ) ); ?>"><?php echo esc_html( $title ); ?></a>
<a href="<?php echo esc_url( get_permalink( $year_post ) ); ?>"><?php echo esc_html( $title ); ?><?php if ( '' !== $no_title_excerpt ) : ?>
<span class="trimmed-post-excerpt"><?php echo esc_html( $no_title_excerpt ); ?></span>
<?php endif; ?></a>
<?php if ( $show_author ) : ?>
<?php
echo '<span class="wp-on-this-day-post-author">' . esc_html(
Expand Down
80 changes: 73 additions & 7 deletions tests/phpunit/tests/admin/wpOnThisDay.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,28 @@ private function set_up_dashboard_screen() {
* @param string $title Post title.
* @param int $years_ago Number of years before today.
* @param string $time Post time.
* @param array $post_args Additional post arguments.
* @return int Post ID.
*/
private function create_matching_post(
$author_id,
$title = 'A memory from last year',
$years_ago = 1,
$time = '12:00:00'
$time = '12:00:00',
$post_args = array()
) {
$post_date = current_datetime()->modify( '-' . $years_ago . ' years' )->format( 'Y-m-d' ) . ' ' . $time;

return self::factory()->post->create(
array(
'post_author' => $author_id,
'post_date' => $post_date,
'post_date_gmt' => get_gmt_from_date( $post_date ),
'post_status' => 'publish',
'post_title' => $title,
array_merge(
array(
'post_author' => $author_id,
'post_date' => $post_date,
'post_date_gmt' => get_gmt_from_date( $post_date ),
'post_status' => 'publish',
'post_title' => $title,
),
$post_args
)
);
}
Expand Down Expand Up @@ -309,6 +314,67 @@ public function test_widget_groups_posts_by_year() {
$this->assertStringContainsString( 'Late-night shipping log', $output );
}

/**
* @covers ::wp_dashboard_on_this_day
* @covers ::_wp_dashboard_on_this_day_get_no_title_excerpt
*/
public function test_widget_includes_trimmed_excerpt_for_untitled_posts() {
$user_id = self::factory()->user->create( array( 'role' => 'author' ) );
wp_set_current_user( $user_id );

$words = array();
for ( $n = 1; $n <= 20; $n++ ) {
$words[] = 'word' . $n;
}

$this->create_matching_post(
$user_id,
'',
1,
'12:00:00',
array(
'post_excerpt' => implode( ' ', $words ),
)
);

ob_start();
wp_dashboard_on_this_day();
$output = ob_get_clean();

$this->assertStringContainsString( '(no title)', $output );
$this->assertStringContainsString( 'class="trimmed-post-excerpt"', $output );
$this->assertStringContainsString( 'word15', $output, 'The 15th word should be present.' );
$this->assertStringNotContainsString( 'word16', $output, 'The 16th word should be trimmed.' );
$this->assertStringContainsString( '&hellip;', $output, 'The excerpt should end with an ellipsis.' );
}

/**
* @covers ::wp_dashboard_on_this_day
* @covers ::_wp_dashboard_on_this_day_get_no_title_excerpt
*/
public function test_widget_hides_untitled_post_excerpt_for_password_protected_posts() {
$user_id = self::factory()->user->create( array( 'role' => 'author' ) );
wp_set_current_user( $user_id );

$this->create_matching_post(
$user_id,
'',
1,
'12:00:00',
array(
'post_excerpt' => 'Private anniversary memory.',
'post_password' => 'secret',
)
);

ob_start();
wp_dashboard_on_this_day();
$output = ob_get_clean();

$this->assertStringNotContainsString( 'Private anniversary memory.', $output );
$this->assertStringNotContainsString( 'class="trimmed-post-excerpt"', $output );
}

/**
* @covers ::wp_dashboard_on_this_day
* @covers ::wp_dashboard_on_this_day_get_posts
Expand Down
Loading