WordPress.org

Make WordPress Core

Changeset 50717


Ignore:
Timestamp:
04/14/2021 11:22:07 PM (2 months ago)
Author:
desrosj
Message:

REST API: Allow authors to read their own password protected posts.

Allow authenticated users to read the contents of password protected posts if they have the edit_post meta capability for the post.

Props xknown, zieladam, peterwilsoncc, swissspidy, timothyblynjacobs.

Location:
trunk
Files:
2 edited

Legend:

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

    r50505 r50717  
    3131     */
    3232    protected $meta;
     33
     34    /**
     35     * Passwordless post access permitted.
     36     *
     37     * @since 5.7.1
     38     * @var int[]
     39     */
     40    protected $password_check_passed = array();
    3341
    3442    /**
     
    150158
    151159    /**
     160     * Override the result of the post password check for REST requested posts.
     161     *
     162     * Allow users to read the content of password protected posts if they have
     163     * previously passed a permission check or if they have the `edit_post` capability
     164     * for the post being checked.
     165     *
     166     * @since 5.7.1
     167     *
     168     * @param bool    $required Whether the post requires a password check.
     169     * @param WP_Post $post     The post been password checked.
     170     * @return bool Result of password check taking in to account REST API considerations.
     171     */
     172    public function check_password_required( $required, $post ) {
     173        if ( ! $required ) {
     174            return $required;
     175        }
     176
     177        $post = get_post( $post );
     178
     179        if ( ! $post ) {
     180            return $required;
     181        }
     182
     183        if ( ! empty( $this->password_check_passed[ $post->ID ] ) ) {
     184            // Password previously checked and approved.
     185            return false;
     186        }
     187
     188        return ! current_user_can( 'edit_post', $post->ID );
     189    }
     190
     191    /**
    152192     * Retrieves a collection of posts.
    153193     *
     
    315355        // Allow access to all password protected posts if the context is edit.
    316356        if ( 'edit' === $request['context'] ) {
    317             add_filter( 'post_password_required', '__return_false' );
     357            add_filter( 'post_password_required', array( $this, 'check_password_required' ), 10, 2 );
    318358        }
    319359
     
    331371        // Reset filter.
    332372        if ( 'edit' === $request['context'] ) {
    333             remove_filter( 'post_password_required', '__return_false' );
     373            remove_filter( 'post_password_required', array( $this, 'check_password_required' ) );
    334374        }
    335375
     
    446486        // Allow access to all password protected posts if the context is edit.
    447487        if ( 'edit' === $request['context'] ) {
    448             add_filter( 'post_password_required', '__return_false' );
     488            add_filter( 'post_password_required', array( $this, 'check_password_required' ), 10, 2 );
    449489        }
    450490
     
    474514        }
    475515
    476         // Edit context always gets access to password-protected posts.
    477         if ( 'edit' === $request['context'] ) {
     516        /*
     517         * Users always gets access to password protected content in the edit
     518         * context if they have the `edit_post` meta capability.
     519         */
     520        if (
     521            'edit' === $request['context'] &&
     522            current_user_can( 'edit_post', $post->ID )
     523        ) {
    478524            return true;
    479525        }
     
    17291775
    17301776        if ( $this->can_access_password_content( $post, $request ) ) {
     1777            $this->password_check_passed[ $post->ID ] = true;
    17311778            // Allow access to the post, permissions already checked before.
    1732             add_filter( 'post_password_required', '__return_false' );
     1779            add_filter( 'post_password_required', array( $this, 'check_password_required' ), 10, 2 );
    17331780
    17341781            $has_password_filter = true;
     
    17681815        if ( $has_password_filter ) {
    17691816            // Reset filter.
    1770             remove_filter( 'post_password_required', '__return_false' );
     1817            remove_filter( 'post_password_required', array( $this, 'check_password_required' ) );
    17711818        }
    17721819
  • trunk/tests/phpunit/tests/rest-api/rest-posts-controller.php

    r50463 r50717  
    18191819
    18201820        $this->assertErrorResponse( 'rest_forbidden', $response, 401 );
     1821    }
     1822
     1823    public function test_get_post_draft_edit_context() {
     1824        $post_content = 'Hello World!';
     1825        $this->factory->post->create(
     1826            array(
     1827                'post_title'    => 'Hola',
     1828                'post_password' => 'password',
     1829                'post_content'  => $post_content,
     1830                'post_excerpt'  => $post_content,
     1831                'post_author'   => self::$editor_id,
     1832            )
     1833        );
     1834        $draft_id = $this->factory->post->create(
     1835            array(
     1836                'post_status'  => 'draft',
     1837                'post_author'  => self::$contributor_id,
     1838                'post_content' => '<!-- wp:latest-posts {"displayPostContent":true} /--> <!-- wp:latest-posts {"displayPostContent":true,"displayPostContentRadio":"full_post"} /-->',
     1839            )
     1840        );
     1841        wp_set_current_user( self::$contributor_id );
     1842        $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $draft_id ) );
     1843        $request->set_param( 'context', 'edit' );
     1844        $response = rest_get_server()->dispatch( $request );
     1845        $data     = $response->get_data();
     1846        $this->assertNotContains( $post_content, $data['content']['rendered'] );
    18211847    }
    18221848
Note: See TracChangeset for help on using the changeset viewer.