Skip to content

Commit cf5cbec

Browse files
authored
Merge branch 'WordPress:trunk' into trunk
2 parents ef709be + 35e63f8 commit cf5cbec

4 files changed

Lines changed: 210 additions & 34 deletions

File tree

src/wp-admin/includes/class-wp-posts-list-table.php

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,38 @@ public function column_title( $post ) {
11741174
echo '<div class="locked-info"><span class="locked-avatar">' . $locked_avatar . '</span> <span class="locked-text">' . $locked_text . "</span></div>\n";
11751175
}
11761176

1177-
$pad = str_repeat( '&#8212; ', $this->current_level );
1177+
$pad = str_repeat(
1178+
'<span aria-hidden="true">&#8212;</span> ',
1179+
$this->current_level
1180+
);
1181+
$described_by_attr = '';
1182+
$hierarchy_linked = '';
1183+
$hierarchy_nolink = '';
1184+
1185+
if ( $post->post_parent ) {
1186+
$parent = get_post( $post->post_parent );
1187+
1188+
if ( $parent ) {
1189+
/** This filter is documented in wp-includes/post-template.php */
1190+
$parent_title = apply_filters( 'the_title', $parent->post_title, $parent->ID );
1191+
1192+
$hierarchy_id = 'post-hierarchy-' . $post->ID;
1193+
$described_by_attr = sprintf( ' aria-describedby="%s"', esc_attr( $hierarchy_id ) );
1194+
$hierarchy_linked = sprintf(
1195+
'<span id="%1$s" class="hidden">%2$s</span>',
1196+
esc_attr( $hierarchy_id ),
1197+
/* translators: %s: Parent post title. */
1198+
esc_html( sprintf( __( 'Child of %s' ), wp_strip_all_tags( $parent_title ) ) )
1199+
);
1200+
$hierarchy_nolink = sprintf(
1201+
'<span id="%1$s" class="screen-reader-text"> (%2$s)</span>',
1202+
esc_attr( $hierarchy_id ),
1203+
/* translators: %s: Parent post title. */
1204+
esc_html( sprintf( __( 'Child of %s' ), wp_strip_all_tags( $parent_title ) ) )
1205+
);
1206+
}
1207+
}
1208+
11781209
echo '<strong>';
11791210

