From 56939ff70e883ed7258086e2ae6b9268eb13bd33 Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Wed, 20 Jan 2021 04:39:24 +0000 Subject: [PATCH] Media: Ensure `get_post_status()` returns correct result for attachments. Prevent `get_post_status()` returning `false` for attachments if the parent post has been deleted. The returned attachment post status is now passed through the `get_post_status` filter. Add tests for `get_post_status()`. Props peterwilsoncc, timothyblynjacobs for review. Fixes #52326. git-svn-id: https://develop.svn.wordpress.org/trunk@49985 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/post.php | 51 +++++-- tests/phpunit/tests/post/getPostStatus.php | 167 +++++++++++++++++++++ 2 files changed, 202 insertions(+), 16 deletions(-) create mode 100644 tests/phpunit/tests/post/getPostStatus.php diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index c0372ade57..95a74b75c5 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -901,36 +901,55 @@ function get_post_status( $post = null ) { return false; } - if ( 'attachment' === $post->post_type ) { - if ( 'private' === $post->post_status ) { - return 'private'; - } + $post_status = $post->post_status; - // Unattached attachments are assumed to be published. - if ( ( 'inherit' === $post->post_status ) && ( 0 == $post->post_parent ) ) { - return 'publish'; - } + if ( + 'attachment' === $post->post_type && + 'inherit' === $post_status + ) { + // Attachment permitted statuses: 'inherit', , see wp_insert_post(). - // Inherit status from the parent. - if ( $post->post_parent && ( $post->ID != $post->post_parent ) ) { - $parent_post_status = get_post_status( $post->post_parent ); - if ( 'trash' === $parent_post_status ) { - return get_post_meta( $post->post_parent, '_wp_trash_meta_status', true ); - } else { - return $parent_post_status; + if ( + 0 === $post->post_parent || + ! get_post( $post->post_parent ) || + $post->ID === $post->post_parent + ) { + // Unattached attachments with inherit status are assumed to be published. + $post_status = 'publish'; + } elseif ( 'trash' === get_post_status( $post->post_parent ) ) { + // Get parent status prior to trashing. + $post_status = get_post_meta( $post->post_parent, '_wp_trash_meta_status', true ); + if ( ! $post_status ) { + // Assume publish as above. + $post_status = 'publish'; } + } else { + $post_status = get_post_status( $post->post_parent ); } + } elseif ( + 'attachment' === $post->post_type && + ! in_array( $post_status, array( 'private', 'trash', 'auto-draft' ), true ) + ) { + /* + * Ensure uninherited attachments have a permitted status either 'private', 'trash', 'auto-draft'. + * This is to match the logic in wp_insert_post(). + * + * Note: 'inherit' is excluded from this check as it is resolved to the parent post's + * status in the logic block above. + */ + $post_status = 'publish'; } /** * Filters the post status. * * @since 4.4.0 + * @since 5.7.0 The attachment post type is now passed through this filter. * * @param string $post_status The post status. * @param WP_Post $post The post object. */ - return apply_filters( 'get_post_status', $post->post_status, $post ); + return apply_filters( 'get_post_status', $post_status, $post ); } /** diff --git a/tests/phpunit/tests/post/getPostStatus.php b/tests/phpunit/tests/post/getPostStatus.php new file mode 100644 index 0000000000..a388df5d6d --- /dev/null +++ b/tests/phpunit/tests/post/getPostStatus.php @@ -0,0 +1,167 @@ +post->create( + array( + 'post_status' => $actual_status, + 'post_date' => $date, + 'post_name' => "$post_status-post", + ) + ); + + // Attachments without parent or media. + self::$post_ids[ "$post_status-attachment-no-parent" ] = $factory->attachment->create_object( + array( + 'post_status' => $actual_status, + 'post_name' => "$post_status-attachment-no-parent", + 'post_date' => $date, + ) + ); + + // Attachments without media. + self::$post_ids[ "$post_status-attachment" ] = $factory->attachment->create_object( + array( + 'post_parent' => self::$post_ids[ $post_status ], + 'post_status' => 'inherit', + 'post_name' => "$post_status-attachment", + 'post_date' => $date, + ) + ); + } + + // Attachment with incorrect parent ID. + self::$post_ids['badly-parented-attachment'] = $factory->attachment->create_object( + array( + 'post_parent' => PHP_INT_MAX, // Impossibly large number. + 'post_status' => 'inherit', + 'post_name' => "$post_status-attachment", + 'post_date' => $date, + ) + ); + + // Trash the trash post and attachment. + wp_trash_post( self::$post_ids['trash'] ); + wp_trash_post( self::$post_ids['trash-attachment-no-parent'] ); + + // Force delete parent and unattached post objects. + wp_delete_post( self::$post_ids['delete'], true ); + wp_delete_post( self::$post_ids['delete-attachment-no-parent'], true ); + } + + /** + * Ensure `get_post_status()` resolves correctly for posts and attachments. + * + * @ticket 52326 + * @dataProvider data_get_post_status_resolves + * + * @param string $post_key The post key in self::$post_ids. + * @param string $expected The expected get_post_status() return value. + */ + public function test_get_post_status_resolves( $post_key, $expected ) { + $this->assertSame( $expected, get_post_status( self::$post_ids[ $post_key ] ) ); + } + + /** + * Data provider for test_get_post_status_resolves(). + * + * @return array[] { + * @type string $post_key The post key in self::$post_ids. + * @type string $expected The expected get_post_status() return value. + * } + */ + public function data_get_post_status_resolves() { + return array( + array( 'publish', 'publish' ), + array( 'future', 'future' ), + array( 'draft', 'draft' ), + array( 'auto-draft', 'auto-draft' ), + array( 'trash', 'trash' ), + array( 'private', 'private' ), + array( 'delete', false ), + + // Attachment with `inherit` status from parent. + array( 'publish-attachment', 'publish' ), + array( 'future-attachment', 'future' ), + array( 'draft-attachment', 'draft' ), + array( 'auto-draft-attachment', 'auto-draft' ), + array( 'trash-attachment', 'publish' ), + array( 'private-attachment', 'private' ), + array( 'delete-attachment', 'publish' ), + + // Attachment with native status (rather than inheriting from parent). + array( 'publish-attachment-no-parent', 'publish' ), + array( 'future-attachment-no-parent', 'publish' ), // Attachments can't have future status. + array( 'draft-attachment-no-parent', 'publish' ), // Attachments can't have draft status. + array( 'auto-draft-attachment-no-parent', 'auto-draft' ), + array( 'trash-attachment-no-parent', 'trash' ), + array( 'private-attachment-no-parent', 'private' ), + array( 'delete-attachment-no-parent', false ), + + // Attachment attempting to inherit from an invalid parent number. + array( 'badly-parented-attachment', 'publish' ), + ); + } + + /** + * Ensure post status resolves after trashing parent posts. + * + * @ticket 52326 + * @dataProvider data_get_post_status_after_trashing + * + * @param string $post_to_test The post key in self::$post_ids. + * @param string $post_to_trash The post key to trash then delete in self::$post_ids. + * @param string $expected The expected result after trashing the post. + */ + public function test_get_post_status_after_trashing( $post_to_test, $post_to_trash, $expected ) { + wp_trash_post( self::$post_ids[ $post_to_trash ] ); + $this->assertSame( $expected, get_post_status( self::$post_ids[ $post_to_test ] ) ); + + // Now delete the post, expect publish. + wp_delete_post( self::$post_ids[ $post_to_trash ], true ); + $this->assertSame( 'publish', get_post_status( self::$post_ids[ $post_to_test ] ) ); + } + + /** + * Data provider for test_get_post_status_after_trashing(). + * @return array[] { + * @type string $post_to_test The post key in self::$post_ids. + * @type string $post_to_trash The post key to trash then delete in self::$post_ids. + * @type string $expected The expected result after trashing the post. + * } + */ + public function data_get_post_status_after_trashing() { + return array( + array( 'publish-attachment', 'publish', 'publish' ), + array( 'future-attachment', 'future', 'future' ), + array( 'draft-attachment', 'draft', 'draft' ), + array( 'auto-draft-attachment', 'auto-draft', 'auto-draft' ), + array( 'private-attachment', 'private', 'private' ), + array( 'delete-attachment', 'publish', 'publish' ), + ); + } +}