Make WordPress Core

Changeset 61996


Ignore:
Timestamp:
03/12/2026 08:47:58 PM (2 weeks ago)
Author:
johnjamesjacoby
Message:

REST API: Prevent inaccessible attachments from being embedded in posts.

When an attachment is used by multiple posts, it could be included in _embed for a published post even if its post_parent is a draft.

This commit avoids embedding attachments that are not viewable in this context.

Props bor0.

Fixes #64183.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

    r61773 r61996  
    22952295        // If we have a featured media, add that.
    22962296        $featured_media = get_post_thumbnail_id( $post->ID );
    2297         if ( $featured_media ) {
     2297        if ( $featured_media && ( 'publish' === get_post_status( $featured_media ) || current_user_can( 'read_post', $featured_media ) ) ) {
    22982298            $image_url = rest_url( rest_get_route_for_post( $featured_media ) );
    22992299
  • trunk/tests/phpunit/tests/rest-api/rest-posts-controller.php

    r61269 r61996  
    33293329        $this->assertSame( 0, $data['featured_media'] );
    33303330        $this->assertSame( 0, (int) get_post_thumbnail_id( $new_post->ID ) );
     3331    }
     3332
     3333    /**
     3334     * Data provider for featured media link permission tests.
     3335     *
     3336     * @return array
     3337     */
     3338    public function data_featured_media_link_permissions() {
     3339        return array(
     3340            'unauthenticated user with draft parent attachment' => array(
     3341                'attachment_parent_status' => 'draft',
     3342                'attachment_status'        => 'inherit',
     3343                'user_id'                  => 0,
     3344                'expect_link'              => false,
     3345            ),
     3346            'authenticated editor with draft parent attachment' => array(
     3347                'attachment_parent_status' => 'draft',
     3348                'attachment_status'        => 'inherit',
     3349                'user_id'                  => 'editor',
     3350                'expect_link'              => true,
     3351            ),
     3352            'unauthenticated user with published attachment' => array(
     3353                'attachment_parent_status' => null,
     3354                'attachment_status'        => 'publish',
     3355                'user_id'                  => 0,
     3356                'expect_link'              => true,
     3357            ),
     3358        );
     3359    }
     3360
     3361    /**
     3362     * Tests that featured media links respect attachment permissions.
     3363     *
     3364     * @ticket 64183
     3365     * @dataProvider data_featured_media_link_permissions
     3366     *
     3367     * @param string|null $attachment_parent_status Status of the attachment's parent post, or null for no parent.
     3368     * @param string      $attachment_status Status to set on the attachment.
     3369     * @param int|string  $user_id User ID (0 for unauthenticated) or 'editor' for editor role.
     3370     * @param bool        $expect_link Whether the featured media link should be included.
     3371     */
     3372    public function test_get_item_featured_media_link_permissions( $attachment_parent_status, $attachment_status, $user_id, $expect_link ) {
     3373        $file = DIR_TESTDATA . '/images/canola.jpg';
     3374
     3375        // Create attachment parent if needed.
     3376        $parent_post_id = 0;
     3377        if ( null !== $attachment_parent_status ) {
     3378            $parent_post_id = self::factory()->post->create(
     3379                array(
     3380                    'post_title'  => 'Parent Post',
     3381                    'post_status' => $attachment_parent_status,
     3382                )
     3383            );
     3384        }
     3385
     3386        // Create attachment.
     3387        $attachment_id = self::factory()->attachment->create_object(
     3388            $file,
     3389            $parent_post_id,
     3390            array(
     3391                'post_mime_type' => 'image/jpeg',
     3392            )
     3393        );
     3394
     3395        // Set attachment status if different from default.
     3396        if ( 'publish' === $attachment_status ) {
     3397            wp_update_post(
     3398                array(
     3399                    'ID'          => $attachment_id,
     3400                    'post_status' => 'publish',
     3401                )
     3402            );
     3403        }
     3404
     3405        // Create published post with featured media.
     3406        $published_post_id = self::factory()->post->create(
     3407            array(
     3408                'post_title'  => 'Published Post',
     3409                'post_status' => 'publish',
     3410            )
     3411        );
     3412        set_post_thumbnail( $published_post_id, $attachment_id );
     3413
     3414        // Set current user.
     3415        if ( 'editor' === $user_id ) {
     3416            wp_set_current_user( self::$editor_id );
     3417        } else {
     3418            wp_set_current_user( $user_id );
     3419        }
     3420
     3421        // Make request.
     3422        $request  = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $published_post_id ) );
     3423        $response = rest_get_server()->dispatch( $request );
     3424        $links    = $response->get_links();
     3425
     3426        // Assert link presence based on expectation.
     3427        if ( $expect_link ) {
     3428            $this->assertArrayHasKey( 'https://api.w.org/featuredmedia', $links );
     3429            $this->assertSame(
     3430                rest_url( '/wp/v2/media/' . $attachment_id ),
     3431                $links['https://api.w.org/featuredmedia'][0]['href']
     3432            );
     3433        } else {
     3434            $this->assertArrayNotHasKey( 'https://api.w.org/featuredmedia', $links );
     3435        }
    33313436    }
    33323437
Note: See TracChangeset for help on using the changeset viewer.