Embeds: Filter HTML response in oEmbed proxy controller.

Adapts the response from `WP_oEmbed_Controller::get_proxy_item()` so that the response is correctly filtered and embeds work properly in JavaSccript editors. Introduces new `get_oembed_response_data_for_url()` function for preparing internal oEmbed responses.

Merges [43810] from the 5.0 branch to trunk.

Props danielbachhuber, imath, swissspidy.
Fixes #45142.



git-svn-id: https://develop.svn.wordpress.org/trunk@44154 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Gary Pendergast 2018-12-14 03:19:48 +00:00
parent 88de9a1d7c
commit f61cfa648c
5 changed files with 374 additions and 167 deletions

View File

@ -404,9 +404,9 @@ class WP_oEmbed {
*
* @since 2.9.0
*
* @param string $data The returned oEmbed HTML.
* @param string $url URL of the content to be embedded.
* @param array $args Optional arguments, usually passed from a shortcode.
* @param string|false $data The returned oEmbed HTML (false if unsafe).
* @param string $url URL of the content to be embedded.
* @param array $args Optional arguments, usually passed from a shortcode.
*/
return apply_filters( 'oembed_result', $this->data2html( $data, $url ), $url, $args );
}

View File

@ -181,12 +181,22 @@ final class WP_oEmbed_Controller {
$args['height'] = $args['maxheight'];
}
// Short-circuit process for URLs belonging to the current site.
$data = get_oembed_response_data_for_url( $url, $args );
if ( $data ) {
return $data;
}
$data = _wp_oembed_get_object()->get_data( $url, $args );
if ( false === $data ) {
return new WP_Error( 'oembed_invalid_url', get_status_header_desc( 404 ), array( 'status' => 404 ) );
}
/** This filter is documented in wp-includes/class-oembed.php */
$data->html = apply_filters( 'oembed_result', _wp_oembed_get_object()->data2html( (object) $data, $url ), $url, $args );
/**
* Filters the oEmbed TTL value (time to live).
*

View File

@ -61,13 +61,11 @@ function wp_embed_unregister_handler( $id, $priority = 10 ) {
* @return array Default embed parameters.
*/
function wp_embed_defaults( $url = '' ) {
if ( ! empty( $GLOBALS['content_width'] ) ) {
if ( ! empty( $GLOBALS['content_width'] ) )
$width = (int) $GLOBALS['content_width'];
}
if ( empty( $width ) ) {
if ( empty( $width ) )
$width = 500;
}
$height = min( ceil( $width * 1.5 ), 1000 );
@ -76,7 +74,7 @@ function wp_embed_defaults( $url = '' ) {
*
* @since 2.9.0
*
* @param int[] $size An array of embed width and height values
* @param array $size An array of embed width and height values
* in pixels (in that order).
* @param string $url The URL that should be embedded.
*/
@ -133,8 +131,8 @@ function _wp_oembed_get_object() {
*/
function wp_oembed_add_provider( $format, $provider, $regex = false ) {
if ( did_action( 'plugins_loaded' ) ) {
$oembed = _wp_oembed_get_object();
$oembed->providers[ $format ] = array( $provider, $regex );
$oembed = _wp_oembed_get_object();
$oembed->providers[$format] = array( $provider, $regex );
} else {
WP_oEmbed::_add_provider_early( $format, $provider, $regex );
}
@ -228,7 +226,7 @@ function wp_maybe_load_embeds() {
*/
function wp_embed_handler_youtube( $matches, $attr, $url, $rawattr ) {
global $wp_embed;
$embed = $wp_embed->autoembed( sprintf( 'https://youtube.com/watch?v=%s', urlencode( $matches[2] ) ) );
$embed = $wp_embed->autoembed( sprintf( "https://youtube.com/watch?v=%s", urlencode( $matches[2] ) ) );
/**
* Filters the YoutTube embed output.
@ -397,13 +395,10 @@ function get_oembed_endpoint_url( $permalink = '', $format = 'json' ) {
$url = rest_url( 'oembed/1.0/embed' );
if ( '' !== $permalink ) {
$url = add_query_arg(
array(
'url' => urlencode( $permalink ),
'format' => ( 'json' !== $format ) ? $format : false,
),
$url
);
$url = add_query_arg( array(
'url' => urlencode( $permalink ),
'format' => ( 'json' !== $format ) ? $format : false,
), $url );
}
/**
@ -454,7 +449,7 @@ function get_post_embed_html( $width, $height, $post = null ) {
* minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
* and edit wp-embed.js directly.
*/
$output .= <<<JS
$output .=<<<JS
include "js/wp-embed.min.js"
JS;
}
@ -522,13 +517,10 @@ function get_oembed_response_data( $post, $width ) {
* @type int $max Maximum width. Default 600.
* }
*/
$min_max_width = apply_filters(
'oembed_min_max_width',
array(
'min' => 200,
'max' => 600,
)
);
$min_max_width = apply_filters( 'oembed_min_max_width', array(
'min' => 200,
'max' => 600
) );
$width = min( max( $min_max_width['min'], $width ), $min_max_width['max'] );
$height = max( ceil( $width / 16 * 9 ), 200 );
@ -563,6 +555,71 @@ function get_oembed_response_data( $post, $width ) {
return apply_filters( 'oembed_response_data', $data, $post, $width, $height );
}
/**
* Retrieves the oEmbed response data for a given URL.
*
* @since 5.0.0
*
* @param string $url The URL that should be inspected for discovery `<link>` tags.
* @param array $args oEmbed remote get arguments.
* @return object|false oEmbed response data if the URL does belong to the current site. False otherwise.
*/
function get_oembed_response_data_for_url( $url, $args ) {
$switched_blog = false;
if ( is_multisite() ) {
$url_parts = wp_parse_args( wp_parse_url( $url ), array(
'host' => '',
'path' => '/',
) );
$qv = array( 'domain' => $url_parts['host'], 'path' => '/' );
// In case of subdirectory configs, set the path.
if ( ! is_subdomain_install() ) {
$path = explode( '/', ltrim( $url_parts['path'], '/' ) );
$path = reset( $path );
if ( $path ) {
$qv['path'] = get_network()->path . $path . '/';
}
}
$sites = get_sites( $qv );
$site = reset( $sites );
if ( $site && (int) $site->blog_id !== get_current_blog_id() ) {
switch_to_blog( $site->blog_id );
$switched_blog = true;
}
}
$post_id = url_to_postid( $url );
/** This filter is documented in wp-includes/class-wp-oembed-controller.php */
$post_id = apply_filters( 'oembed_request_post_id', $post_id, $url );
if ( ! $post_id ) {
if ( $switched_blog ) {
restore_current_blog();
}
return false;
}
$width = isset( $args['width'] ) ? $args['width'] : 0;
$data = get_oembed_response_data( $post_id, $width );
if ( $switched_blog ) {
restore_current_blog();
}
return $data ? (object) $data : false;
}
/**
* Filters the oEmbed response data to return an iframe embed code.
*
@ -590,7 +647,7 @@ function get_oembed_response_data_rich( $data, $post, $width, $height ) {
if ( 'attachment' === get_post_type( $post ) ) {
if ( wp_attachment_is_image( $post ) ) {
$thumbnail_id = $post->ID;
} elseif ( wp_attachment_is( 'video', $post ) ) {
} else if ( wp_attachment_is( 'video', $post ) ) {
$thumbnail_id = get_post_thumbnail_id( $post );
$data['type'] = 'video';
}
@ -598,9 +655,9 @@ function get_oembed_response_data_rich( $data, $post, $width, $height ) {
if ( $thumbnail_id ) {
list( $thumbnail_url, $thumbnail_width, $thumbnail_height ) = wp_get_attachment_image_src( $thumbnail_id, array( $width, 99999 ) );
$data['thumbnail_url'] = $thumbnail_url;
$data['thumbnail_width'] = $thumbnail_width;
$data['thumbnail_height'] = $thumbnail_height;
$data['thumbnail_url'] = $thumbnail_url;
$data['thumbnail_width'] = $thumbnail_width;
$data['thumbnail_height'] = $thumbnail_height;
}
return $data;
@ -737,7 +794,7 @@ function wp_filter_oembed_result( $result, $data, $url ) {
$allowed_html = array(
'a' => array(
'href' => true,
'href' => true,
),
'blockquote' => array(),
'iframe' => array(
@ -767,14 +824,14 @@ function wp_filter_oembed_result( $result, $data, $url ) {
$secret = wp_generate_password( 10, false );
$url = esc_url( "{$results[2]}#?secret=$secret" );
$q = $results[1];
$q = $results[1];
$html = str_replace( $results[0], ' src=' . $q . $url . $q . ' data-secret=' . $q . $secret . $q, $html );
$html = str_replace( '<blockquote', "<blockquote data-secret=\"$secret\"", $html );
}
$allowed_html['blockquote']['data-secret'] = true;
$allowed_html['iframe']['data-secret'] = true;
$allowed_html['iframe']['data-secret'] = true;
$html = wp_kses( $html, $allowed_html );
@ -805,8 +862,7 @@ function wp_embed_excerpt_more( $more_string ) {
return $more_string;
}
$link = sprintf(
'<a href="%1$s" class="wp-embed-more" target="_top">%2$s</a>',
$link = sprintf( '<a href="%1$s" class="wp-embed-more" target="_top">%2$s</a>',
esc_url( get_permalink() ),
/* translators: %s: Name of current post */
sprintf( __( 'Continue reading %s' ), '<span class="screen-reader-text">' . get_the_title() . '</span>' )
@ -882,23 +938,23 @@ function print_embed_styles() {
?>
<style type="text/css">
<?php
if ( SCRIPT_DEBUG ) {
readfile( ABSPATH . WPINC . '/css/wp-embed-template.css' );
} else {
/*
* If you're looking at a src version of this file, you'll see an "include"
* statement below. This is used by the `grunt build` process to directly
* include a minified version of wp-oembed-embed.css, instead of using the
* readfile() method from above.
*
* If you're looking at a build version of this file, you'll see a string of
* minified CSS. If you need to debug it, please turn on SCRIPT_DEBUG
* and edit wp-embed-template.css directly.
*/
?>
include "css/wp-embed-template.min.css"
<?php
}
if ( SCRIPT_DEBUG ) {
readfile( ABSPATH . WPINC . "/css/wp-embed-template.css" );
} else {
/*
* If you're looking at a src version of this file, you'll see an "include"
* statement below. This is used by the `grunt build` process to directly
* include a minified version of wp-oembed-embed.css, instead of using the
* readfile() method from above.
*
* If you're looking at a build version of this file, you'll see a string of
* minified CSS. If you need to debug it, please turn on SCRIPT_DEBUG
* and edit wp-embed-template.css directly.
*/
?>
include "css/wp-embed-template.min.css"
<?php
}
?>
</style>
<?php
@ -913,23 +969,23 @@ function print_embed_scripts() {
?>
<script type="text/javascript">
<?php
if ( SCRIPT_DEBUG ) {
readfile( ABSPATH . WPINC . '/js/wp-embed-template.js' );
} else {
/*
* If you're looking at a src version of this file, you'll see an "include"
* statement below. This is used by the `grunt build` process to directly
* include a minified version of wp-embed-template.js, instead of using the
* readfile() method from above.
*
* If you're looking at a build version of this file, you'll see a string of
* minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
* and edit wp-embed-template.js directly.
*/
?>
include "js/wp-embed-template.min.js"
<?php
}
if ( SCRIPT_DEBUG ) {
readfile( ABSPATH . WPINC . "/js/wp-embed-template.js" );
} else {
/*
* If you're looking at a src version of this file, you'll see an "include"
* statement below. This is used by the `grunt build` process to directly
* include a minified version of wp-embed-template.js, instead of using the
* readfile() method from above.
*
* If you're looking at a build version of this file, you'll see a string of
* minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
* and edit wp-embed-template.js directly.
*/
?>
include "js/wp-embed-template.min.js"
<?php
}
?>
</script>
<?php
@ -1080,66 +1136,11 @@ function the_embed_site_title() {
* Null if the URL does not belong to the current site.
*/
function wp_filter_pre_oembed_result( $result, $url, $args ) {
$switched_blog = false;
$data = get_oembed_response_data_for_url( $url, $args );
if ( is_multisite() ) {
$url_parts = wp_parse_args(
wp_parse_url( $url ),
array(
'host' => '',
'path' => '/',
)
);
$qv = array(
'domain' => $url_parts['host'],
'path' => '/',
);
// In case of subdirectory configs, set the path.
if ( ! is_subdomain_install() ) {
$path = explode( '/', ltrim( $url_parts['path'], '/' ) );
$path = reset( $path );
if ( $path ) {
$qv['path'] = get_network()->path . $path . '/';
}
}
$sites = get_sites( $qv );
$site = reset( $sites );
if ( $site && (int) $site->blog_id !== get_current_blog_id() ) {
switch_to_blog( $site->blog_id );
$switched_blog = true;
}
if ( $data ) {
return _wp_oembed_get_object()->data2html( $data, $url );
}
$post_id = url_to_postid( $url );
/** This filter is documented in wp-includes/class-wp-oembed-controller.php */
$post_id = apply_filters( 'oembed_request_post_id', $post_id, $url );
if ( ! $post_id ) {
if ( $switched_blog ) {
restore_current_blog();
}
return $result;
}
$width = isset( $args['width'] ) ? $args['width'] : 0;
$data = get_oembed_response_data( $post_id, $width );
$data = _wp_oembed_get_object()->data2html( (object) $data, $url );
if ( $switched_blog ) {
restore_current_blog();
}
if ( ! $data ) {
return $result;
}
return $data;
return $result;
}

View File

@ -14,6 +14,7 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
protected static $subscriber;
const YOUTUBE_VIDEO_ID = 'OQSNhk5ICTI';
const INVALID_OEMBED_URL = 'https://www.notreallyanoembedprovider.com/watch?v=awesome-cat-video';
const UNTRUSTED_PROVIDER_URL = 'https://www.untrustedprovider.com';
public static function wpSetUpBeforeClass( $factory ) {
self::$subscriber = $factory->user->create(
@ -49,7 +50,10 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
do_action( 'rest_api_init', $wp_rest_server );
add_filter( 'pre_http_request', array( $this, 'mock_embed_request' ), 10, 3 );
add_filter( 'oembed_result', array( $this, 'filter_oembed_result' ), 10, 3 );
$this->request_count = 0;
$this->oembed_result_filter_count = 0;
}
public function tearDown() {
@ -59,6 +63,7 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
$wp_rest_server = null;
remove_filter( 'pre_http_request', array( $this, 'mock_embed_request' ), 10 );
remove_filter( 'oembed_result', array( $this, 'filter_oembed_result' ), 10 );
}
/**
@ -68,6 +73,13 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
*/
public $request_count = 0;
/**
* Count of the number of times the oembed_result filter was called.
*
* @var int
*/
public $oembed_result_filter_count = 0;
/**
* Intercept oEmbed requests and mock responses.
*
@ -80,7 +92,8 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
unset( $preempt, $r );
$parsed_url = wp_parse_url( $url );
parse_str( $parsed_url['query'], $query_params );
$query = isset( $parsed_url['query'] ) ? $parsed_url['query'] : '';
parse_str( $query, $query_params );
$this->request_count += 1;
// Mock request to YouTube Embed.
@ -99,20 +112,66 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
'width' => $query_params['maxwidth'],
'thumbnail_height' => $query_params['maxheight'],
'height' => $query_params['maxheight'],
'html' => '<iframe width="' . $query_params['maxwidth'] . '" height="' . $query_params['maxheight'] . '" src="https://www.youtube.com/embed/' . self::YOUTUBE_VIDEO_ID . '?feature=oembed" frameborder="0" allowfullscreen></iframe>',
'html' => '<b>Unfiltered</b><iframe width="' . $query_params['maxwidth'] . '" height="' . $query_params['maxheight'] . '" src="https://www.youtube.com/embed/' . self::YOUTUBE_VIDEO_ID . '?feature=oembed" frameborder="0" allowfullscreen></iframe>',
'author_name' => 'Yosemitebear62',
'thumbnail_url' => 'https://i.ytimg.com/vi/' . self::YOUTUBE_VIDEO_ID . '/hqdefault.jpg',
'title' => 'Yosemitebear Mountain Double Rainbow 1-8-10',
)
),
);
} else {
}
if ( $url === self::UNTRUSTED_PROVIDER_URL ) {
return array(
'response' => array(
'code' => 404,
'code' => 200,
),
'body' => '<html><head><link rel="alternate" type="application/json+oembed" href="' . self::UNTRUSTED_PROVIDER_URL . '" /></head><body></body></html>',
);
}
if ( ! empty( $query_params['url'] ) && false !== strpos( $query_params['url'], self::UNTRUSTED_PROVIDER_URL ) ) {
return array(
'response' => array(
'code' => 200,
),
'body' => wp_json_encode(
array(
'version' => '1.0',
'type' => 'rich',
'provider_name' => 'Untrusted',
'provider_url' => self::UNTRUSTED_PROVIDER_URL,
'html' => '<b>Filtered</b><a href="">Unfiltered</a>',
'author_name' => 'Untrusted Embed Author',
'title' => 'Untrusted Embed',
)
),
);
}
return array(
'response' => array(
'code' => 404,
),
);
}
/**
* Filters 'oembed_result' to ensure correct type.
*
* @param string|false $data The returned oEmbed HTML.
* @param string $url URL of the content to be embedded.
* @param array $args Optional arguments, usually passed from a shortcode.
* @return string
*/
public function filter_oembed_result( $data, $url, $args ) {
if ( ! is_string( $data ) && false !== $data ) {
$this->fail( 'Unexpected type for $data.' );
}
$this->assertInternalType( 'string', $url );
$this->assertInternalType( 'array', $args );
$this->oembed_result_filter_count++;
return $data;
}
function test_wp_oembed_ensure_format() {
@ -543,7 +602,7 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
$data = $response->get_data();
$this->assertNotEmpty( $data );
$this->assertTrue( is_object( $data ) );
$this->assertInternalType( 'object', $data );
$this->assertEquals( 'YouTube', $data->provider_name );
$this->assertEquals( 'https://i.ytimg.com/vi/' . self::YOUTUBE_VIDEO_ID . '/hqdefault.jpg', $data->thumbnail_url );
$this->assertEquals( $data->width, $request['maxwidth'] );
@ -585,4 +644,141 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
$data = $response->get_data();
$this->assertEquals( $data['code'], 'rest_invalid_param' );
}
/**
* @ticket 45142
*/
function test_proxy_with_internal_url() {
wp_set_current_user( self::$editor );
$user = self::factory()->user->create_and_get( array(
'display_name' => 'John Doe',
) );
$post = self::factory()->post->create_and_get( array(
'post_author' => $user->ID,
'post_title' => 'Hello World',
) );
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'url', get_permalink( $post->ID ) );
$request->set_param( 'maxwidth', 400 );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$data = (array) $data;
$this->assertNotEmpty( $data );
$this->assertArrayHasKey( 'version', $data );
$this->assertArrayHasKey( 'provider_name', $data );
$this->assertArrayHasKey( 'provider_url', $data );
$this->assertArrayHasKey( 'author_name', $data );
$this->assertArrayHasKey( 'author_url', $data );
$this->assertArrayHasKey( 'title', $data );
$this->assertArrayHasKey( 'type', $data );
$this->assertArrayHasKey( 'width', $data );
$this->assertEquals( '1.0', $data['version'] );
$this->assertEquals( get_bloginfo( 'name' ), $data['provider_name'] );
$this->assertEquals( get_home_url(), $data['provider_url'] );
$this->assertEquals( $user->display_name, $data['author_name'] );
$this->assertEquals( get_author_posts_url( $user->ID, $user->user_nicename ), $data['author_url'] );
$this->assertEquals( $post->post_title, $data['title'] );
$this->assertEquals( 'rich', $data['type'] );
$this->assertTrue( $data['width'] <= $request['maxwidth'] );
}
/**
* @ticket 45142
*/
function test_proxy_with_static_front_page_url() {
wp_set_current_user( self::$editor );
$post = self::factory()->post->create_and_get( array(
'post_title' => 'Front page',
'post_type' => 'page',
'post_author' => 0,
) );
update_option( 'show_on_front', 'page' );
update_option( 'page_on_front', $post->ID );
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'url', home_url() );
$request->set_param( 'maxwidth', 400 );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertInternalType( 'object', $data );
$data = (array) $data;
$this->assertNotEmpty( $data );
$this->assertArrayHasKey( 'version', $data );
$this->assertArrayHasKey( 'provider_name', $data );
$this->assertArrayHasKey( 'provider_url', $data );
$this->assertArrayHasKey( 'author_name', $data );
$this->assertArrayHasKey( 'author_url', $data );
$this->assertArrayHasKey( 'title', $data );
$this->assertArrayHasKey( 'type', $data );
$this->assertArrayHasKey( 'width', $data );
$this->assertEquals( '1.0', $data['version'] );
$this->assertEquals( get_bloginfo( 'name' ), $data['provider_name'] );
$this->assertEquals( get_home_url(), $data['provider_url'] );
$this->assertEquals( get_bloginfo( 'name' ), $data['author_name'] );
$this->assertEquals( get_home_url(), $data['author_url'] );
$this->assertEquals( $post->post_title, $data['title'] );
$this->assertEquals( 'rich', $data['type'] );
$this->assertTrue( $data['width'] <= $request['maxwidth'] );
update_option( 'show_on_front', 'posts' );
}
/**
* @ticket 45142
*/
public function test_proxy_filters_result_of_untrusted_oembed_provider() {
wp_set_current_user( self::$editor );
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'url', self::UNTRUSTED_PROVIDER_URL );
$request->set_param( 'maxwidth', 456 );
$request->set_param( 'maxheight', 789 );
$request->set_param( '_wpnonce', wp_create_nonce( 'wp_rest' ) );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 1, $this->oembed_result_filter_count );
$this->assertInternalType( 'object', $data );
$this->assertEquals( 'Untrusted', $data->provider_name );
$this->assertEquals( self::UNTRUSTED_PROVIDER_URL, $data->provider_url );
$this->assertEquals( 'rich', $data->type );
$this->assertFalse( $data->html );
}
/**
* @ticket 45142
*/
public function test_proxy_does_not_filter_result_of_trusted_oembed_provider() {
wp_set_current_user( self::$editor );
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'url', 'https://www.youtube.com/watch?v=' . self::YOUTUBE_VIDEO_ID );
$request->set_param( 'maxwidth', 456 );
$request->set_param( 'maxheight', 789 );
$request->set_param( '_wpnonce', wp_create_nonce( 'wp_rest' ) );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 1, $this->oembed_result_filter_count );
$this->assertInternalType( 'object', $data );
$this->assertStringStartsWith( '<b>Unfiltered</b>', $data->html );
}
}

View File

@ -5083,16 +5083,16 @@ mockedApiResponse.postRevisions = [
}
},
{
"author": 375,
"author": 376,
"date": "2017-02-14T00:00:00",
"date_gmt": "2017-02-14T00:00:00",
"id": 36744,
"id": 3162,
"modified": "2017-02-14T00:00:00",
"modified_gmt": "2017-02-14T00:00:00",
"parent": 36743,
"slug": "36743-revision-v1",
"parent": 3161,
"slug": "3161-revision-v1",
"guid": {
"rendered": "http://example.org/?p=36744"
"rendered": "http://example.org/?p=3162"
},
"title": {
"rendered": "REST API Client Fixture: Post"
@ -5106,7 +5106,7 @@ mockedApiResponse.postRevisions = [
"_links": {
"parent": [
{
"href": "http://example.org/index.php?rest_route=/wp/v2/posts/36743"
"href": "http://example.org/index.php?rest_route=/wp/v2/posts/3161"
}
]
}
@ -5138,16 +5138,16 @@ mockedApiResponse.revision = {
mockedApiResponse.postAutosaves = [
{
"author": 375,
"author": 376,
"date": "2017-02-14T00:00:00",
"date_gmt": "2017-02-14T00:00:00",
"id": 36745,
"id": 3163,
"modified": "2017-02-14T00:00:00",
"modified_gmt": "2017-02-14T00:00:00",
"parent": 36743,
"slug": "36743-autosave-v1",
"parent": 3161,
"slug": "3161-autosave-v1",
"guid": {
"rendered": "http://example.org/?p=36745"
"rendered": "http://example.org/?p=3163"
},
"title": {
"rendered": ""
@ -5161,7 +5161,7 @@ mockedApiResponse.postAutosaves = [
"_links": {
"parent": [
{
"href": "http://example.org/index.php?rest_route=/wp/v2/posts/36743"
"href": "http://example.org/index.php?rest_route=/wp/v2/posts/3161"
}
]
}
@ -5169,16 +5169,16 @@ mockedApiResponse.postAutosaves = [
];
mockedApiResponse.autosave = {
"author": 375,
"author": 376,
"date": "2017-02-14T00:00:00",
"date_gmt": "2017-02-14T00:00:00",
"id": 36745,
"id": 3163,
"modified": "2017-02-14T00:00:00",
"modified_gmt": "2017-02-14T00:00:00",
"parent": 36743,
"slug": "36743-autosave-v1",
"parent": 3161,
"slug": "3161-autosave-v1",
"guid": {
"rendered": "http://example.org/?p=36745"
"rendered": "http://example.org/?p=3163"
},
"title": {
"rendered": ""
@ -5343,16 +5343,16 @@ mockedApiResponse.pageRevisions = [
}
},
{
"author": 375,
"author": 376,
"date": "2017-02-14T00:00:00",
"date_gmt": "2017-02-14T00:00:00",
"id": 36747,
"id": 3165,
"modified": "2017-02-14T00:00:00",
"modified_gmt": "2017-02-14T00:00:00",
"parent": 36746,
"slug": "36746-revision-v1",
"parent": 3164,
"slug": "3164-revision-v1",
"guid": {
"rendered": "http://example.org/?p=36747"
"rendered": "http://example.org/?p=3165"
},
"title": {
"rendered": "REST API Client Fixture: Page"
@ -5366,7 +5366,7 @@ mockedApiResponse.pageRevisions = [
"_links": {
"parent": [
{
"href": "http://example.org/index.php?rest_route=/wp/v2/pages/36746"
"href": "http://example.org/index.php?rest_route=/wp/v2/pages/3164"
}
]
}
@ -5398,16 +5398,16 @@ mockedApiResponse.pageRevision = {
mockedApiResponse.pageAutosaves = [
{
"author": 375,
"author": 376,
"date": "2017-02-14T00:00:00",
"date_gmt": "2017-02-14T00:00:00",
"id": 36748,
"id": 3166,
"modified": "2017-02-14T00:00:00",
"modified_gmt": "2017-02-14T00:00:00",
"parent": 36746,
"slug": "36746-autosave-v1",
"parent": 3164,
"slug": "3164-autosave-v1",
"guid": {
"rendered": "http://example.org/?p=36748"
"rendered": "http://example.org/?p=3166"
},
"title": {
"rendered": ""
@ -5421,7 +5421,7 @@ mockedApiResponse.pageAutosaves = [
"_links": {
"parent": [
{
"href": "http://example.org/index.php?rest_route=/wp/v2/pages/36746"
"href": "http://example.org/index.php?rest_route=/wp/v2/pages/3164"
}
]
}
@ -5429,16 +5429,16 @@ mockedApiResponse.pageAutosaves = [
];
mockedApiResponse.pageAutosave = {
"author": 375,
"author": 376,
"date": "2017-02-14T00:00:00",
"date_gmt": "2017-02-14T00:00:00",
"id": 36748,
"id": 3166,
"modified": "2017-02-14T00:00:00",
"modified_gmt": "2017-02-14T00:00:00",
"parent": 36746,
"slug": "36746-autosave-v1",
"parent": 3164,
"slug": "3164-autosave-v1",
"guid": {
"rendered": "http://example.org/?p=36748"
"rendered": "http://example.org/?p=3166"
},
"title": {
"rendered": ""