From 5b4dec71b4165ba3fcfc675a72203d69b69e1c90 Mon Sep 17 00:00:00 2001
From: Deepak Kumar
Date: Fri, 17 Jul 2026 10:25:09 +0530
Subject: [PATCH 1/6] Administration: Always display the On This Day dashboard
widget
---
.../includes/dashboard-on-this-day.php | 34 +++----------------
tests/phpunit/tests/admin/wpOnThisDay.php | 29 +---------------
2 files changed, 6 insertions(+), 57 deletions(-)
diff --git a/src/wp-admin/includes/dashboard-on-this-day.php b/src/wp-admin/includes/dashboard-on-this-day.php
index 1939f8ca4b0e3..b2cc7c161975a 100644
--- a/src/wp-admin/includes/dashboard-on-this-day.php
+++ b/src/wp-admin/includes/dashboard-on-this-day.php
@@ -11,16 +11,14 @@
* Registers the On This Day dashboard widget.
*
* Designed to be the single entry point called from the dashboard setup
- * routine. The widget is always registered so that it remains available in
- * Screen Options and keeps its user-customized position. When there are no
- * matching posts, a marker class is added to the postbox so the widget can be
- * hidden with CSS.
+ * routine. The widget is always registered and always visible, keeping its
+ * Screen Options entry consistent with what is shown on screen. When there are
+ * no matching posts, a placeholder message is displayed. Users who do not want
+ * the widget can hide it via Screen Options, and that preference is preserved.
*
* @since 7.1.0
*/
function wp_dashboard_on_this_day_setup() {
- add_filter( 'postbox_classes_dashboard_wp_dashboard_on_this_day', 'wp_dashboard_on_this_day_postbox_classes' );
-
wp_add_dashboard_widget(
'wp_dashboard_on_this_day',
__( 'On This Day' ),
@@ -28,27 +26,6 @@ function wp_dashboard_on_this_day_setup() {
);
}
-/**
- * Hides the On This Day postbox when there are no posts to show.
- *
- * Adds the core `hidden` class so the widget stays registered — preserving its
- * Screen Options entry and user-customized position — while being hidden when
- * empty. A user can still reveal it via Screen Options, in which case the
- * placeholder message is shown.
- *
- * @since 7.1.0
- *
- * @param string[] $classes An array of postbox classes.
- * @return string[] Filtered postbox classes.
- */
-function wp_dashboard_on_this_day_postbox_classes( $classes ) {
- if ( empty( wp_dashboard_on_this_day_get_posts() ) ) {
- $classes[] = 'hidden';
- }
-
- return $classes;
-}
-
/**
* Renders the On This Day dashboard widget.
*
@@ -60,8 +37,7 @@ function wp_dashboard_on_this_day() {
$posts = wp_dashboard_on_this_day_get_posts();
if ( empty( $posts ) ) {
- // Placeholder shown when a user reveals the hidden widget via Screen
- // Options on a day with no matching posts.
+ // Placeholder shown on a day with no matching posts in previous years.
echo '' . esc_html__( 'No posts were published on this day in previous years.' ) . '
';
return;
}
diff --git a/tests/phpunit/tests/admin/wpOnThisDay.php b/tests/phpunit/tests/admin/wpOnThisDay.php
index 61aef6401683a..6740caa3a0ac6 100644
--- a/tests/phpunit/tests/admin/wpOnThisDay.php
+++ b/tests/phpunit/tests/admin/wpOnThisDay.php
@@ -94,7 +94,7 @@ private static function get_date_query_clause( $date ) {
/**
* @covers ::wp_dashboard_on_this_day_setup
*/
- public function test_setup_always_registers_widget_and_postbox_class_filter() {
+ public function test_setup_always_registers_widget() {
$this->set_up_dashboard_screen();
$user_id = self::factory()->user->create( array( 'role' => 'author' ) );
@@ -106,33 +106,6 @@ public function test_setup_always_registers_widget_and_postbox_class_filter() {
$this->assertArrayHasKey( 'wp_dashboard_on_this_day', $dashboard_widgets );
$this->assertSame( 'On This Day', $dashboard_widgets['wp_dashboard_on_this_day']['title'] );
- $this->assertNotFalse(
- has_filter(
- 'postbox_classes_dashboard_wp_dashboard_on_this_day',
- 'wp_dashboard_on_this_day_postbox_classes'
- )
- );
- }
-
- /**
- * @covers ::wp_dashboard_on_this_day_postbox_classes
- */
- public function test_postbox_classes_hides_widget_without_matching_posts() {
- $user_id = self::factory()->user->create( array( 'role' => 'author' ) );
- wp_set_current_user( $user_id );
-
- $this->assertContains( 'hidden', wp_dashboard_on_this_day_postbox_classes( array( '' ) ) );
- }
-
- /**
- * @covers ::wp_dashboard_on_this_day_postbox_classes
- */
- public function test_postbox_classes_does_not_hide_widget_with_matching_posts() {
- $user_id = self::factory()->user->create( array( 'role' => 'author' ) );
- wp_set_current_user( $user_id );
- $this->create_matching_post( $user_id );
-
- $this->assertNotContains( 'hidden', wp_dashboard_on_this_day_postbox_classes( array( '' ) ) );
}
/**
From d218c56c885149a07deb1d1782dfa5c3d71db745 Mon Sep 17 00:00:00 2001
From: Aki Hamano
Date: Wed, 29 Jul 2026 10:33:39 +0900
Subject: [PATCH 2/6] Inline wp_dashboard_on_this_day_setup() into
wp_dashboard_setup().
The setup function only wrapped a single wp_add_dashboard_widget() call,
which added an indirection every other core dashboard widget does without.
Registering the widget directly in wp_dashboard_setup() keeps the On This
Day widget consistent with At a Glance, Activity, and Quick Draft.
The file guard now checks for wp_dashboard_on_this_day(), the render
callback that remains in dashboard-on-this-day.php.
The two unit tests for the removed function only asserted that
wp_add_dashboard_widget() had been called, which no other core widget is
tested for, so they are dropped along with their now unused helpers.
Query and rendering behavior stays covered by the remaining tests.
Co-Authored-By: Claude
---
.../includes/dashboard-on-this-day.php | 19 -------
src/wp-admin/includes/dashboard.php | 4 +-
.../tests/admin/wpDashboardOnThisDay.php | 55 -------------------
3 files changed, 2 insertions(+), 76 deletions(-)
diff --git a/src/wp-admin/includes/dashboard-on-this-day.php b/src/wp-admin/includes/dashboard-on-this-day.php
index b2cc7c161975a..23a411e7e34e8 100644
--- a/src/wp-admin/includes/dashboard-on-this-day.php
+++ b/src/wp-admin/includes/dashboard-on-this-day.php
@@ -7,25 +7,6 @@
* @since 7.1.0
*/
-/**
- * Registers the On This Day dashboard widget.
- *
- * Designed to be the single entry point called from the dashboard setup
- * routine. The widget is always registered and always visible, keeping its
- * Screen Options entry consistent with what is shown on screen. When there are
- * no matching posts, a placeholder message is displayed. Users who do not want
- * the widget can hide it via Screen Options, and that preference is preserved.
- *
- * @since 7.1.0
- */
-function wp_dashboard_on_this_day_setup() {
- wp_add_dashboard_widget(
- 'wp_dashboard_on_this_day',
- __( 'On This Day' ),
- 'wp_dashboard_on_this_day'
- );
-}
-
/**
* Renders the On This Day dashboard widget.
*
diff --git a/src/wp-admin/includes/dashboard.php b/src/wp-admin/includes/dashboard.php
index 5fdbaf7a4fa40..a0c2a23189644 100644
--- a/src/wp-admin/includes/dashboard.php
+++ b/src/wp-admin/includes/dashboard.php
@@ -89,11 +89,11 @@ function wp_dashboard_setup() {
}
// On This Day.
- if ( ! function_exists( 'wp_dashboard_on_this_day_setup' ) ) {
+ if ( ! function_exists( 'wp_dashboard_on_this_day' ) ) {
require_once ABSPATH . 'wp-admin/includes/dashboard-on-this-day.php';
}
- wp_dashboard_on_this_day_setup();
+ wp_add_dashboard_widget( 'wp_dashboard_on_this_day', __( 'On This Day' ), 'wp_dashboard_on_this_day' );
// WordPress Events and News.
wp_add_dashboard_widget( 'dashboard_primary', __( 'WordPress Events and News' ), 'wp_dashboard_events_news' );
diff --git a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
index c2f2f50922193..ed6d7bfc18842 100644
--- a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
+++ b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
@@ -32,25 +32,6 @@ public static function wpTearDownAfterClass() {
self::delete_user( self::$other_user_id );
}
- public function tear_down() {
- unset( $GLOBALS['wp_meta_boxes']['dashboard'] );
-
- parent::tear_down();
- }
-
- /**
- * Sets up the globals needed to register dashboard widgets.
- */
- private function set_up_dashboard_screen() {
- if ( ! function_exists( 'wp_add_dashboard_widget' ) ) {
- require_once ABSPATH . 'wp-admin/includes/dashboard.php';
- }
-
- set_current_screen( 'dashboard' );
-
- $GLOBALS['wp_meta_boxes']['dashboard'] = array();
- }
-
/**
* Creates a published post on the widget's prior-year calendar day.
*
@@ -114,42 +95,6 @@ private static function get_date_query_clause( string $date ): array {
return _wp_dashboard_on_this_day_date_query_clause( new DateTimeImmutable( $date, wp_timezone() ) );
}
- /**
- * @ticket 65116
- *
- * @covers ::wp_dashboard_on_this_day_setup
- */
- public function test_setup_always_registers_widget() {
- $this->set_up_dashboard_screen();
-
- wp_set_current_user( self::$user_id );
-
- wp_dashboard_on_this_day_setup();
-
- $dashboard_widgets = $GLOBALS['wp_meta_boxes']['dashboard']['normal']['core'] ?? array();
-
- $this->assertArrayHasKey( 'wp_dashboard_on_this_day', $dashboard_widgets );
- $this->assertSame( 'On This Day', $dashboard_widgets['wp_dashboard_on_this_day']['title'] );
- }
-
- /**
- * @ticket 65116
- *
- * @covers ::wp_dashboard_on_this_day_setup
- */
- public function test_setup_adds_dashboard_widget_with_matching_post_from_another_author() {
- $this->set_up_dashboard_screen();
-
- wp_set_current_user( self::$user_id );
- $this->create_matching_post( self::$other_user_id );
-
- wp_dashboard_on_this_day_setup();
-
- $dashboard_widgets = $GLOBALS['wp_meta_boxes']['dashboard']['normal']['core'] ?? array();
-
- $this->assertArrayHasKey( 'wp_dashboard_on_this_day', $dashboard_widgets );
- }
-
/**
* @ticket 65116
*
From 60ab25192fd85d3381c7ca91415ac9f6a8a589f8 Mon Sep 17 00:00:00 2001
From: Aki Hamano
Date: Sat, 1 Aug 2026 18:08:06 +0900
Subject: [PATCH 3/6] Reword the On This Day empty state and link to the new
post screen.
Now that the widget is always displayed, its empty state is seen far more
often, including on sites that rarely publish. The previous sentence only
stated a fact and offered no way forward, so it is replaced with a shorter,
invitational message that links straight to the new post screen.
The link is only rendered for users who can create posts; everyone else sees
the message on its own.
---
.../includes/dashboard-on-this-day.php | 14 +++++++-
.../tests/admin/wpDashboardOnThisDay.php | 32 +++++++++++++++++--
2 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/src/wp-admin/includes/dashboard-on-this-day.php b/src/wp-admin/includes/dashboard-on-this-day.php
index 23a411e7e34e8..be81d8d58060a 100644
--- a/src/wp-admin/includes/dashboard-on-this-day.php
+++ b/src/wp-admin/includes/dashboard-on-this-day.php
@@ -19,7 +19,19 @@ function wp_dashboard_on_this_day() {
if ( empty( $posts ) ) {
// Placeholder shown on a day with no matching posts in previous years.
- echo '' . esc_html__( 'No posts were published on this day in previous years.' ) . '
';
+ echo '';
+
+ if ( current_user_can( 'edit_posts' ) ) {
+ printf(
+ /* translators: %s: URL to the new post screen. */
+ __( 'Nothing here yet. Write today’s post.' ),
+ esc_url( admin_url( 'post-new.php' ) )
+ );
+ } else {
+ echo esc_html__( 'Nothing here yet.' );
+ }
+
+ echo '
';
return;
}
diff --git a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
index ed6d7bfc18842..393f6be6adb14 100644
--- a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
+++ b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
@@ -10,6 +10,8 @@ class Tests_Admin_wpDashboardOnThisDay extends WP_UnitTestCase {
protected static int $other_user_id;
+ protected static int $subscriber_id;
+
public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
require_once ABSPATH . 'wp-admin/includes/dashboard-on-this-day.php';
@@ -25,11 +27,18 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
'role' => 'author',
)
);
+ self::$subscriber_id = $factory->user->create(
+ array(
+ 'display_name' => 'Reader',
+ 'role' => 'subscriber',
+ )
+ );
}
public static function wpTearDownAfterClass() {
self::delete_user( self::$user_id );
self::delete_user( self::$other_user_id );
+ self::delete_user( self::$subscriber_id );
}
/**
@@ -165,10 +174,29 @@ public function test_widget_outputs_placeholder_without_matching_posts() {
wp_dashboard_on_this_day();
$output = ob_get_clean();
- $this->assertStringContainsString( 'No posts were published on this day in previous years.', $output );
+ $this->assertStringContainsString( 'Nothing here yet.', $output );
+ $this->assertStringContainsString( 'Write today’s post', $output );
+ $this->assertStringContainsString( admin_url( 'post-new.php' ), $output );
$this->assertStringNotContainsString( '', $output );
}
+ /**
+ * @ticket 65116
+ *
+ * @covers ::wp_dashboard_on_this_day
+ */
+ public function test_widget_placeholder_omits_link_without_edit_posts_capability() {
+ wp_set_current_user( self::$subscriber_id );
+
+ ob_start();
+ wp_dashboard_on_this_day();
+ $output = ob_get_clean();
+
+ $this->assertStringContainsString( 'Nothing here yet.', $output );
+ $this->assertStringNotContainsString( 'Write today’s post', $output );
+ $this->assertStringNotContainsString( admin_url( 'post-new.php' ), $output );
+ }
+
/**
* @ticket 65116
*
@@ -183,7 +211,7 @@ public function test_widget_ignores_nearby_prior_year_posts() {
$output = ob_get_clean();
$this->assertStringNotContainsString( 'Almost a memory', $output );
- $this->assertStringContainsString( 'No posts were published on this day in previous years.', $output );
+ $this->assertStringContainsString( 'Nothing here yet.', $output );
}
/**
From 7057cc91c775eb530c87cc906b02cec6d0bd793f Mon Sep 17 00:00:00 2001
From: Aki Hamano
Date: Sun, 2 Aug 2026 13:28:21 +0900
Subject: [PATCH 4/6] Restore the explanatory sentence in the On This Day empty
state.
The shortened "Nothing here yet." message dropped the connection to what the
widget actually does, leaving no explanation of why the area is empty. The
original sentence is restored and the invitation to publish is folded into it,
so the empty state both explains itself and offers a way forward.
Co-Authored-By: Claude
---
src/wp-admin/includes/dashboard-on-this-day.php | 4 ++--
tests/phpunit/tests/admin/wpDashboardOnThisDay.php | 10 +++++-----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/wp-admin/includes/dashboard-on-this-day.php b/src/wp-admin/includes/dashboard-on-this-day.php
index be81d8d58060a..19d1d5452751c 100644
--- a/src/wp-admin/includes/dashboard-on-this-day.php
+++ b/src/wp-admin/includes/dashboard-on-this-day.php
@@ -24,11 +24,11 @@ function wp_dashboard_on_this_day() {
if ( current_user_can( 'edit_posts' ) ) {
printf(
/* translators: %s: URL to the new post screen. */
- __( 'Nothing here yet. Write today’s post.' ),
+ __( 'No posts were published on this day in previous years. Write one today, and be reminded about it next year.' ),
esc_url( admin_url( 'post-new.php' ) )
);
} else {
- echo esc_html__( 'Nothing here yet.' );
+ echo esc_html__( 'No posts were published on this day in previous years.' );
}
echo '
';
diff --git a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
index 393f6be6adb14..37d1a669dd1d3 100644
--- a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
+++ b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
@@ -174,8 +174,8 @@ public function test_widget_outputs_placeholder_without_matching_posts() {
wp_dashboard_on_this_day();
$output = ob_get_clean();
- $this->assertStringContainsString( 'Nothing here yet.', $output );
- $this->assertStringContainsString( 'Write today’s post', $output );
+ $this->assertStringContainsString( 'No posts were published on this day in previous years.', $output );
+ $this->assertStringContainsString( 'Write one today', $output );
$this->assertStringContainsString( admin_url( 'post-new.php' ), $output );
$this->assertStringNotContainsString( '', $output );
}
@@ -192,8 +192,8 @@ public function test_widget_placeholder_omits_link_without_edit_posts_capability
wp_dashboard_on_this_day();
$output = ob_get_clean();
- $this->assertStringContainsString( 'Nothing here yet.', $output );
- $this->assertStringNotContainsString( 'Write today’s post', $output );
+ $this->assertStringContainsString( 'No posts were published on this day in previous years.', $output );
+ $this->assertStringNotContainsString( 'Write one today', $output );
$this->assertStringNotContainsString( admin_url( 'post-new.php' ), $output );
}
@@ -211,7 +211,7 @@ public function test_widget_ignores_nearby_prior_year_posts() {
$output = ob_get_clean();
$this->assertStringNotContainsString( 'Almost a memory', $output );
- $this->assertStringContainsString( 'Nothing here yet.', $output );
+ $this->assertStringContainsString( 'No posts were published on this day in previous years.', $output );
}
/**
From 699f995d5f598217d31ed8499445adc8ebf7f8c2 Mon Sep 17 00:00:00 2001
From: Aki Hamano
Date: Mon, 3 Aug 2026 19:40:18 +0900
Subject: [PATCH 5/6] Fix the On This Day tests broken by the trunk merge.
The excerpt tests added in trunk call a set_up_dashboard_screen() helper that
this branch removed, since registering the widget by hand is no longer needed
now that it is always displayed. Merging the two left the calls without their
helper and the tests errored out.
The helper is not restored, because only one part of it still matters: outside
the admin, get_the_title() prefixes private and password protected posts with
"Private:" / "Protected:", so an untitled post no longer looks untitled and the
"(no title)" fallback never renders. The widget only ever runs on the
dashboard, so the screen is now set once in set_up() for the whole class rather
than per test. WP_UnitTestCase resets the current screen globals on tear down,
so no cleanup is required.
Co-Authored-By: Claude
---
tests/phpunit/tests/admin/wpDashboardOnThisDay.php | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
index 9b564950f8d96..cd1d7439585f6 100644
--- a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
+++ b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
@@ -41,6 +41,13 @@ public static function wpTearDownAfterClass() {
self::delete_user( self::$subscriber_id );
}
+ public function set_up() {
+ parent::set_up();
+
+ // The widget only ever renders on the dashboard, where titles are not prefixed by `get_the_title()`.
+ set_current_screen( 'dashboard' );
+ }
+
/**
* Creates a published post on the widget's prior-year calendar day.
*
@@ -349,8 +356,6 @@ public function test_widget_does_not_append_excerpt_to_titled_posts() {
* @covers ::wp_dashboard_on_this_day
*/
public function test_widget_includes_trimmed_excerpt_for_untitled_private_posts_authored_by_current_user() {
- $this->set_up_dashboard_screen();
-
wp_set_current_user( self::$user_id );
$this->create_matching_post(
@@ -384,8 +389,6 @@ public function test_widget_includes_trimmed_excerpt_for_untitled_private_posts_
* @covers ::wp_dashboard_on_this_day
*/
public function test_widget_hides_untitled_post_excerpt_for_unreadable_posts() {
- $this->set_up_dashboard_screen();
-
wp_set_current_user( self::$user_id );
$post_id = $this->create_matching_post(
@@ -420,8 +423,6 @@ public function test_widget_hides_untitled_post_excerpt_for_unreadable_posts() {
* @covers ::wp_dashboard_on_this_day
*/
public function test_widget_hides_untitled_post_excerpt_for_password_protected_posts() {
- $this->set_up_dashboard_screen();
-
wp_set_current_user( self::$user_id );
$this->create_matching_post(
From 5e6a57b6cbc3e410b729e00d27b9c3dc527f253f Mon Sep 17 00:00:00 2001
From: Aki Hamano
Date: Mon, 3 Aug 2026 19:41:27 +0900
Subject: [PATCH 6/6] Drop the redundant comment above set_current_screen().
The dashboard is the only screen this widget renders on, so setting it in the
test set up needs no explanation. Other tests that put set_current_screen() in
set_up() leave it unannotated as well.
Co-Authored-By: Claude
---
tests/phpunit/tests/admin/wpDashboardOnThisDay.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
index cd1d7439585f6..728b9bcef64d0 100644
--- a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
+++ b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php
@@ -44,7 +44,6 @@ public static function wpTearDownAfterClass() {
public function set_up() {
parent::set_up();
- // The widget only ever renders on the dashboard, where titles are not prefixed by `get_the_title()`.
set_current_screen( 'dashboard' );
}