11801211
$title = _draft_or_post_title();
@@ -1187,16 +1218,19 @@ public function column_title( $post ) {
11871218

11881219
if ( $can_edit_post && 'trash' !== $post->post_status ) {
11891220
printf(
1190-
'<a class="row-title" href="%s">%s%s</a>',
1191-
get_edit_post_link( $post->ID ),
1221+
'%1$s<a class="row-title" href="%2$s"%3$s>%4$s</a>%5$s',
11921222
$pad,
1193-
$title
1223+
get_edit_post_link( $post->ID ),
1224+
$described_by_attr,
1225+
$title,
1226+
$hierarchy_linked
11941227
);
11951228
} else {
11961229
printf(
1197-
'<span>%s%s</span>',
1230+
'%1$s<span>%2$s%3$s</span>',
11981231
$pad,
1199-
$title
1232+
$title,
1233+
$hierarchy_nolink
12001234
);
12011235
}
12021236
_post_states( $post );

src/wp-includes/functions.php

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3639,24 +3639,29 @@ function wp_get_ext_types() {
36393639
* Wrapper for PHP filesize with filters and casting the result as an integer.
36403640
*
36413641
* @since 6.0.0
3642+
* @since 7.1.0 The return value is now ensured to always be greater than or equal to zero.
36423643
*
36433644
* @link https://www.php.net/manual/en/function.filesize.php
36443645
*
36453646
* @param string $path Path to the file.
36463647
* @return int The size of the file in bytes, or 0 in the event of an error.
3648+
* @phpstan-return non-negative-int
36473649
*/
3648-
function wp_filesize( $path ) {
3650+
function wp_filesize( $path ): int {
36493651
/**
36503652
* Filters the result of wp_filesize() before the file_exists() PHP function is run.
36513653
*
36523654
* @since 6.0.0
3655+
* @since 7.1.0 Negative values are now ignored, being treated the same as null. Numeric values are cast to integers.
36533656
*
3654-
* @param null|int $size The unfiltered value. Returning an int from the callback bypasses the filesize call.
3657+
* @param null|int $size The unfiltered value. Returning a non-negative number from the callback bypasses the filesize call.
36553658
* @param string $path Path to the file.
36563659
*/
36573660
$size = apply_filters( 'pre_wp_filesize', null, $path );
3658-
3659-
if ( is_int( $size ) ) {
3661+
if ( is_numeric( $size ) ) {
3662+
$size = (int) $size;
3663+
}
3664+
if ( is_int( $size ) && $size >= 0 ) {
36603665
return $size;
36613666
}
36623667

@@ -3666,11 +3671,18 @@ function wp_filesize( $path ) {
36663671
* Filters the size of the file.
36673672
*
36683673
* @since 6.0.0
3674+
* @since 7.1.0 The return value is now always zero or greater. Numeric values are cast to integers.
36693675
*
36703676
* @param int $size The result of PHP filesize on the file.
36713677
* @param string $path Path to the file.
36723678
*/
3673-
return (int) apply_filters( 'wp_filesize', $size, $path );
3679+
$size = apply_filters( 'wp_filesize', $size, $path );
3680+
if ( is_numeric( $size ) ) {
3681+
$size = (int) $size;
3682+
} else {
3683+
$size = 0;
3684+
}
3685+
return max( 0, $size );
36743686
}
36753687

36763688
/**

tests/phpunit/tests/admin/wpPostsListTable.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,61 @@ public function test_grandchildren_hierarchical_pages_second_page() {
196196
);
197197
}
198198

199+
/**
200+
* @ticket 64932
201+
*
202+
* @covers WP_Posts_List_Table::display_rows
203+
* @covers WP_Posts_List_Table::set_hierarchical_display
204+
* @covers WP_Posts_List_Table::column_title
205+
*/
206+
public function test_child_page_row_title_has_hierarchy_description() {
207+
wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
208+
209+
$output = $this->get_hierarchical_page_list_output(
210+
array(
211+
self::$top[1],
212+
self::$children[1][1],
213+
)
214+
);
215+
216+
$expected = sprintf(
217+
'<span aria-hidden="true">&#8212;</span> ' .
218+
'<a class="row-title" href="%1$s" aria-describedby="post-hierarchy-%2$d">Child 1</a>' .
219+
'<span id="post-hierarchy-%2$d" class="hidden">Child of Top Level Page 1</span>',
220+
get_edit_post_link( self::$children[1][1]->ID ),
221+
self::$children[1][1]->ID
222+
);
223+
224+
$this->assertStringContainsString( $expected, $output );
225+
}
226+
227+
/**
228+
* @ticket 64932
229+
*
230+
* @covers WP_Posts_List_Table::display_rows
231+
* @covers WP_Posts_List_Table::set_hierarchical_display
232+
* @covers WP_Posts_List_Table::column_title
233+
*/
234+
public function test_top_level_page_row_title_does_not_have_hierarchy_description() {
235+
wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
236+
237+
$output = $this->get_hierarchical_page_list_output(
238+
array(
239+
self::$top[1],
240+
)
241+
);
242+
243+
$this->assertStringContainsString(
244+
sprintf(
245+
'<a class="row-title" href="%s">Top Level Page 1</a>',
246+
get_edit_post_link( self::$top[1]->ID )
247+
),
248+
$output
249+
);
250+
$this->assertStringNotContainsString( 'aria-describedby="post-hierarchy-', $output );
251+
$this->assertStringNotContainsString( 'class="hidden">Child of ', $output );
252+
}
253+
199254
/**
200255
* Helper function to test the output of a page which uses `WP_Posts_List_Table`.
201256
*
@@ -245,6 +300,27 @@ protected function _test_list_hierarchical_page( array $args, array $expected_id
245300
}
246301
}
247302

303+
/**
304+
* Gets the output for a hierarchical page list table.
305+
*
306+
* @param WP_Post[] $posts Posts to display.
307+
* @return string List table rows output.
308+
*/
309+
protected function get_hierarchical_page_list_output( array $posts ) {
310+
$_REQUEST['paged'] = 1;
311+
$GLOBALS['per_page'] = 20;
312+
313+
ob_start();
314+
$this->table->set_hierarchical_display( true );
315+
$this->table->display_rows( $posts );
316+
$output = ob_get_clean();
317+
318+
unset( $_REQUEST['paged'] );
319+
unset( $GLOBALS['per_page'] );
320+
321+
return $output;
322+
}
323+
248324
/**
249325
* @ticket 37407
250326
*

tests/phpunit/tests/functions/wpFilesize.php

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,100 @@
99
*/
1010
class Tests_Functions_wpFilesize extends WP_UnitTestCase {
1111

12+
const TEST_FILE = DIR_TESTDATA . '/images/test-image-upside-down.jpg';
13+
1214
/**
1315
* @ticket 49412
1416
*/
15-
public function test_wp_filesize() {
16-
$file = DIR_TESTDATA . '/images/test-image-upside-down.jpg';
17-
18-
$this->assertSame( filesize( $file ), wp_filesize( $file ) );
17+
public function test_wp_filesize(): void {
18+
$this->assertSame( filesize( self::TEST_FILE ), wp_filesize( self::TEST_FILE ) );
1919
}
2020

2121
/**
2222
* @ticket 49412
23+
* @ticket 65670
2324
*/
24-
public function test_wp_filesize_filters() {
25-
$file = DIR_TESTDATA . '/images/test-image-upside-down.jpg';
25+
public function test_wp_filesize_filters(): void {
26+
add_filter( 'wp_filesize', static fn () => 999 );
27+
$this->assertSame( 999, wp_filesize( self::TEST_FILE ) );
2628

27-
add_filter(
28-
'wp_filesize',
29-
static function () {
30-
return 999;
31-
}
32-
);
29+
add_filter( 'wp_filesize', static fn () => '9991', 100 );
30+
$this->assertSame( 9991, wp_filesize( self::TEST_FILE ) );
3331

34-
$this->assertSame( 999, wp_filesize( $file ) );
32+
add_filter( 'pre_wp_filesize', static fn () => 111 );
33+
$this->assertSame( 111, wp_filesize( self::TEST_FILE ) );
3534

36-
add_filter(
37-
'pre_wp_filesize',
38-
static function () {
39-
return 111;
40-
}
41-
);
35+
add_filter( 'pre_wp_filesize', static fn () => '2222', 100 );
36+
$this->assertSame( 2222, wp_filesize( self::TEST_FILE ) );
4237

43-
$this->assertSame( 111, wp_filesize( $file ) );
38+
add_filter( 'pre_wp_filesize', static fn () => -100, 200 );
39+
$this->assertSame( 9991, wp_filesize( self::TEST_FILE ) );
4440
}
4541

4642
/**
4743
* @ticket 49412
4844
*/
49-
public function test_wp_filesize_with_nonexistent_file() {
50-
$file = 'nonexistent/file.jpg';
45+
public function test_wp_filesize_with_nonexistent_file(): void {
46+
$this->assertSame( 0, wp_filesize( 'nonexistent/file.jpg' ) );
47+
}
48+
49+
/**
50+
* @ticket 65670
51+
*/
52+
public function test_wp_filesize_pre_wp_filesize_filter_null(): void {
53+
add_filter( 'pre_wp_filesize', '__return_null' );
54+
55+
$this->assertSame( filesize( self::TEST_FILE ), wp_filesize( self::TEST_FILE ) );
56+
}
5157

52-
$this->assertSame( 0, wp_filesize( $file ) );
58+
/**
59+
* @ticket 65670
60+
*
61+
* @dataProvider data_wp_filesize_pre_wp_filesize_filter_negative
62+
*
63+
* @param float|int|string $value Negative value returned by the filter.
64+
*/
65+
public function test_wp_filesize_pre_wp_filesize_filter_negative( $value ): void {
66+
add_filter( 'pre_wp_filesize', static fn () => $value );
67+
68+
$this->assertSame( filesize( self::TEST_FILE ), wp_filesize( self::TEST_FILE ) );
69+
}
70+
71+
/**
72+
* Data provider.
73+
*
74+
* @return array<string, array{ 0: float|int|string }>
75+
*/
76+
public function data_wp_filesize_pre_wp_filesize_filter_negative(): array {
77+
return array(
78+
'negative int' => array( -1 ),
79+
'negative numeric string' => array( '-1' ),
80+
'negative float' => array( -1.5 ),
81+
);
82+
}
83+
84+
/**
85+
* @ticket 65670
86+
*
87+
* @dataProvider data_wp_filesize_filter_invalid_value
88+
*
89+
* @param mixed $value
90+
*/
91+
public function test_wp_filesize_wp_filesize_filter_invalid_value( $value ): void {
92+
add_filter( 'wp_filesize', static fn () => $value );
93+
$this->assertSame( 0, wp_filesize( self::TEST_FILE ) );
94+
}
95+
96+
/**
97+
* Data provider.
98+
*
99+
* @return array<string, array{ 0: mixed }>
100+
*/
101+
public function data_wp_filesize_filter_invalid_value(): array {
102+
return array(
103+
'negative' => array( -1 ),
104+
'null' => array( null ),
105+
'array' => array( array( 'bad', 'array' ) ),
106+
);
53107
}
54108
}

0 commit comments

Comments
 (0)