diff --git a/src/wp-admin/css/dashboard.css b/src/wp-admin/css/dashboard.css index 860fe9696b873..bad19e5a82e3d 100644 --- a/src/wp-admin/css/dashboard.css +++ b/src/wp-admin/css/dashboard.css @@ -1054,6 +1054,11 @@ body #dashboard-widgets .postbox form .submit { color: #646970; } +/* Align the pagination with the widget content instead of the list table default. */ +#wp_dashboard_on_this_day .tablenav-pages { + float: none; +} + /* Browse happy box */ #dashboard-widgets #dashboard_browser_nag.postbox .inside { diff --git a/src/wp-admin/includes/dashboard-on-this-day.php b/src/wp-admin/includes/dashboard-on-this-day.php index e9557a60720c8..d88824e6e840d 100644 --- a/src/wp-admin/includes/dashboard-on-this-day.php +++ b/src/wp-admin/includes/dashboard-on-this-day.php @@ -53,11 +53,28 @@ function wp_dashboard_on_this_day_postbox_classes( $classes ) { * Renders the On This Day dashboard widget. * * Outputs the matching posts grouped by publication year, newest year first. + * Posts are paginated, with the requested page read from the + * `on-this-day-page` query argument. * * @since 7.1.0 */ function wp_dashboard_on_this_day() { - $posts = wp_dashboard_on_this_day_get_posts(); + $current_page = isset( $_GET['on-this-day-page'] ) ? max( 1, absint( $_GET['on-this-day-page'] ) ) : 1; + $query = _wp_dashboard_on_this_day_get_posts_query( + array( + 'paged' => $current_page, + ) + ); + + // A page number past the last page falls back to the first page. + if ( empty( $query->posts ) && $current_page > 1 ) { + $current_page = 1; + $query = _wp_dashboard_on_this_day_get_posts_query(); + } + + $posts = $query->posts; + $post_count = (int) $query->found_posts; + $total_pages = (int) $query->max_num_pages; if ( empty( $posts ) ) { // Placeholder shown when a user reveals the hidden widget via Screen @@ -66,19 +83,6 @@ function wp_dashboard_on_this_day() { return; } - $posts_by_year = array(); - $post_count = count( $posts ); - - foreach ( $posts as $post ) { - $year = get_the_date( 'Y', $post ); - - if ( ! isset( $posts_by_year[ $year ] ) ) { - $posts_by_year[ $year ] = array(); - } - - $posts_by_year[ $year ][] = $post; - } - /* translators: Date format for the On This Day widget date, without year. See https://www.php.net/manual/datetime.format.php */ $date = '' . esc_html( wp_date( _x( 'F jS', 'on this day date format' ) ) ) . ''; ?> @@ -107,60 +111,135 @@ function wp_dashboard_on_this_day() { } ?>

