Make WordPress Core

Ticket #43316: 43316.9.diff

File 43316.9.diff, 55.8 KB (added by azaozz, 7 years ago)
  • src/wp-includes/rest-api.php

     
    192192                if ( post_type_supports( $post_type->name, 'revisions' ) ) {
    193193                        $revisions_controller = new WP_REST_Revisions_Controller( $post_type->name );
    194194                        $revisions_controller->register_routes();
     195                        $controller = new WP_REST_Autosaves_Controller( $post_type->name );
     196                        $controller->register_routes();
    195197                }
    196198        }
    197199
  • src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php

     
     1<?php
     2/**
     3 * REST API: WP_REST_Autosaves_Controller class.
     4 *
     5 * @package WordPress
     6 * @subpackage REST_API
     7 * @since 5.0.0
     8 */
     9
     10/**
     11 * Core class used to access autosaves via the REST API.
     12 *
     13 * @since 5.0.0
     14 *
     15 * @see WP_REST_Controller
     16 */
     17class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller {
     18
     19        /**
     20         * Parent post type.
     21         *
     22         * @since 5.0.0
     23         * @var string
     24         */
     25        private $parent_post_type;
     26
     27        /**
     28         * Parent controller.
     29         *
     30         * @since 5.0.0
     31         * @var WP_REST_Controller
     32         */
     33        private $parent_controller;
     34
     35        /**
     36         * Parent controller.
     37         *
     38         * @since 5.0.0
     39         * @var WP_REST_Controller
     40         */
     41        private $revision_controller;
     42
     43        /**
     44         * The base of the parent controller's route.
     45         *
     46         * @since 5.0.0
     47         * @var string
     48         */
     49        private $parent_base;
     50
     51        /**
     52         * Constructor.
     53         *
     54         * @since 5.0.0
     55         *
     56         * @param string $parent_post_type Post type of the parent.
     57         */
     58        public function __construct( $parent_post_type ) {
     59                $this->parent_post_type    = $parent_post_type;
     60                $this->parent_controller   = new WP_REST_Posts_Controller( $parent_post_type );
     61                $this->revision_controller = new WP_REST_Revisions_Controller( $parent_post_type );
     62                $this->rest_namespace      = 'wp/v2';
     63                $this->rest_base           = 'autosaves';
     64                $post_type_object          = get_post_type_object( $parent_post_type );
     65                $this->parent_base         = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
     66        }
     67
     68        /**o
     69         * Registers routes for autosaves.
     70         *
     71         * @since 5.0.0
     72         *
     73         * @see register_rest_route()
     74         */
     75        public function register_routes() {
     76                register_rest_route(
     77                        $this->rest_namespace, '/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base, array(
     78                                'args'   => array(
     79                                        'parent' => array(
     80                                                'description' => __( 'The ID for the parent of the object.' ),
     81                                                'type'        => 'integer',
     82                                        ),
     83                                ),
     84                                array(
     85                                        'methods'             => WP_REST_Server::READABLE,
     86                                        'callback'            => array( $this, 'get_items' ),
     87                                        'permission_callback' => array( $this->revision_controller, 'get_items_permissions_check' ),
     88                                        'args'                => $this->get_collection_params(),
     89                                ),
     90                                array(
     91                                        'methods'             => WP_REST_Server::CREATABLE,
     92                                        'callback'            => array( $this, 'create_item' ),
     93                                        'permission_callback' => array( $this->parent_controller, 'create_item_permissions_check' ),
     94                                        'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
     95                                ),
     96                                'schema' => array( $this, 'get_public_item_schema' ),
     97                        )
     98                );
     99
     100                register_rest_route(
     101                        $this->rest_namespace, '/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base . '/(?P<id>[\d]+)', array(
     102                                'args'   => array(
     103                                        'parent' => array(
     104                                                'description' => __( 'The ID for the parent of the object.' ),
     105                                                'type'        => 'integer',
     106                                        ),
     107                                        'id'     => array(
     108                                                'description' => __( 'Unique identifier for the object.' ),
     109                                                'type'        => 'integer',
     110                                        ),
     111                                ),
     112                                array(
     113                                        'methods'             => WP_REST_Server::READABLE,
     114                                        'callback'            => array( $this, 'get_item' ),
     115                                        'permission_callback' => array( $this->revision_controller, 'get_item_permissions_check' ),
     116                                        'args'                => array(
     117                                                'context' => $this->get_context_param( array( 'default' => 'view' ) ),
     118                                        ),
     119                                ),
     120                                array(
     121                                        'methods'             => WP_REST_Server::DELETABLE,
     122                                        'callback'            => array( $this, 'delete_item' ),
     123                                        'permission_callback' => array( $this->revision_controller, 'delete_item_permissions_check' ),
     124                                        'args'                => array(
     125                                                'force' => array(
     126                                                        'type'        => 'boolean',
     127                                                        'default'     => false,
     128                                                        'description' => __( 'Required to be true, as autosaves do not support trashing.' ),
     129                                                ),
     130                                        ),
     131                                ),
     132                                array(
     133                                        'methods'             => WP_REST_Server::CREATABLE,
     134                                        'callback'            => array( $this, 'create_item' ),
     135                                        'permission_callback' => array( $this->parent_controller, 'create_item_permissions_check' ),
     136                                        'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
     137                                ),
     138                                'schema' => array( $this, 'get_public_item_schema' ),
     139                        )
     140                );
     141
     142        }
     143
     144        /**
     145         * Get the parent post, if the ID is valid.
     146         *
     147         * @since 4.7.2
     148         *
     149         * @param int $id Supplied ID.
     150         * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
     151         */
     152        protected function get_parent( $parent ) {
     153                return $this->revision_controller->get_parent( $parent );
     154        }
     155
     156        /**
     157         * Creates or updates an autosave.
     158         *
     159         * @since 5.0.0
     160         *
     161         * @param WP_REST_Request $request Full details about the request.
     162         * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
     163         */
     164        public function create_item( $request ) {
     165
     166                if ( ! defined( 'DOING_AUTOSAVE' ) ) {
     167                        define( 'DOING_AUTOSAVE', true );
     168                }
     169
     170                // Map new fields onto the existing post data.
     171                $parent            = $this->get_parent( $request->get_param( 'parent' ) );
     172                $prepared_post     = $this->parent_controller->prepare_item_for_database( $request );
     173                $prepared_post->ID = $parent->ID;
     174                $user_id           = get_current_user_id();
     175
     176                if ( ( 'draft' === $parent->post_status || 'auto-draft' === $parent->post_status ) && $parent->post_author == $user_id ) {
     177                        // Draft posts for the same author: autosaving updates the post and does not create a revision.
     178                        // Convert the post object to an array and add slashes, wp_update_post expects escaped array.
     179                        $autosave_id = wp_update_post( wp_slash( (array) $prepared_post ), true );
     180                } else {
     181                        // Non-draft posts: create or update the post autosave.
     182                        $autosave_id = $this->create_post_autosave( (array) $prepared_post );
     183                }
     184
     185                if ( is_wp_error( $autosave_id ) ) {
     186                        return $autosave_id;
     187                }
     188
     189                $post = get_post( $autosave_id );
     190                $request->set_param( 'context', 'edit' );
     191
     192                $response = $this->prepare_item_for_response( $post, $request );
     193                $response = rest_ensure_response( $response );
     194
     195                $response->set_status( 201 );
     196                $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->rest_namespace, $this->rest_base, $autosave_id ) ) );
     197
     198                return $response;
     199        }
     200
     201        /**
     202         * Get the autosave, if the ID is valid.
     203         *
     204         * @since 5.0.0
     205         *
     206         * @param WP_REST_Request $request Full data about the request.
     207         * @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise.
     208         */
     209        public function get_item( $request ) {
     210                $parent_id = (int) $request->get_param( 'parent' );
     211
     212                if ( $parent_id <= 0 ) {
     213                        return new WP_Error( 'rest_post_invalid_id', __( 'Invalid parent post ID.' ), array( 'status' => 404 ) );
     214                }
     215
     216                $autosave = wp_get_post_autosave( $parent_id );
     217
     218                if ( ! $autosave ) {
     219                        return new WP_Error( 'rest_post_no_autosave', __( 'There is no autosave revision for this post.' ), array( 'status' => 404 ) );
     220                }
     221
     222                $response = $this->prepare_item_for_response( $autosave, $request );
     223                return $response;
     224        }
     225
     226        /**
     227         * Gets a collection of autosaves using wp_get_post_autosave.
     228         *
     229         * Contains the user's autosave, for empty if it doesn't exist.
     230         *
     231         * @since 5.0.0
     232         *
     233         * @param WP_REST_Request $request Full data about the request.
     234         * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
     235         */
     236        public function get_items( $request ) {
     237                $parent = $this->get_parent( $request->get_param( 'parent' ) );
     238                if ( is_wp_error( $parent ) ) {
     239                        return $parent;
     240                }
     241
     242                $response  = array();
     243                $parent_id = $parent->ID;
     244                $revisions = wp_get_post_revisions( $parent_id, array( 'check_enabled' => false ) );
     245
     246                foreach ( $revisions as $revision ) {
     247                        if ( false !== strpos( $revision->post_name, "{$parent_id}-autosave" ) ) {
     248                                $data       = $this->prepare_item_for_response( $revision, $request );
     249                                $response[] = $this->prepare_response_for_collection( $data );
     250                        }
     251                }
     252
     253                return rest_ensure_response( $response );
     254        }
     255
     256
     257        /**
     258         * Retrieves the autosave's schema, conforming to JSON Schema.
     259         *
     260         * @since 5.0.0
     261         *
     262         * @return array Item schema data.
     263         */
     264        public function get_item_schema() {
     265                return $this->revision_controller->get_item_schema();
     266        }
     267
     268        /**
     269         * Creates autosave for the specified post.
     270         *
     271         * From wp-admin/post.php.
     272         *
     273         * @since 5.0.0
     274         *
     275         * @param mixed $post_data Associative array containing the post data.
     276         * @return mixed The autosave revision ID or WP_Error.
     277         */
     278        public function create_post_autosave( $post_data ) {
     279
     280                $post_id = (int) $post_data['ID'];
     281                $post    = get_post( $post_id );
     282
     283                if ( is_wp_error( $post ) ) {
     284                        return $post;
     285                }
     286
     287                $user_id = get_current_user_id();
     288
     289                // Store one autosave per author. If there is already an autosave, overwrite it.
     290                $old_autosave = wp_get_post_autosave( $post_id, $user_id );
     291
     292                if ( $old_autosave ) {
     293                        $new_autosave                = _wp_post_revision_data( $post_data, true );
     294                        $new_autosave['ID']          = $old_autosave->ID;
     295                        $new_autosave['post_author'] = $user_id;
     296
     297                        // If the new autosave has the same content as the post, delete the autosave.
     298                        $autosave_is_different = false;
     299
     300                        foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) {
     301                                if ( normalize_whitespace( $new_autosave[ $field ] ) != normalize_whitespace( $post->$field ) ) {
     302                                        $autosave_is_different = true;
     303                                        break;
     304                                }
     305                        }
     306
     307                        if ( ! $autosave_is_different ) {
     308                                wp_delete_post_revision( $old_autosave->ID );
     309                                return new WP_Error( 'rest_autosave_no_changes', __( 'There is nothing to save. The autosave and the post content are the same.' ) );
     310                        }
     311
     312                        /**
     313                         * This filter is documented in wp-admin/post.php.
     314                         */
     315                        do_action( 'wp_creating_autosave', $new_autosave );
     316
     317                        // If the autosave content is significantly different, create a revision.
     318                        $old_length = strlen( $old_autosave->post_content );
     319
     320                        if ( $old_length > 1000 ) {
     321                                $difference = 200;
     322                        } elseif ( $old_length > 500 ) {
     323                                $difference = (int) $old_length * 0.2;
     324                        } elseif ( $old_length > 50 ) {
     325                                $difference = (int) $old_length * 0.3;
     326                        } else {
     327                                $difference = (int) $old_length * 0.5;
     328                        }
     329
     330                        $autosave_sizediff = strlen( $new_autosave['content'] ) - $old_length;
     331                        $create_revision   = absint( $autosave_sizediff ) > $difference;
     332
     333                        /**
     334                         * Filter whether a revision is created when an autosave is made via the REST API.
     335                         *
     336                         * @since 5.0.0
     337                         *
     338                         * @param bool  $create_revision   Create a revision?
     339                         * @param array $post_data         The autosave post data.
     340                         * @param int   $autosave_sizediff The calculated autosave difference.
     341                         */
     342                        if ( apply_filters( 'wp_create_revision_for_api_autosave', $create_revision, $post_data, $autosave_sizediff ) ) {
     343                                _wp_put_post_revision( $post_data );
     344                        }
     345
     346                        // wp_update_post expects escaped array.
     347                        return wp_update_post( wp_slash( $new_autosave ) );
     348                }
     349
     350                // Create the new autosave as a special post revision.
     351                return _wp_put_post_revision( $post_data, true );
     352        }
     353
     354        /**
     355         * Prepares the revision for the REST response.
     356         *
     357         * @since 5.0.0
     358         *
     359         * @param WP_Post         $post    Post revision object.
     360         * @param WP_REST_Request $request Request object.
     361         *
     362         * @return WP_REST_Response Response object.
     363         */
     364        public function prepare_item_for_response( $post, $request ) {
     365                $data = array();
     366                $response = $this->revision_controller->prepare_item_for_response( $post, $request );
     367
     368                /**
     369                 * Filters a revision returned from the API.
     370                 *
     371                 * Allows modification of the revision right before it is returned.
     372                 *
     373                 * @since 5.0.0
     374                 *
     375                 * @param WP_REST_Response $response The response object.
     376                 * @param WP_Post          $post     The original revision object.
     377                 * @param WP_REST_Request  $request  Request used to generate the response.
     378                 */
     379                return apply_filters( 'rest_prepare_autosave', $response, $post, $request );
     380
     381        }
     382
     383}
  • src/wp-settings.php

    Property changes on: src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
    230230require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-post-types-controller.php' );
    231231require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-post-statuses-controller.php' );
    232232require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-revisions-controller.php' );
     233require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-autosaves-controller.php' );
    233234require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-taxonomies-controller.php' );
    234235require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.php' );
    235236require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' );
  • tests/phpunit/tests/rest-api/rest-autosaves-controller.php

     
     1<?php
     2/**
     3 * Unit tests covering WP_REST_Autosaves_Controller functionality.
     4 *
     5 * @package WordPress
     6 * @subpackage REST API
     7 */
     8
     9/**
     10 * @group restapi-autosave
     11 * @group restapi
     12 */
     13class WP_Test_REST_Autosaves_Controller extends WP_Test_REST_Controller_Testcase {
     14        protected static $post_id;
     15        protected static $page_id;
     16
     17        protected static $autosave_post_id;
     18        protected static $autosave_page_id;
     19
     20        protected static $editor_id;
     21        protected static $contributor_id;
     22
     23        protected function set_post_data( $args = array() ) {
     24                $defaults = array(
     25                        'title'   => 'Post Title',
     26                        'content' => 'Post content',
     27                        'excerpt' => 'Post excerpt',
     28                        'name'    => 'test',
     29                        'author'  => get_current_user_id(),
     30                );
     31
     32                return wp_parse_args( $args, $defaults );
     33        }
     34
     35        protected function check_create_autosave_response( $response ) {
     36                $this->assertNotInstanceOf( 'WP_Error', $response );
     37                $response = rest_ensure_response( $response );
     38
     39                $this->assertEquals( 201, $response->get_status() );
     40                $headers = $response->get_headers();
     41                $this->assertArrayHasKey( 'Location', $headers );
     42        }
     43
     44        public static function wpSetUpBeforeClass( $factory ) {
     45                self::$post_id = $factory->post->create();
     46                self::$page_id = $factory->post->create( array( 'post_type' => 'page' ) );
     47
     48                self::$editor_id      = $factory->user->create(
     49                        array(
     50                                'role' => 'editor',
     51                        )
     52                );
     53                self::$contributor_id = $factory->user->create(
     54                        array(
     55                                'role' => 'contributor',
     56                        )
     57                );
     58
     59                wp_set_current_user( self::$editor_id );
     60
     61                // Create an autosave.
     62                self::$autosave_post_id = wp_create_post_autosave(
     63                        array(
     64                                'post_content' => 'This content is better.',
     65                                'post_ID'      => self::$post_id,
     66                                'post_type'    => 'post',
     67                        )
     68                );
     69
     70                self::$autosave_page_id = wp_create_post_autosave(
     71                        array(
     72                                'post_content' => 'This content is better.',
     73                                'post_ID'      => self::$page_id,
     74                                'post_type'    => 'post',
     75                        )
     76                );
     77
     78        }
     79
     80        public static function wpTearDownAfterClass() {
     81                // Also deletes revisions.
     82                wp_delete_post( self::$post_id, true );
     83                wp_delete_post( self::$page_id, true );
     84
     85                self::delete_user( self::$editor_id );
     86                self::delete_user( self::$contributor_id );
     87        }
     88
     89        public function setUp() {
     90                parent::setUp();
     91                wp_set_current_user( self::$editor_id );
     92
     93                $this->post_autosave = wp_get_post_autosave( self::$post_id );
     94        }
     95
     96        public function test_register_routes() {
     97                $routes = rest_get_server()->get_routes();
     98                $this->assertArrayHasKey( '/wp/v2/posts/(?P<parent>[\d]+)/autosaves', $routes );
     99                $this->assertArrayHasKey( '/wp/v2/posts/(?P<parent>[\d]+)/autosaves/(?P<id>[\d]+)', $routes );
     100                $this->assertArrayHasKey( '/wp/v2/pages/(?P<parent>[\d]+)/autosaves', $routes );
     101                $this->assertArrayHasKey( '/wp/v2/pages/(?P<parent>[\d]+)/autosaves/(?P<id>[\d]+)', $routes );
     102        }
     103
     104        public function test_context_param() {
     105                // Collection
     106                $request  = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' );
     107                $response = rest_get_server()->dispatch( $request );
     108                $data     = $response->get_data();
     109                $this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] );
     110                $this->assertEqualSets( array( 'view', 'edit', 'embed' ), $data['endpoints'][0]['args']['context']['enum'] );
     111                // Single
     112                $request  = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     113                $response = rest_get_server()->dispatch( $request );
     114                $data     = $response->get_data();
     115                $this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] );
     116                $this->assertEqualSets( array( 'view', 'edit', 'embed' ), $data['endpoints'][0]['args']['context']['enum'] );   }
     117
     118        public function test_get_items() {
     119                wp_set_current_user( self::$editor_id );
     120                $request  = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves' );
     121                $response = rest_get_server()->dispatch( $request );
     122                $data     = $response->get_data();
     123                $this->assertEquals( 200, $response->get_status() );
     124                $this->assertCount( 1, $data );
     125
     126                $this->assertEquals( self::$autosave_post_id, $data[0]['id'] );
     127
     128                $this->check_get_autosave_response( $data[0], $this->post_autosave );
     129        }
     130
     131        public function test_get_items_no_permission() {
     132                wp_set_current_user( 0 );
     133                $request  = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves' );
     134                $response = rest_get_server()->dispatch( $request );
     135                $this->assertErrorResponse( 'rest_cannot_read', $response, 401 );
     136                wp_set_current_user( self::$contributor_id );
     137                $response = rest_get_server()->dispatch( $request );
     138                $this->assertErrorResponse( 'rest_cannot_read', $response, 403 );
     139        }
     140
     141        public function test_get_items_missing_parent() {
     142                wp_set_current_user( self::$editor_id );
     143                $request  = new WP_REST_Request( 'GET', '/wp/v2/posts/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/autosaves' );
     144                $response = rest_get_server()->dispatch( $request );
     145                $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 );
     146        }
     147
     148        public function test_get_items_invalid_parent_post_type() {
     149                wp_set_current_user( self::$editor_id );
     150                $request  = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$page_id . '/autosaves' );
     151                $response = rest_get_server()->dispatch( $request );
     152                $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 );
     153        }
     154
     155        public function test_get_item() {
     156                wp_set_current_user( self::$editor_id );
     157                $request  = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     158                $response = rest_get_server()->dispatch( $request );
     159                $this->assertEquals( 200, $response->get_status() );
     160                $data     = $response->get_data();
     161
     162                $this->check_get_autosave_response( $response, $this->post_autosave );
     163                $fields = array(
     164                        'author',
     165                        'date',
     166                        'date_gmt',
     167                        'modified',
     168                        'modified_gmt',
     169                        'guid',
     170                        'id',
     171                        'parent',
     172                        'slug',
     173                        'title',
     174                        'excerpt',
     175                        'content',
     176                );
     177                $this->assertEqualSets( $fields, array_keys( $data ) );
     178                $this->assertSame( self::$editor_id, $data['author'] );
     179        }
     180
     181        public function test_get_item_embed_context() {
     182                wp_set_current_user( self::$editor_id );
     183                $request  = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     184                $request->set_param( 'context', 'embed' );
     185                $response = rest_get_server()->dispatch( $request );
     186                $fields   = array(
     187                        'author',
     188                        'date',
     189                        'id',
     190                        'parent',
     191                        'slug',
     192                        'title',
     193                        'excerpt',
     194                );
     195                $data     = $response->get_data();
     196                $this->assertEqualSets( $fields, array_keys( $data ) );
     197        }
     198
     199        public function test_get_item_no_permission() {
     200                $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     201                wp_set_current_user( self::$contributor_id );
     202                $response = rest_get_server()->dispatch( $request );
     203                $this->assertErrorResponse( 'rest_cannot_read', $response, 403 );
     204        }
     205
     206        public function test_get_item_missing_parent() {
     207                wp_set_current_user( self::$editor_id );
     208                $request  = new WP_REST_Request( 'GET', '/wp/v2/posts/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/autosaves/' . self::$autosave_post_id );
     209                $response = rest_get_server()->dispatch( $request );
     210                $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 );
     211
     212        }
     213
     214        public function test_get_item_invalid_parent_post_type() {
     215                wp_set_current_user( self::$editor_id );
     216                $request  = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$page_id . '/autosaves' );
     217                $response = rest_get_server()->dispatch( $request );
     218                $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 );
     219        }
     220
     221        public function test_delete_item() {
     222                wp_set_current_user( self::$editor_id );
     223                $request = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     224                $request->set_param( 'force', true );
     225                $response = rest_get_server()->dispatch( $request );
     226                $this->assertEquals( 200, $response->get_status() );
     227                $this->assertNull( get_post( self::$autosave_post_id ) );
     228        }
     229
     230        public function test_delete_item_no_trash() {
     231                wp_set_current_user( self::$editor_id );
     232
     233                $request  = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     234                $response = rest_get_server()->dispatch( $request );
     235                $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 );
     236
     237                $request->set_param( 'force', 'false' );
     238                $response = rest_get_server()->dispatch( $request );
     239                $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 );
     240
     241                // Ensure the revision still exists
     242                $this->assertNotNull( get_post( self::$autosave_post_id ) );
     243        }
     244
     245        public function test_delete_item_no_permission() {
     246                wp_set_current_user( self::$contributor_id );
     247                $request  = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     248                $response = rest_get_server()->dispatch( $request );
     249                $this->assertErrorResponse( 'rest_cannot_read', $response, 403 );
     250        }
     251
     252        public function test_prepare_item() {
     253                wp_set_current_user( self::$editor_id );
     254                $request  = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     255                $response = rest_get_server()->dispatch( $request );
     256                $this->assertEquals( 200, $response->get_status() );
     257                $this->check_get_autosave_response( $response, $this->post_autosave );
     258        }
     259
     260        public function test_get_item_schema() {
     261                $request    = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' );
     262                $response   = rest_get_server()->dispatch( $request );
     263                $data       = $response->get_data();
     264                $properties = $data['schema']['properties'];
     265                $this->assertEquals( 12, count( $properties ) );
     266                $this->assertArrayHasKey( 'author', $properties );
     267                $this->assertArrayHasKey( 'content', $properties );
     268                $this->assertArrayHasKey( 'date', $properties );
     269                $this->assertArrayHasKey( 'date_gmt', $properties );
     270                $this->assertArrayHasKey( 'excerpt', $properties );
     271                $this->assertArrayHasKey( 'guid', $properties );
     272                $this->assertArrayHasKey( 'id', $properties );
     273                $this->assertArrayHasKey( 'modified', $properties );
     274                $this->assertArrayHasKey( 'modified_gmt', $properties );
     275                $this->assertArrayHasKey( 'parent', $properties );
     276                $this->assertArrayHasKey( 'slug', $properties );
     277                $this->assertArrayHasKey( 'title', $properties );
     278        }
     279
     280        public function test_create_item() {
     281
     282                wp_set_current_user( self::$editor_id );
     283
     284                $request  = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' );
     285                $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
     286                $params = $this->set_post_data();
     287                $request->set_body_params( $params );
     288                $response = rest_get_server()->dispatch( $request );
     289
     290                $this->check_create_autosave_response( $response );
     291        }
     292
     293        public function test_update_item() {
     294                wp_set_current_user( self::$editor_id );
     295                $request  = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     296                $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
     297                $params = $this->set_post_data();
     298                $request->set_body_params( $params );
     299                $response = rest_get_server()->dispatch( $request );
     300                $this->assertErrorResponse( 'rest_post_exists', $response, 400 );
     301        }
     302
     303        public function test_get_additional_field_registration() {
     304                $schema = array(
     305                        'type'        => 'integer',
     306                        'description' => 'Some integer of mine',
     307                        'enum'        => array( 1, 2, 3, 4 ),
     308                        'context'     => array( 'view', 'edit' ),
     309                );
     310
     311                register_rest_field(
     312                        'post-revision', 'my_custom_int', array(
     313                                'schema'          => $schema,
     314                                'get_callback'    => array( $this, 'additional_field_get_callback' ),
     315                                'update_callback' => array( $this, 'additional_field_update_callback' ),
     316                        )
     317                );
     318
     319                $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' );
     320
     321                $response = rest_get_server()->dispatch( $request );
     322                $data     = $response->get_data();
     323
     324                $this->assertArrayHasKey( 'my_custom_int', $data['schema']['properties'] );
     325                $this->assertEquals( $schema, $data['schema']['properties']['my_custom_int'] );
     326
     327                wp_set_current_user( 1 );
     328
     329                $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     330
     331                $response = rest_get_server()->dispatch( $request );
     332                $this->assertArrayHasKey( 'my_custom_int', $response->data );
     333
     334                global $wp_rest_additional_fields;
     335                $wp_rest_additional_fields = array();
     336        }
     337
     338        public function additional_field_get_callback( $object ) {
     339                return get_post_meta( $object['id'], 'my_custom_int', true );
     340        }
     341
     342        public function additional_field_update_callback( $value, $post ) {
     343                update_post_meta( $post->ID, 'my_custom_int', $value );
     344        }
     345
     346        protected function check_get_autosave_response( $response, $autosave ) {
     347                if ( $response instanceof WP_REST_Response ) {
     348                        $links    = $response->get_links();
     349                        $response = $response->get_data();
     350                } else {
     351                        $this->assertArrayHasKey( '_links', $response );
     352                        $links = $response['_links'];
     353                }
     354
     355                $this->assertEquals( $autosave->post_author, $response['author'] );
     356
     357                $rendered_content = apply_filters( 'the_content', $autosave->post_content );
     358                $this->assertEquals( $rendered_content, $response['content']['rendered'] );
     359
     360                $this->assertEquals( mysql_to_rfc3339( $autosave->post_date ), $response['date'] );
     361                $this->assertEquals( mysql_to_rfc3339( $autosave->post_date_gmt ), $response['date_gmt'] );
     362
     363                $rendered_guid = apply_filters( 'get_the_guid', $autosave->guid, $autosave->ID );
     364                $this->assertEquals( $rendered_guid, $response['guid']['rendered'] );
     365
     366                $this->assertEquals( $autosave->ID, $response['id'] );
     367                $this->assertEquals( mysql_to_rfc3339( $autosave->post_modified ), $response['modified'] );
     368                $this->assertEquals( mysql_to_rfc3339( $autosave->post_modified_gmt ), $response['modified_gmt'] );
     369                $this->assertEquals( $autosave->post_name, $response['slug'] );
     370
     371                $rendered_title = get_the_title( $autosave->ID );
     372                $this->assertEquals( $rendered_title, $response['title']['rendered'] );
     373
     374                $parent            = get_post( $autosave->post_parent );
     375                $parent_controller = new WP_REST_Posts_Controller( $parent->post_type );
     376                $parent_object     = get_post_type_object( $parent->post_type );
     377                $parent_base       = ! empty( $parent_object->rest_base ) ? $parent_object->rest_base : $parent_object->name;
     378                $this->assertEquals( rest_url( '/wp/v2/' . $parent_base . '/' . $autosave->post_parent ), $links['parent'][0]['href'] );
     379        }
     380
     381        public function test_get_item_sets_up_postdata() {
     382                wp_set_current_user( self::$editor_id );
     383                $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id );
     384                rest_get_server()->dispatch( $request );
     385
     386                $post           = get_post();
     387                $parent_post_id = wp_is_post_revision( $post->ID );
     388
     389                $this->assertEquals( $post->ID, self::$autosave_post_id );
     390                $this->assertEquals( $parent_post_id, self::$post_id );
     391        }
     392
     393}
  • tests/phpunit/tests/rest-api/rest-schema-setup.php

     
    8989                        '/wp/v2/posts/(?P<id>[\\d]+)',
    9090                        '/wp/v2/posts/(?P<parent>[\\d]+)/revisions',
    9191                        '/wp/v2/posts/(?P<parent>[\\d]+)/revisions/(?P<id>[\\d]+)',
     92                        '/wp/v2/posts/(?P<parent>[\\d]+)/autosaves',
     93                        '/wp/v2/posts/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)',
    9294                        '/wp/v2/pages',
    9395                        '/wp/v2/pages/(?P<id>[\\d]+)',
    9496                        '/wp/v2/pages/(?P<parent>[\\d]+)/revisions',
    9597                        '/wp/v2/pages/(?P<parent>[\\d]+)/revisions/(?P<id>[\\d]+)',
     98                        '/wp/v2/pages/(?P<parent>[\\d]+)/autosaves',
     99                        '/wp/v2/pages/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)',
    96100                        '/wp/v2/media',
    97101                        '/wp/v2/media/(?P<id>[\\d]+)',
    98102                        '/wp/v2/types',
     
    159163                $post_revisions   = array_values( wp_get_post_revisions( $post_id ) );
    160164                $post_revision_id = $post_revisions[ count( $post_revisions ) - 1 ]->ID;
    161165
     166                // Create an autosave.
     167                wp_create_post_autosave(
     168                        array(
     169                                'post_ID'      => $post_id,
     170                                'post_content' => 'Autosave post content.',
     171                                'post_type'    => 'post',
     172                        )
     173                );
     174
    162175                $page_id = $this->factory->post->create(
    163176                        array(
    164177                                'post_type'     => 'page',
     
    180193                $page_revisions   = array_values( wp_get_post_revisions( $page_id ) );
    181194                $page_revision_id = $page_revisions[ count( $page_revisions ) - 1 ]->ID;
    182195
     196                // Create an autosave.
     197                wp_create_post_autosave(
     198                        array(
     199                                'post_ID'      => $page_id,
     200                                'post_content' => 'Autosave page content.',
     201                                'post_type'    => 'page',
     202                        )
     203                );
     204
    183205                $tag_id = $this->factory->tag->create(
    184206                        array(
    185207                                'name'        => 'REST API Client Fixture: Tag',
     
    272294                                'name'  => 'revision',
    273295                        ),
    274296                        array(
     297                                'route' => '/wp/v2/posts/' . $post_id . '/autosaves',
     298                                'name'  => 'postAutosaves',
     299                        ),
     300                        array(
     301                                'route' => '/wp/v2/posts/' . $post_id . '/autosaves/' . $post_revision_id,
     302                                'name'  => 'autosave',
     303                        ),
     304                        array(
    275305                                'route' => '/wp/v2/pages',
    276306                                'name'  => 'PagesCollection',
    277307                        ),
     
    288318                                'name'  => 'pageRevision',
    289319                        ),
    290320                        array(
     321                                'route' => '/wp/v2/pages/' . $page_id . '/autosaves',
     322                                'name'  => 'pageAutosaves',
     323                        ),
     324                        array(
     325                                'route' => '/wp/v2/pages/' . $page_id . '/autosaves/' . $page_revision_id,
     326                                'name'  => 'pageAutosave',
     327                        ),
     328                        array(
    291329                                'route' => '/wp/v2/media',
    292330                                'name'  => 'MediaCollection',
    293331                        ),
  • tests/qunit/fixtures/wp-api-generated.js

     
    783783                }
    784784            ]
    785785        },
     786        "/wp/v2/posts/(?P<parent>[\\d]+)/autosaves": {
     787            "namespace": "wp/v2",
     788            "methods": [
     789                "GET",
     790                "POST"
     791            ],
     792            "endpoints": [
     793                {
     794                    "methods": [
     795                        "GET"
     796                    ],
     797                    "args": {
     798                        "parent": {
     799                            "required": false,
     800                            "description": "The ID for the parent of the object.",
     801                            "type": "integer"
     802                        },
     803                        "context": {
     804                            "required": false,
     805                            "default": "view",
     806                            "enum": [
     807                                "view",
     808                                "embed",
     809                                "edit"
     810                            ],
     811                            "description": "Scope under which the request is made; determines fields present in response.",
     812                            "type": "string"
     813                        }
     814                    }
     815                },
     816                {
     817                    "methods": [
     818                        "POST"
     819                    ],
     820                    "args": {
     821                        "parent": {
     822                            "required": false,
     823                            "description": "The ID for the parent of the object.",
     824                            "type": "integer"
     825                        },
     826                        "author": {
     827                            "required": false,
     828                            "description": "The ID for the author of the object.",
     829                            "type": "integer"
     830                        },
     831                        "date": {
     832                            "required": false,
     833                            "description": "The date the object was published, in the site's timezone.",
     834                            "type": "string"
     835                        },
     836                        "date_gmt": {
     837                            "required": false,
     838                            "description": "The date the object was published, as GMT.",
     839                            "type": "string"
     840                        },
     841                        "id": {
     842                            "required": false,
     843                            "description": "Unique identifier for the object.",
     844                            "type": "integer"
     845                        },
     846                        "modified": {
     847                            "required": false,
     848                            "description": "The date the object was last modified, in the site's timezone.",
     849                            "type": "string"
     850                        },
     851                        "modified_gmt": {
     852                            "required": false,
     853                            "description": "The date the object was last modified, as GMT.",
     854                            "type": "string"
     855                        },
     856                        "slug": {
     857                            "required": false,
     858                            "description": "An alphanumeric identifier for the object unique to its type.",
     859                            "type": "string"
     860                        },
     861                        "title": {
     862                            "required": false,
     863                            "description": "The title for the object.",
     864                            "type": "object"
     865                        },
     866                        "content": {
     867                            "required": false,
     868                            "description": "The content for the object.",
     869                            "type": "object"
     870                        },
     871                        "excerpt": {
     872                            "required": false,
     873                            "description": "The excerpt for the object.",
     874                            "type": "object"
     875                        }
     876                    }
     877                }
     878            ]
     879        },
     880        "/wp/v2/posts/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)": {
     881            "namespace": "wp/v2",
     882            "methods": [
     883                "GET",
     884                "DELETE",
     885                "POST"
     886            ],
     887            "endpoints": [
     888                {
     889                    "methods": [
     890                        "GET"
     891                    ],
     892                    "args": {
     893                        "parent": {
     894                            "required": false,
     895                            "description": "The ID for the parent of the object.",
     896                            "type": "integer"
     897                        },
     898                        "id": {
     899                            "required": false,
     900                            "description": "Unique identifier for the object.",
     901                            "type": "integer"
     902                        },
     903                        "context": {
     904                            "required": false,
     905                            "default": "view",
     906                            "enum": [
     907                                "view",
     908                                "embed",
     909                                "edit"
     910                            ],
     911                            "description": "Scope under which the request is made; determines fields present in response.",
     912                            "type": "string"
     913                        }
     914                    }
     915                },
     916                {
     917                    "methods": [
     918                        "DELETE"
     919                    ],
     920                    "args": {
     921                        "parent": {
     922                            "required": false,
     923                            "description": "The ID for the parent of the object.",
     924                            "type": "integer"
     925                        },
     926                        "id": {
     927                            "required": false,
     928                            "description": "Unique identifier for the object.",
     929                            "type": "integer"
     930                        },
     931                        "force": {
     932                            "required": false,
     933                            "default": false,
     934                            "description": "Required to be true, as autosaves do not support trashing.",
     935                            "type": "boolean"
     936                        }
     937                    }
     938                },
     939                {
     940                    "methods": [
     941                        "POST"
     942                    ],
     943                    "args": {
     944                        "parent": {
     945                            "required": false,
     946                            "description": "The ID for the parent of the object.",
     947                            "type": "integer"
     948                        },
     949                        "id": {
     950                            "required": false,
     951                            "description": "Unique identifier for the object.",
     952                            "type": "integer"
     953                        },
     954                        "author": {
     955                            "required": false,
     956                            "description": "The ID for the author of the object.",
     957                            "type": "integer"
     958                        },
     959                        "date": {
     960                            "required": false,
     961                            "description": "The date the object was published, in the site's timezone.",
     962                            "type": "string"
     963                        },
     964                        "date_gmt": {
     965                            "required": false,
     966                            "description": "The date the object was published, as GMT.",
     967                            "type": "string"
     968                        },
     969                        "modified": {
     970                            "required": false,
     971                            "description": "The date the object was last modified, in the site's timezone.",
     972                            "type": "string"
     973                        },
     974                        "modified_gmt": {
     975                            "required": false,
     976                            "description": "The date the object was last modified, as GMT.",
     977                            "type": "string"
     978                        },
     979                        "slug": {
     980                            "required": false,
     981                            "description": "An alphanumeric identifier for the object unique to its type.",
     982                            "type": "string"
     983                        },
     984                        "title": {
     985                            "required": false,
     986                            "description": "The title for the object.",
     987                            "type": "object"
     988                        },
     989                        "content": {
     990                            "required": false,
     991                            "description": "The content for the object.",
     992                            "type": "object"
     993                        },
     994                        "excerpt": {
     995                            "required": false,
     996                            "description": "The excerpt for the object.",
     997                            "type": "object"
     998                        }
     999                    }
     1000                }
     1001            ]
     1002        },
    7861003        "/wp/v2/pages": {
    7871004            "namespace": "wp/v2",
    7881005            "methods": [
     
    13211538                }
    13221539            ]
    13231540        },
     1541        "/wp/v2/pages/(?P<parent>[\\d]+)/autosaves": {
     1542            "namespace": "wp/v2",
     1543            "methods": [
     1544                "GET",
     1545                "POST"
     1546            ],
     1547            "endpoints": [
     1548                {
     1549                    "methods": [
     1550                        "GET"
     1551                    ],
     1552                    "args": {
     1553                        "parent": {
     1554                            "required": false,
     1555                            "description": "The ID for the parent of the object.",
     1556                            "type": "integer"
     1557                        },
     1558                        "context": {
     1559                            "required": false,
     1560                            "default": "view",
     1561                            "enum": [
     1562                                "view",
     1563                                "embed",
     1564                                "edit"
     1565                            ],
     1566                            "description": "Scope under which the request is made; determines fields present in response.",
     1567                            "type": "string"
     1568                        }
     1569                    }
     1570                },
     1571                {
     1572                    "methods": [
     1573                        "POST"
     1574                    ],
     1575                    "args": {
     1576                        "parent": {
     1577                            "required": false,
     1578                            "description": "The ID for the parent of the object.",
     1579                            "type": "integer"
     1580                        },
     1581                        "author": {
     1582                            "required": false,
     1583                            "description": "The ID for the author of the object.",
     1584                            "type": "integer"
     1585                        },
     1586                        "date": {
     1587                            "required": false,
     1588                            "description": "The date the object was published, in the site's timezone.",
     1589                            "type": "string"
     1590                        },
     1591                        "date_gmt": {
     1592                            "required": false,
     1593                            "description": "The date the object was published, as GMT.",
     1594                            "type": "string"
     1595                        },
     1596                        "id": {
     1597                            "required": false,
     1598                            "description": "Unique identifier for the object.",
     1599                            "type": "integer"
     1600                        },
     1601                        "modified": {
     1602                            "required": false,
     1603                            "description": "The date the object was last modified, in the site's timezone.",
     1604                            "type": "string"
     1605                        },
     1606                        "modified_gmt": {
     1607                            "required": false,
     1608                            "description": "The date the object was last modified, as GMT.",
     1609                            "type": "string"
     1610                        },
     1611                        "slug": {
     1612                            "required": false,
     1613                            "description": "An alphanumeric identifier for the object unique to its type.",
     1614                            "type": "string"
     1615                        },
     1616                        "title": {
     1617                            "required": false,
     1618                            "description": "The title for the object.",
     1619                            "type": "object"
     1620                        },
     1621                        "content": {
     1622                            "required": false,
     1623                            "description": "The content for the object.",
     1624                            "type": "object"
     1625                        },
     1626                        "excerpt": {
     1627                            "required": false,
     1628                            "description": "The excerpt for the object.",
     1629                            "type": "object"
     1630                        }
     1631                    }
     1632                }
     1633            ]
     1634        },
     1635        "/wp/v2/pages/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)": {
     1636            "namespace": "wp/v2",
     1637            "methods": [
     1638                "GET",
     1639                "DELETE",
     1640                "POST"
     1641            ],
     1642            "endpoints": [
     1643                {
     1644                    "methods": [
     1645                        "GET"
     1646                    ],
     1647                    "args": {
     1648                        "parent": {
     1649                            "required": false,
     1650                            "description": "The ID for the parent of the object.",
     1651                            "type": "integer"
     1652                        },
     1653                        "id": {
     1654                            "required": false,
     1655                            "description": "Unique identifier for the object.",
     1656                            "type": "integer"
     1657                        },
     1658                        "context": {
     1659                            "required": false,
     1660                            "default": "view",
     1661                            "enum": [
     1662                                "view",
     1663                                "embed",
     1664                                "edit"
     1665                            ],
     1666                            "description": "Scope under which the request is made; determines fields present in response.",
     1667                            "type": "string"
     1668                        }
     1669                    }
     1670                },
     1671                {
     1672                    "methods": [
     1673                        "DELETE"
     1674                    ],
     1675                    "args": {
     1676                        "parent": {
     1677                            "required": false,
     1678                            "description": "The ID for the parent of the object.",
     1679                            "type": "integer"
     1680                        },
     1681                        "id": {
     1682                            "required": false,
     1683                            "description": "Unique identifier for the object.",
     1684                            "type": "integer"
     1685                        },
     1686                        "force": {
     1687                            "required": false,
     1688                            "default": false,
     1689                            "description": "Required to be true, as autosaves do not support trashing.",
     1690                            "type": "boolean"
     1691                        }
     1692                    }
     1693                },
     1694                {
     1695                    "methods": [
     1696                        "POST"
     1697                    ],
     1698                    "args": {
     1699                        "parent": {
     1700                            "required": false,
     1701                            "description": "The ID for the parent of the object.",
     1702                            "type": "integer"
     1703                        },
     1704                        "id": {
     1705                            "required": false,
     1706                            "description": "Unique identifier for the object.",
     1707                            "type": "integer"
     1708                        },
     1709                        "author": {
     1710                            "required": false,
     1711                            "description": "The ID for the author of the object.",
     1712                            "type": "integer"
     1713                        },
     1714                        "date": {
     1715                            "required": false,
     1716                            "description": "The date the object was published, in the site's timezone.",
     1717                            "type": "string"
     1718                        },
     1719                        "date_gmt": {
     1720                            "required": false,
     1721                            "description": "The date the object was published, as GMT.",
     1722                            "type": "string"
     1723                        },
     1724                        "modified": {
     1725                            "required": false,
     1726                            "description": "The date the object was last modified, in the site's timezone.",
     1727                            "type": "string"
     1728                        },
     1729                        "modified_gmt": {
     1730                            "required": false,
     1731                            "description": "The date the object was last modified, as GMT.",
     1732                            "type": "string"
     1733                        },
     1734                        "slug": {
     1735                            "required": false,
     1736                            "description": "An alphanumeric identifier for the object unique to its type.",
     1737                            "type": "string"
     1738                        },
     1739                        "title": {
     1740                            "required": false,
     1741                            "description": "The title for the object.",
     1742                            "type": "object"
     1743                        },
     1744                        "content": {
     1745                            "required": false,
     1746                            "description": "The content for the object.",
     1747                            "type": "object"
     1748                        },
     1749                        "excerpt": {
     1750                            "required": false,
     1751                            "description": "The excerpt for the object.",
     1752                            "type": "object"
     1753                        }
     1754                    }
     1755                }
     1756            ]
     1757        },
    13241758        "/wp/v2/media": {
    13251759            "namespace": "wp/v2",
    13261760            "methods": [
     
    36704104            "rendered": "http://example.org/?p=4"
    36714105        },
    36724106        "title": {
     4107            "rendered": ""
     4108        },
     4109        "content": {
     4110            "rendered": "<p>Autosave post content.</p>\n"
     4111        },
     4112        "excerpt": {
     4113            "rendered": ""
     4114        },
     4115        "_links": {
     4116            "parent": [
     4117                {
     4118                    "href": "http://example.org/index.php?rest_route=/wp/v2/posts/3"
     4119                }
     4120            ]
     4121        }
     4122    },
     4123    {
     4124        "author": 2,
     4125        "date": "2017-02-14T00:00:00",
     4126        "date_gmt": "2017-02-14T00:00:00",
     4127        "id": 4,
     4128        "modified": "2017-02-14T00:00:00",
     4129        "modified_gmt": "2017-02-14T00:00:00",
     4130        "parent": 3,
     4131        "slug": "3-revision-v1",
     4132        "guid": {
     4133            "rendered": "http://example.org/?p=4"
     4134        },
     4135        "title": {
    36734136            "rendered": "REST API Client Fixture: Post"
    36744137        },
    36754138        "content": {
     
    37114174    }
    37124175};
    37134176
     4177mockedApiResponse.postAutosaves = [
     4178    {
     4179        "author": 2,
     4180        "date": "2017-02-14T00:00:00",
     4181        "date_gmt": "2017-02-14T00:00:00",
     4182        "id": 5,
     4183        "modified": "2017-02-14T00:00:00",
     4184        "modified_gmt": "2017-02-14T00:00:00",
     4185        "parent": 3,
     4186        "slug": "3-autosave-v1",
     4187        "guid": {
     4188            "rendered": "http://example.org/?p=5"
     4189        },
     4190        "title": {
     4191            "rendered": ""
     4192        },
     4193        "content": {
     4194            "rendered": "<p>Autosave post content.</p>\n"
     4195        },
     4196        "excerpt": {
     4197            "rendered": ""
     4198        },
     4199        "_links": {
     4200            "parent": [
     4201                {
     4202                    "href": "http://example.org/index.php?rest_route=/wp/v2/posts/3"
     4203                }
     4204            ]
     4205        }
     4206    }
     4207];
     4208
     4209mockedApiResponse.autosave = {
     4210    "author": 2,
     4211    "date": "2017-02-14T00:00:00",
     4212    "date_gmt": "2017-02-14T00:00:00",
     4213    "id": 5,
     4214    "modified": "2017-02-14T00:00:00",
     4215    "modified_gmt": "2017-02-14T00:00:00",
     4216    "parent": 3,
     4217    "slug": "3-autosave-v1",
     4218    "guid": {
     4219        "rendered": "http://example.org/?p=5"
     4220    },
     4221    "title": {
     4222        "rendered": ""
     4223    },
     4224    "content": {
     4225        "rendered": "<p>Autosave post content.</p>\n"
     4226    },
     4227    "excerpt": {
     4228        "rendered": ""
     4229    }
     4230};
     4231
    37144232mockedApiResponse.PagesCollection = [
    37154233    {
    37164234        "id": 5,
     
    38394357            "rendered": "http://example.org/?p=6"
    38404358        },
    38414359        "title": {
     4360            "rendered": ""
     4361        },
     4362        "content": {
     4363            "rendered": "<p>Autosave page content.</p>\n"
     4364        },
     4365        "excerpt": {
     4366            "rendered": ""
     4367        },
     4368        "_links": {
     4369            "parent": [
     4370                {
     4371                    "href": "http://example.org/index.php?rest_route=/wp/v2/pages/5"
     4372                }
     4373            ]
     4374        }
     4375    },
     4376    {
     4377        "author": 2,
     4378        "date": "2017-02-14T00:00:00",
     4379        "date_gmt": "2017-02-14T00:00:00",
     4380        "id": 7,
     4381        "modified": "2017-02-14T00:00:00",
     4382        "modified_gmt": "2017-02-14T00:00:00",
     4383        "parent": 6,
     4384        "slug": "6-revision-v1",
     4385        "guid": {
     4386            "rendered": "http://example.org/?p=7"
     4387        },
     4388        "title": {
    38424389            "rendered": "REST API Client Fixture: Page"
    38434390        },
    38444391        "content": {
     
    38504397        "_links": {
    38514398            "parent": [
    38524399                {
    3853                     "href": "http://example.org/index.php?rest_route=/wp/v2/pages/5"
     4400                    "href": "http://example.org/index.php?rest_route=/wp/v2/pages/6"
    38544401                }
    38554402            ]
    38564403        }
     
    38804427    }
    38814428};
    38824429
     4430mockedApiResponse.pageAutosaves = [
     4431    {
     4432        "author": 2,
     4433        "date": "2017-02-14T00:00:00",
     4434        "date_gmt": "2017-02-14T00:00:00",
     4435        "id": 8,
     4436        "modified": "2017-02-14T00:00:00",
     4437        "modified_gmt": "2017-02-14T00:00:00",
     4438        "parent": 6,
     4439        "slug": "6-autosave-v1",
     4440        "guid": {
     4441            "rendered": "http://example.org/?p=8"
     4442        },
     4443        "title": {
     4444            "rendered": ""
     4445        },
     4446        "content": {
     4447            "rendered": "<p>Autosave page content.</p>\n"
     4448        },
     4449        "excerpt": {
     4450            "rendered": ""
     4451        },
     4452        "_links": {
     4453            "parent": [
     4454                {
     4455                    "href": "http://example.org/index.php?rest_route=/wp/v2/pages/6"
     4456                }
     4457            ]
     4458        }
     4459    }
     4460];
     4461
     4462mockedApiResponse.pageAutosave = {
     4463    "author": 2,
     4464    "date": "2017-02-14T00:00:00",
     4465    "date_gmt": "2017-02-14T00:00:00",
     4466    "id": 8,
     4467    "modified": "2017-02-14T00:00:00",
     4468    "modified_gmt": "2017-02-14T00:00:00",
     4469    "parent": 6,
     4470    "slug": "6-autosave-v1",
     4471    "guid": {
     4472        "rendered": "http://example.org/?p=8"
     4473    },
     4474    "title": {
     4475        "rendered": ""
     4476    },
     4477    "content": {
     4478        "rendered": "<p>Autosave page content.</p>\n"
     4479    },
     4480    "excerpt": {
     4481        "rendered": ""
     4482    }
     4483};
     4484
    38834485mockedApiResponse.MediaCollection = [
    38844486    {
    38854487        "id": 7,