diff --git a/src/wp-admin/includes/dashboard-on-this-day.php b/src/wp-admin/includes/dashboard-on-this-day.php
index 1939f8ca4b0e3..1caa37057d08a 100644
--- a/src/wp-admin/includes/dashboard-on-this-day.php
+++ b/src/wp-admin/includes/dashboard-on-this-day.php
@@ -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 ) {
+ 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.
*
@@ -114,10 +141,12 @@ function wp_dashboard_on_this_day() {
post_author;
@@ -125,7 +154,9 @@ function wp_dashboard_on_this_day() {
$show_author = '' !== trim( $author_name ) && get_current_user_id() !== $author_id;
?>
-
-
+
+
+
' . esc_html(
diff --git a/tests/phpunit/tests/admin/wpOnThisDay.php b/tests/phpunit/tests/admin/wpOnThisDay.php
index 61aef6401683a..6220cf1e23218 100644
--- a/tests/phpunit/tests/admin/wpOnThisDay.php
+++ b/tests/phpunit/tests/admin/wpOnThisDay.php
@@ -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
)
);
}
@@ -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( '…', $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