- - - + + ' . esc_html( + sprintf( + /* translators: %s: Post author's display name. */ + __( 'by %s' ), + $author_name + ) + ) . ''; + ?> + + + + + + true, + ) + ); + + return $query->posts; +} + +/** + * Retrieves the WP_Query for On This Day posts. + * + * @since 7.1.0 + * @access private + * + * @param array $query_args Additional query arguments. + * @return WP_Query Query for matching posts. + */ +function _wp_dashboard_on_this_day_get_posts_query( $query_args = array() ) { $today = current_datetime(); $year = (int) $today->format( 'Y' ); $date_query = array( @@ -187,17 +285,20 @@ function wp_dashboard_on_this_day_get_posts() { _wp_dashboard_on_this_day_date_query_clause( $today ), ); - $args = array( - 'post_type' => 'post', - 'post_status' => array( 'publish' ), - 'posts_per_page' => 10, - 'ignore_sticky_posts' => true, - 'orderby' => 'date', - 'order' => 'DESC', - 'no_found_rows' => true, - 'update_post_term_cache' => false, - 'update_post_meta_cache' => false, - 'date_query' => $date_query, + $args = array_merge( + array( + 'post_type' => 'post', + 'post_status' => array( 'publish' ), + 'posts_per_page' => 10, + 'ignore_sticky_posts' => true, + 'orderby' => 'date', + 'order' => 'DESC', + 'no_found_rows' => false, + 'update_post_term_cache' => false, + 'update_post_meta_cache' => false, + 'date_query' => $date_query, + ), + $query_args ); /** @@ -209,9 +310,7 @@ function wp_dashboard_on_this_day_get_posts() { */ $args = apply_filters( 'wp_dashboard_on_this_day_query_args', $args ); - $query = new WP_Query( $args ); - - return $query->posts; + return new WP_Query( $args ); } /** diff --git a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php index a2b1cdbfaff1f..88b5b387b7ba1 100644 --- a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php +++ b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php @@ -34,6 +34,7 @@ public static function wpTearDownAfterClass() { public function tear_down() { unset( $GLOBALS['wp_meta_boxes']['dashboard'] ); + unset( $_GET['on-this-day-page'] ); parent::tear_down(); } @@ -499,13 +500,15 @@ public function test_widget_hides_untitled_post_excerpt_for_password_protected_p } /** + * @ticket 65116 + * * @covers ::wp_dashboard_on_this_day - * @covers ::wp_dashboard_on_this_day_get_posts + * @covers ::_wp_dashboard_on_this_day_get_posts_query */ - public function test_widget_limits_posts_to_ten() { + public function test_widget_paginates_posts() { wp_set_current_user( self::$user_id ); - for ( $years_ago = 1; $years_ago <= 11; $years_ago++ ) { + for ( $years_ago = 1; $years_ago <= 22; $years_ago++ ) { $this->create_matching_post( self::$user_id, 'Anniversary post ' . $years_ago, $years_ago ); } @@ -513,10 +516,67 @@ public function test_widget_limits_posts_to_ten() { wp_dashboard_on_this_day(); $output = ob_get_clean(); - $this->assertStringContainsString( '10 posts have been published on ' . wp_date( 'F jS' ) . ':', $output ); + $this->assertStringContainsString( '22 posts have been published on ' . wp_date( 'F jS' ) . ':', $output ); $this->assertMatchesRegularExpression( '/>\s*Anniversary post 1\s*<\/a>/', $output ); $this->assertMatchesRegularExpression( '/>\s*Anniversary post 10\s*<\/a>/', $output ); $this->assertStringNotContainsString( 'Anniversary post 11', $output ); + $this->assertStringContainsString( '
assertStringContainsString( '', $output ); + $this->assertStringContainsString( 'assertStringContainsString( ' of 3', $output ); + $this->assertStringContainsString( 'class="next-page button" href="' . esc_url( admin_url( 'index.php?on-this-day-page=2#wp_dashboard_on_this_day' ) ) . '"', $output ); + } + + /** + * @ticket 65116 + * + * @covers ::wp_dashboard_on_this_day + * @covers ::_wp_dashboard_on_this_day_get_posts_query + */ + public function test_widget_displays_the_requested_page() { + wp_set_current_user( self::$user_id ); + + for ( $years_ago = 1; $years_ago <= 22; $years_ago++ ) { + $this->create_matching_post( self::$user_id, 'Anniversary post ' . $years_ago, $years_ago ); + } + + $_GET['on-this-day-page'] = 2; + + ob_start(); + wp_dashboard_on_this_day(); + $output = ob_get_clean(); + + $this->assertMatchesRegularExpression( '/>\s*Anniversary post 11\s*<\/a>/', $output ); + $this->assertMatchesRegularExpression( '/>\s*Anniversary post 20\s*<\/a>/', $output ); + $this->assertDoesNotMatchRegularExpression( '/>\s*Anniversary post 1\s*<\/a>/', $output ); + $this->assertStringNotContainsString( 'Anniversary post 21', $output ); + $this->assertStringContainsString( 'assertStringContainsString( 'class="prev-page button" href="' . esc_url( admin_url( 'index.php?on-this-day-page=1#wp_dashboard_on_this_day' ) ) . '"', $output ); + $this->assertStringContainsString( 'class="next-page button" href="' . esc_url( admin_url( 'index.php?on-this-day-page=3#wp_dashboard_on_this_day' ) ) . '"', $output ); + } + + /** + * @ticket 65116 + * + * @covers ::wp_dashboard_on_this_day + */ + public function test_widget_falls_back_to_the_first_page_for_an_out_of_range_page() { + wp_set_current_user( self::$user_id ); + + for ( $years_ago = 1; $years_ago <= 22; $years_ago++ ) { + $this->create_matching_post( self::$user_id, 'Anniversary post ' . $years_ago, $years_ago ); + } + + $_GET['on-this-day-page'] = 99; + + ob_start(); + wp_dashboard_on_this_day(); + $output = ob_get_clean(); + + $this->assertMatchesRegularExpression( '/>\s*Anniversary post 1\s*<\/a>/', $output ); + $this->assertMatchesRegularExpression( '/>\s*Anniversary post 10\s*<\/a>/', $output ); + $this->assertStringContainsString( 'assertStringNotContainsString( 'No posts were published on this day', $output ); } /**