Skip to content

Commit 6cb82e6

Browse files
authored
Merge branch 'WordPress:trunk' into trunk
2 parents ef50673 + 8946881 commit 6cb82e6

7 files changed

Lines changed: 549 additions & 34 deletions

File tree

src/wp-includes/class-wp-query.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2825,11 +2825,11 @@ public function get_posts() {
28252825
if ( $this->is_comment_feed && ! $this->is_singular ) {
28262826
if ( $this->is_archive || $this->is_search ) {
28272827
$cjoin = "JOIN {$wpdb->posts} ON ( {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID ) $join ";
2828-
$cwhere = "WHERE comment_approved = '1' $where";
2828+
$cwhere = "WHERE comment_approved = '1' AND {$wpdb->comments}.comment_type != 'note' $where";
28292829
$cgroupby = "{$wpdb->comments}.comment_id";
28302830
} else { // Other non-singular, e.g. front.
28312831
$cjoin = "JOIN {$wpdb->posts} ON ( {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID )";
2832-
$cwhere = "WHERE ( post_status = 'publish' OR ( post_status = 'inherit' AND post_type = 'attachment' ) ) AND comment_approved = '1'";
2832+
$cwhere = "WHERE ( post_status = 'publish' OR ( post_status = 'inherit' AND post_type = 'attachment' ) ) AND comment_approved = '1' AND {$wpdb->comments}.comment_type != 'note'";
28332833
$cgroupby = '';
28342834
}
28352835

@@ -3487,7 +3487,7 @@ public function get_posts() {
34873487
$cjoin = apply_filters_ref_array( 'comment_feed_join', array( '', &$this ) );
34883488

34893489
/** This filter is documented in wp-includes/class-wp-query.php */
3490-
$cwhere = apply_filters_ref_array( 'comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );
3490+
$cwhere = apply_filters_ref_array( 'comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1' AND {$wpdb->comments}.comment_type != 'note'", &$this ) );
34913491

34923492
/** This filter is documented in wp-includes/class-wp-query.php */
34933493
$cgroupby = apply_filters_ref_array( 'comment_feed_groupby', array( '', &$this ) );

src/wp-includes/rest-api/class-wp-rest-server.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,6 +1384,20 @@ public function get_index( $request ) {
13841384

13851385
/** This filter is documented in wp-admin/includes/image.php */
13861386
$available['image_size_threshold'] = (int) apply_filters( 'big_image_size_threshold', 2560, array( 0, 0 ), '', 0 );
1387+
1388+
/** This filter is documented in wp-includes/class-wp-image-editor-imagick.php */
1389+
$available['image_strip_meta'] = (bool) apply_filters( 'image_strip_meta', true );
1390+
1391+
/*
1392+
* On the server, this filter receives the decoded image's actual bit depth.
1393+
* The client path never decodes the image on the server, so the filter is
1394+
* applied with 16 (the maximum depth the client encoder can produce) as
1395+
* both the value and the current depth. The client caps its output bit
1396+
* depth at the filtered value, so a plugin lowering it (e.g. to 8) takes
1397+
* effect on client-generated images too.
1398+
*/
1399+
/** This filter is documented in wp-includes/class-wp-image-editor-imagick.php */
1400+
$available['image_max_bit_depth'] = (int) apply_filters( 'image_max_bit_depth', 16, 16 );
13871401
}
13881402

13891403
$response = new WP_REST_Response( $available );

src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,14 +2413,23 @@ private function validate_image_dimensions( int $width, int $height, string $ima
24132413
);
24142414
}
24152415

2416-
// 'original' size: should match original attachment dimensions.
2416+
/*
2417+
* 'original' size: the full-size image that replaces the main file (see
2418+
* sideload_item()/finalize_item()). The endpoint expects any EXIF
2419+
* orientation to be applied to the image already, which can swap width
2420+
* and height, so the dimensions must match the stored dimensions or be
2421+
* their transpose.
2422+
*/
24172423
if ( 'original' === $image_size ) {
24182424
$metadata = wp_get_attachment_metadata( $attachment_id, true );
24192425
if ( is_array( $metadata ) && isset( $metadata['width'], $metadata['height'] ) ) {
24202426
$expected_width = (int) $metadata['width'];
24212427
$expected_height = (int) $metadata['height'];
24222428

2423-
if ( $width !== $expected_width || $height !== $expected_height ) {
2429+
$matches_dimensions = $width === $expected_width && $height === $expected_height;
2430+
$transposes_dimensions = $width === $expected_height && $height === $expected_width;
2431+
2432+
if ( ! $matches_dimensions && ! $transposes_dimensions ) {
24242433
return new WP_Error(
24252434
'rest_upload_dimension_mismatch',
24262435
sprintf(
@@ -2665,8 +2674,6 @@ public function sideload_item( WP_REST_Request $request ) {
26652674
$sub_size_data['file'] = wp_basename( $path );
26662675
$sub_size_data['mime_type'] = $type;
26672676
$sub_size_data['filesize'] = wp_filesize( $path );
2668-
} elseif ( 'original' === $image_size ) {
2669-
$sub_size_data['file'] = wp_basename( $path );
26702677
} elseif ( self::IMAGE_SIZE_SOURCE_ORIGINAL === $image_size ) {
26712678
/*
26722679
* Source-format original (e.g. the HEIC kept next to its JPEG
@@ -2681,8 +2688,16 @@ public function sideload_item( WP_REST_Request $request ) {
26812688
* finalize_item can store it under its dedicated meta key.
26822689
*/
26832690
$sub_size_data['file'] = wp_basename( $path );
2684-
} elseif ( 'scaled' === $image_size ) {
2685-
// Record the current attached file as the original.
2691+
} elseif ( 'scaled' === $image_size || 'original' === $image_size ) {
2692+
/*
2693+
* 'scaled' and 'original' both replace the attachment's main file
2694+
* with the supplied image and keep the file being replaced as
2695+
* `original_image`, which is the untouched upload. A 'scaled'
2696+
* image is downsized and an 'original' image has any EXIF
2697+
* orientation already applied. This is the same swap WordPress
2698+
* makes when it scales or rotates an image on upload; see
2699+
* _wp_image_meta_replace_original().
2700+
*/
26862701
$current_file = get_attached_file( $attachment_id, true );
26872702

26882703
if ( ! $current_file ) {
@@ -2695,19 +2710,19 @@ public function sideload_item( WP_REST_Request $request ) {
26952710

26962711
$sub_size_data['original_image'] = wp_basename( $current_file );
26972712

2698-
// Validate the scaled image before updating the attached file.
2713+
// Validate the supplied image before updating the attached file.
26992714
$size = wp_getimagesize( $path );
27002715
$filesize = wp_filesize( $path );
27012716

27022717
if ( ! $size || ! $filesize ) {
27032718
return new WP_Error(
27042719
'rest_sideload_invalid_image',
2705-
__( 'Unable to read the scaled image file.' ),
2720+
__( 'Unable to read the sideloaded image file.' ),
27062721
array( 'status' => 500 )
27072722
);
27082723
}
27092724

2710-
// Update the attached file to point to the scaled version.
2725+
// Update the attached file to point to the supplied image.
27112726
// This writes to _wp_attached_file meta, not _wp_attachment_metadata.
27122727
if (
27132728
get_attached_file( $attachment_id, true ) !== $path &&
@@ -2834,8 +2849,39 @@ public function finalize_item( WP_REST_Request $request ) {
28342849
continue;
28352850
}
28362851

2837-
if ( 'original' === $image_size ) {
2838-
$metadata['original_image'] = $sub_size['file'];
2852+
if ( 'original' === $image_size || 'scaled' === $image_size ) {
2853+
// Skip malformed entries so a bad payload cannot blank out the
2854+
// main file metadata.
2855+
if ( empty( $sub_size['file'] ) ) {
2856+
continue;
2857+
}
2858+
2859+
/*
2860+
* Record the supplied full-size image (from sideload_item()) as
2861+
* the main file, keeping the current attached file as
2862+
* `original_image`. A 'scaled' image is downsized and an
2863+
* 'original' image is rotated; both have any EXIF orientation
2864+
* already applied by the client.
2865+
*/
2866+
if ( ! empty( $sub_size['original_image'] ) ) {
2867+
$metadata['original_image'] = $sub_size['original_image'];
2868+
}
2869+
$metadata['width'] = $sub_size['width'] ?? 0;
2870+
$metadata['height'] = $sub_size['height'] ?? 0;
2871+
$metadata['filesize'] = $sub_size['filesize'] ?? 0;
2872+
$metadata['file'] = $sub_size['file'];
2873+
2874+
/*
2875+
* The supplied image has its orientation applied already, so
2876+
* reset the stored value (from the upload) to 1, as
2877+
* wp_create_image_subsizes() does for both its scale and rotate
2878+
* paths. Otherwise exif_orientation would still report the
2879+
* pre-rotation value and the client would rotate the image
2880+
* again on a re-fetch.
2881+
*/
2882+
if ( ! empty( $metadata['image_meta']['orientation'] ) ) {
2883+
$metadata['image_meta']['orientation'] = 1;
2884+
}
28392885
} elseif ( self::IMAGE_SIZE_SOURCE_ORIGINAL === $image_size ) {
28402886
/*
28412887
* Source-format original: stored under its own meta key so the
@@ -2855,14 +2901,6 @@ public function finalize_item( WP_REST_Request $request ) {
28552901
} elseif ( 'animated_video_poster' === $image_size ) {
28562902
// Static first-frame poster for the converted video.
28572903
$metadata['animated_video_poster'] = $sub_size['file'];
2858-
} elseif ( 'scaled' === $image_size ) {
2859-
if ( ! empty( $sub_size['original_image'] ) ) {
2860-
$metadata['original_image'] = $sub_size['original_image'];
2861-
}
2862-
$metadata['width'] = $sub_size['width'] ?? 0;
2863-
$metadata['height'] = $sub_size['height'] ?? 0;
2864-
$metadata['filesize'] = $sub_size['filesize'] ?? 0;
2865-
$metadata['file'] = $sub_size['file'] ?? '';
28662904
} else {
28672905
$metadata['sizes'] = $metadata['sizes'] ?? array();
28682906

tests/phpunit/tests/query/commentFeed.php

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
* @group feeds
77
*/
88
class Tests_Query_CommentFeed extends WP_UnitTestCase {
9-
public static $post_type = 'post';
10-
protected static $post_ids = array();
9+
public static string $post_type = 'post';
10+
11+
/**
12+
* @var int[]
13+
*/
14+
protected static array $post_ids = array();
1115

1216
public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
1317
self::$post_ids = $factory->post->create_many(
@@ -82,6 +86,96 @@ public function test_archive_comment_feed_invalid_cache() {
8286
$this->assertSame( 20, $comment_count );
8387
}
8488

89+
/**
90+
* @ticket 65613
91+
*/
92+
public function test_main_comment_feed_should_exclude_notes(): void {
93+
$note_id = self::factory()->comment->create(
94+
array(
95+
'comment_post_ID' => self::$post_ids[0],
96+
'comment_type' => 'note',
97+
'comment_approved' => '1',
98+
)
99+
);
100+
101+
$q = new WP_Query();
102+
$q->query(
103+
array(
104+
'withcomments' => 1,
105+
'feed' => 'comments-rss',
106+
)
107+
);
108+
109+
$this->assertTrue( $q->is_comment_feed() );
110+
$this->assertFalse( $q->is_singular() );
111+
112+
$comment_ids = array_map( 'intval', wp_list_pluck( $q->comments, 'comment_ID' ) );
113+
$this->assertNotContains( $note_id, $comment_ids, 'Comments feed should not include notes.' );
114+
$this->assertSame( 15, $q->comment_count, 'Comments feed should include all regular comments.' );
115+
}
116+
117+
/**
118+
* @ticket 65613
119+
*/
120+
public function test_archive_comment_feed_should_exclude_notes(): void {
121+
$note_id = self::factory()->comment->create(
122+
array(
123+
'comment_post_ID' => self::$post_ids[0],
124+
'comment_type' => 'note',
125+
'comment_approved' => '1',
126+
)
127+
);
128+
129+
$q = new WP_Query();
130+
$q->query(
131+
array(
132+
'withcomments' => 1,
133+
'feed' => 'comments-rss',
134+
'year' => (int) get_the_date( 'Y', self::$post_ids[0] ),
135+
)
136+
);
137+
138+
$this->assertTrue( $q->is_comment_feed() );
139+
$this->assertTrue( $q->is_archive() );
140+
141+
$comment_ids = array_map( 'intval', wp_list_pluck( $q->comments, 'comment_ID' ) );
142+
$this->assertNotContains( $note_id, $comment_ids, 'Archive comments feed should not include notes.' );
143+
$this->assertSame( 15, $q->comment_count, 'Archive comments feed should include all regular comments.' );
144+
}
145+
146+
/**
147+
* @ticket 65613
148+
*/
149+
public function test_single_comment_feed_should_exclude_notes(): void {
150+
$post = get_post( self::$post_ids[0] );
151+
$this->assertInstanceOf( WP_Post::class, $post );
152+
153+
$note_id = self::factory()->comment->create(
154+
array(
155+
'comment_post_ID' => $post->ID,
156+
'comment_type' => 'note',
157+
'comment_approved' => '1',
158+
)
159+
);
160+
161+
$q = new WP_Query();
162+
$q->query(
163+
array(
164+
'withcomments' => 1,
165+
'feed' => 'comments-rss',
166+
'post_type' => $post->post_type,
167+
'name' => $post->post_name,
168+
)
169+
);
170+
171+
$this->assertTrue( $q->is_comment_feed() );
172+
$this->assertTrue( $q->is_singular() );
173+
174+
$comment_ids = array_map( 'intval', wp_list_pluck( $q->comments, 'comment_ID' ) );
175+
$this->assertNotContains( $note_id, $comment_ids, 'Singular comments feed should not include notes.' );
176+
$this->assertSame( 5, $q->comment_count, 'Singular comments feed should include all regular comments.' );
177+
}
178+
85179
/**
86180
* @ticket 36904
87181
*/

0 commit comments

Comments
 (0)