Skip to content

Commit e8f519d

Browse files
committed
Widgets: Add "On This Day" dashboard widget.
Add a dashboard widget that shows users past entries published on the same month and day from previous years. The widget is hidden if there are no history to show for the date. Props alshakero, eclev91, annezazu, westonruter, kellychoffman, simison, joen, retrofox, audrasjb, desrosj, peterwilsoncc, matt, sabernhardt, wildworks, jeherve, apermo, dmsnell, jonsurrell, jorbin, talldanwp, retrofox, joedolson. Fixes #65116. git-svn-id: https://develop.svn.wordpress.org/trunk@62681 602fd350-edb4-49c9-b593-d223f7449a82
1 parent e82d922 commit e8f519d

4 files changed

Lines changed: 607 additions & 0 deletions

File tree

src/wp-admin/css/dashboard.css

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,35 @@ body #dashboard-widgets .postbox form .submit {
10171017
top: 0;
10181018
}
10191019

1020+
/* On This Day dashboard widget */
1021+
1022+
#wp_dashboard_on_this_day h3 {
1023+
font-weight: 600;
1024+
}
1025+
1026+
#wp_dashboard_on_this_day li {
1027+
margin: 0;
1028+
padding: 0;
1029+
}
1030+
1031+
#wp_dashboard_on_this_day ul ul {
1032+
margin: 0 0 0 18px;
1033+
padding: 0;
1034+
list-style: disc;
1035+
}
1036+
1037+
#wp_dashboard_on_this_day ul ul li + li {
1038+
margin-top: 6px;
1039+
}
1040+
1041+
#wp_dashboard_on_this_day .wp-on-this-day-widget > ul > li + li {
1042+
margin-top: 16px;
1043+
}
1044+
1045+
#wp_dashboard_on_this_day .wp-on-this-day-post-author {
1046+
color: #646970;
1047+
}
1048+
10201049
/* Browse happy box */
10211050

10221051
#dashboard-widgets #dashboard_browser_nag.postbox .inside {
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
<?php
2+
/**
3+
* WordPress Dashboard "On This Day" widget.
4+
*
5+
* @package WordPress
6+
* @subpackage Administration
7+
* @since 7.1.0
8+
*/
9+
10+
/**
11+
* Registers the On This Day dashboard widget.
12+
*
13+
* Designed to be the single entry point called from the dashboard setup
14+
* routine. The widget is always registered so that it remains available in
15+
* Screen Options and keeps its user-customized position. When there are no
16+
* matching posts, a marker class is added to the postbox so the widget can be
17+
* hidden with CSS.
18+
*
19+
* @since 7.1.0
20+
*/
21+
function wp_dashboard_on_this_day_setup() {
22+
add_filter( 'postbox_classes_dashboard_wp_dashboard_on_this_day', 'wp_dashboard_on_this_day_postbox_classes' );
23+
24+
wp_add_dashboard_widget(
25+
'wp_dashboard_on_this_day',
26+
__( 'On This Day' ),
27+
'wp_dashboard_on_this_day'
28+
);
29+
}
30+
31+
/**
32+
* Hides the On This Day postbox when there are no posts to show.
33+
*
34+
* Adds the core `hidden` class so the widget stays registered — preserving its
35+
* Screen Options entry and user-customized position — while being hidden when
36+
* empty. A user can still reveal it via Screen Options, in which case the
37+
* placeholder message is shown.
38+
*
39+
* @since 7.1.0
40+
*
41+
* @param string[] $classes An array of postbox classes.
42+
* @return string[] Filtered postbox classes.
43+
*/
44+
function wp_dashboard_on_this_day_postbox_classes( $classes ) {
45+
if ( empty( wp_dashboard_on_this_day_get_posts() ) ) {
46+
$classes[] = 'hidden';
47+
}
48+
49+
return $classes;
50+
}
51+
52+
/**
53+
* Renders the On This Day dashboard widget.
54+
*
55+
* Outputs the matching posts grouped by publication year, newest year first.
56+
*
57+
* @since 7.1.0
58+
*/
59+
function wp_dashboard_on_this_day() {
60+
$posts = wp_dashboard_on_this_day_get_posts();
61+
62+
if ( empty( $posts ) ) {
63+
// Placeholder shown when a user reveals the hidden widget via Screen
64+
// Options on a day with no matching posts.
65+
echo '<p>' . esc_html__( 'No posts were published on this day in previous years.' ) . '</p>';
66+
return;
67+
}
68+
69+
$posts_by_year = array();
70+
$post_count = count( $posts );
71+
72+
foreach ( $posts as $post ) {
73+
$year = get_the_date( 'Y', $post );
74+
75+
if ( ! isset( $posts_by_year[ $year ] ) ) {
76+
$posts_by_year[ $year ] = array();
77+
}
78+
79+
$posts_by_year[ $year ][] = $post;
80+
}
81+
82+
/* translators: Date format for the On This Day widget date, without year. See https://www.php.net/manual/datetime.format.php */
83+
$date = '<strong>' . esc_html( wp_date( _x( 'F jS', 'on this day date format' ) ) ) . '</strong>';
84+
?>
85+
<div class="wp-on-this-day-widget">
86+
<p>
87+
<?php
88+
if ( 1 === $post_count ) {
89+
printf(
90+
/* translators: %s: Date, without year. */
91+
esc_html__( 'One post has been published on %s:' ),
92+
$date // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Date is escaped above.
93+
);
94+
} else {
95+
printf(
96+
esc_html(
97+
/* translators: 1: Number of posts, 2: Date, without year. */
98+
_n(
99+
'%1$s post has been published on %2$s:',
100+
'%1$s posts have been published on %2$s:',
101+
$post_count
102+
)
103+
),
104+
esc_html( number_format_i18n( $post_count ) ),
105+
$date // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Date is escaped above.
106+
);
107+
}
108+
?>
109+
</p>
110+
<ul>
111+
<?php foreach ( $posts_by_year as $year => $year_posts ) : ?>
112+
<li>
113+
<h3><?php echo esc_html( $year ); ?></h3>
114+
<ul>
115+
<?php foreach ( $year_posts as $year_post ) : ?>
116+
<?php
117+
$title = get_the_title( $year_post );
118+
119+
if ( '' === trim( $title ) ) {
120+
$title = __( '(no title)' );
121+
}
122+
123+
$author_id = (int) $year_post->post_author;
124+
$author_name = $author_id > 0 ? (string) get_the_author_meta( 'display_name', $author_id ) : '';
125+
$show_author = '' !== trim( $author_name ) && get_current_user_id() !== $author_id;
126+
?>
127+
<li>
128+
<a href="<?php echo esc_url( get_permalink( $year_post ) ); ?>"><?php echo esc_html( $title ); ?></a>
129+
<?php if ( $show_author ) : ?>
130+
<?php
131+
echo '<span class="wp-on-this-day-post-author">' . esc_html(
132+
sprintf(
133+
/* translators: %s: Post author's display name. */
134+
__( 'by %s' ),
135+
$author_name
136+
)
137+
) . '</span>';
138+
?>
139+
<?php endif; ?>
140+
</li>
141+
<?php endforeach; ?>
142+
</ul>
143+
</li>
144+
<?php endforeach; ?>
145+
</ul>
146+
</div>
147+
<?php
148+
}
149+
150+
/**
151+
* Retrieves published posts from all authors that were published on this
152+
* calendar day in previous years.
153+
*
154+
* The date constraint matches today's month and day, combined with a
155+
* `before` clause anchored to January 1 of the current year. Up to ten posts
156+
* are returned; use the `wp_dashboard_on_this_day_query_args` filter to change
157+
* the limit. Results are cached by WP_Query's native query caching.
158+
*
159+
* @since 7.1.0
160+
*
161+
* @return WP_Post[] Array of posts ordered by newest first.
162+
*/
163+
function wp_dashboard_on_this_day_get_posts() {
164+
$today = current_datetime();
165+
$year = (int) $today->format( 'Y' );
166+
$date_query = array(
167+
'relation' => 'AND',
168+
array(
169+
'before' => array( 'year' => $year ),
170+
),
171+
_wp_dashboard_on_this_day_date_query_clause( $today ),
172+
);
173+
174+
$args = array(
175+
'post_type' => 'post',
176+
'post_status' => array( 'publish' ),
177+
'posts_per_page' => 10,
178+
'ignore_sticky_posts' => true,
179+
'orderby' => 'date',
180+
'order' => 'DESC',
181+
'no_found_rows' => true,
182+
'update_post_term_cache' => false,
183+
'update_post_meta_cache' => false,
184+
'date_query' => $date_query,
185+
);
186+
187+
/**
188+
* Filters the arguments used to query posts for the On This Day dashboard widget.
189+
*
190+
* @since 7.1.0
191+
*
192+
* @param array $args WP_Query arguments.
193+
*/
194+
$args = apply_filters( 'wp_dashboard_on_this_day_query_args', $args );
195+
196+
$query = new WP_Query( $args );
197+
198+
return $query->posts;
199+
}
200+
201+
/**
202+
* Builds the date query clause for today's anniversary date.
203+
*
204+
* On February 28 in a non-leap year, February 29 posts are included so
205+
* leap-day anniversaries still appear.
206+
*
207+
* @since 7.1.0
208+
* @access private
209+
*
210+
* @param DateTimeInterface $date Date to build the clause for.
211+
* @return array Date query clause.
212+
*/
213+
function _wp_dashboard_on_this_day_date_query_clause( $date ) {
214+
$month = (int) $date->format( 'm' );
215+
$day = (int) $date->format( 'd' );
216+
$clause = array(
217+
'month' => $month,
218+
'day' => $day,
219+
);
220+
221+
// Display leap day posts on Feb 28 in non leap years.
222+
if (
223+
28 === $day
224+
&& 2 === $month
225+
&& false === (bool) $date->format( 'L' )
226+
) {
227+
$clause = array(
228+
'relation' => 'OR',
229+
$clause,
230+
array(
231+
'month' => 2,
232+
'day' => 29,
233+
),
234+
);
235+
}
236+
237+
return $clause;
238+
}

src/wp-admin/includes/dashboard.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ function wp_dashboard_setup() {
8888
wp_add_dashboard_widget( 'dashboard_quick_press', $quick_draft_title, 'wp_dashboard_quick_press' );
8989
}
9090

91+
// On This Day.
92+
if ( ! function_exists( 'wp_dashboard_on_this_day_setup' ) ) {
93+
require_once ABSPATH . 'wp-admin/includes/dashboard-on-this-day.php';
94+
}
95+
96+
wp_dashboard_on_this_day_setup();
97+
9198
// WordPress Events and News.
9299
wp_add_dashboard_widget( 'dashboard_primary', __( 'WordPress Events and News' ), 'wp_dashboard_events_news' );
93100

0 commit comments

Comments
 (0)