Embeds: Who put this REST API infrastructure in my WordPress?

Well, while it's here, we probably should make use of it. The oEmbed endpoint now uses the REST API infrastructure, instead of providing its own.

Props swissspidy.

Fixes #34207.


Built from https://develop.svn.wordpress.org/trunk@35436


git-svn-id: http://core.svn.wordpress.org/trunk@35400 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Gary Pendergast 2015-10-29 22:51:24 +00:00
parent c68c3804fa
commit 8be4a22f82
5 changed files with 118 additions and 152 deletions

View File

@ -10,36 +10,18 @@
/**
* oEmbed API endpoint controller.
*
* Parses the oEmbed API requests and delivers
* XML and JSON responses.
* Registers the API route and delivers the response data.
* The output format (XML or JSON) is handled by the REST API.
*
* @since 4.4.0
*/
final class WP_oEmbed_Controller {
/**
* Hook into the query parsing to detect oEmbed requests.
*
* If an oEmbed request is made, trigger the output.
* Register the oEmbed REST API route.
*
* @since 4.4.0
*
* @param WP_Query $wp_query The WP_Query instance (passed by reference).
*/
public function parse_query( $wp_query ) {
if ( false === $wp_query->get( 'oembed', false ) ) {
return;
}
if ( false === $wp_query->get( 'url', false ) ) {
status_header( 400 );
return get_status_header_desc( 400 );
exit;
}
$url = esc_url_raw( get_query_var( 'url' ) );
$format = wp_oembed_ensure_format( get_query_var( 'format' ) );
public function register_routes() {
/**
* Filter the maxwidth oEmbed parameter.
*
@ -48,30 +30,40 @@ final class WP_oEmbed_Controller {
* @param int $maxwidth Maximum allowed width. Default 600.
*/
$maxwidth = apply_filters( 'oembed_default_width', 600 );
$maxwidth = absint( get_query_var( 'maxwidth', $maxwidth ) );
$callback = get_query_var( '_jsonp', false );
$request = array(
'url' => $url,
'format' => $format,
'maxwidth' => $maxwidth,
'callback' => $callback,
);
echo $this->dispatch( $request );
exit;
register_rest_route( 'oembed/1.0/', '/embed', array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_item' ),
'args' => array(
'url' => array(
'required' => true,
'sanitize_callback' => 'esc_url_raw',
),
'format' => array(
'default' => 'json',
'sanitize_callback' => 'wp_oembed_ensure_format',
),
'maxwidth' => array(
'default' => $maxwidth,
'sanitize_callback' => 'absint',
),
),
),
) );
}
/**
* Handle the whole request and print the response.
* Callback for the API endpoint.
*
* Returns the JSON object for the post.
*
* @since 4.4.0
*
* @param array $request The request arguments.
* @return string The oEmbed API response.
* @param WP_REST_Request $request Full data about the request.
* @return WP_Error|array oEmbed response data or WP_Error on failure.
*/
public function dispatch( $request ) {
public function get_item( $request ) {
$post_id = url_to_postid( $request['url'] );
/**
@ -86,79 +78,10 @@ final class WP_oEmbed_Controller {
$data = get_oembed_response_data( $post_id, $request['maxwidth'] );
if ( false === $data ) {
status_header( 404 );
return get_status_header_desc( 404 );
if ( ! $data ) {
return new WP_Error( 'oembed_invalid_url', get_status_header_desc( 404 ), array( 'status' => 404 ) );
}
if ( 'json' === $request['format'] ) {
return $this->json_response( $data, $request );
}
return $this->xml_response( $data );
}
/**
* Print the oEmbed JSON response.
*
* @since 4.4.0
*
* @param array $data The oEmbed response data.
* @param array $request The request arguments.
* @return string The JSON response data.
*/
public function json_response( $data, $request ) {
if ( ! is_string( $request['callback'] ) || preg_match( '/[^\w\.]/', $request['callback'] ) ) {
$request['callback'] = false;
}
$result = wp_json_encode( $data );
// Bail if the result couldn't be JSON encoded.
if ( ! $result || ! is_array( $data ) || empty( $data ) ) {
status_header( 501 );
return get_status_header_desc( 501 );
}
if ( ! headers_sent() ) {
$content_type = $request['callback'] ? 'application/javascript' : 'application/json';
header( 'Content-Type: ' . $content_type . '; charset=' . get_option( 'blog_charset' ) );
header( 'X-Content-Type-Options: nosniff' );
}
if ( $request['callback'] ) {
return '/**/' . $request['callback'] . '(' . $result . ')';
}
return $result;
}
/**
* Print the oEmbed XML response.
*
* @since 4.4.0
*
* @param array $data The oEmbed response data.
* @return string The XML response data.
*/
public function xml_response( $data ) {
if ( ! class_exists( 'SimpleXMLElement' ) ) {
status_header( 501 );
return get_status_header_desc( 501 );
}
$result = _oembed_create_xml( $data );
// Bail if there's no XML.
if ( ! $result ) {
status_header( 501 );
return get_status_header_desc( 501 );
}
if ( ! headers_sent() ) {
header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ) );
}
return $result;
return $data;
}
}

View File

@ -15,7 +15,7 @@ class WP {
* @access public
* @var array
*/
public $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type', 'title', 'embed', 'oembed', 'format', 'url', '_jsonp', 'maxwidth' );
public $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type', 'title', 'embed' );
/**
* Private query variables.

View File

@ -439,31 +439,32 @@ add_filter( 'image_send_to_editor', 'image_add_caption', 20, 8 );
add_filter( 'media_send_to_editor', 'image_media_send_to_editor', 10, 3 );
// Embeds
add_action( 'parse_query', 'wp_oembed_parse_query' );
add_action( 'rest_api_init', 'wp_oembed_register_route' );
add_filter( 'rest_pre_serve_request', '_oembed_rest_pre_serve_request', 10, 4 );
add_action( 'wp_head', 'wp_oembed_add_discovery_links' );
add_action( 'wp_head', 'wp_oembed_add_host_js' );
add_action( 'wp_head', 'wp_oembed_add_discovery_links' );
add_action( 'wp_head', 'wp_oembed_add_host_js' );
add_action( 'embed_head', 'print_emoji_detection_script' );
add_action( 'embed_head', 'print_emoji_styles' );
add_action( 'embed_head', 'print_embed_styles' );
add_action( 'embed_head', 'wp_print_head_scripts', 20 );
add_action( 'embed_head', 'wp_print_styles', 20 );
add_action( 'embed_head', 'wp_no_robots' );
add_action( 'embed_head', 'rel_canonical' );
add_action( 'embed_head', 'locale_stylesheet' );
add_action( 'embed_head', 'print_emoji_detection_script' );
add_action( 'embed_head', 'print_emoji_styles' );
add_action( 'embed_head', 'print_embed_styles' );
add_action( 'embed_head', 'wp_print_head_scripts', 20 );
add_action( 'embed_head', 'wp_print_styles', 20 );
add_action( 'embed_head', 'wp_no_robots' );
add_action( 'embed_head', 'rel_canonical' );
add_action( 'embed_head', 'locale_stylesheet' );
add_action( 'embed_footer', 'print_embed_scripts' );
add_action( 'embed_footer', 'wp_print_footer_scripts', 20 );
add_action( 'embed_footer', 'print_embed_scripts' );
add_action( 'embed_footer', 'wp_print_footer_scripts', 20 );
add_filter( 'excerpt_more', 'wp_embed_excerpt_more', 20 );
add_filter( 'the_excerpt_embed', 'wptexturize' );
add_filter( 'the_excerpt_embed', 'convert_chars' );
add_filter( 'the_excerpt_embed', 'wpautop' );
add_filter( 'the_excerpt_embed', 'shortcode_unautop' );
add_filter( 'the_excerpt_embed', 'wp_embed_excerpt_attachment' );
add_filter( 'excerpt_more', 'wp_embed_excerpt_more', 20 );
add_filter( 'the_excerpt_embed', 'wptexturize' );
add_filter( 'the_excerpt_embed', 'convert_chars' );
add_filter( 'the_excerpt_embed', 'wpautop' );
add_filter( 'the_excerpt_embed', 'shortcode_unautop' );
add_filter( 'the_excerpt_embed', 'wp_embed_excerpt_attachment' );
add_filter( 'oembed_dataparse', 'wp_filter_oembed_result', 10, 3 );
add_filter( 'oembed_response_data', 'get_oembed_response_data_rich', 10, 4 );
add_filter( 'oembed_dataparse', 'wp_filter_oembed_result', 10, 3 );
add_filter( 'oembed_response_data', 'get_oembed_response_data_rich', 10, 4 );
unset( $filter, $action );

View File

@ -328,17 +328,13 @@ function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) {
}
/**
* Parses an oEmbed API query.
* Registers the oEmbed REST API route.
*
* @since 4.4.0
*
* @see WP_oEmbed_Controller::parse_query()
*
* @param WP_Query $wp_query The current WP_Query instance.
*/
function wp_oembed_parse_query( $wp_query ) {
function wp_oembed_register_route() {
$controller = new WP_oEmbed_Controller();
$controller->parse_query( $wp_query );
$controller->register_routes();
}
/**
@ -421,7 +417,7 @@ function get_post_embed_url( $post = null ) {
* @return string The oEmbed endpoint URL.
*/
function get_oembed_endpoint_url( $permalink = '', $format = 'json' ) {
$url = add_query_arg( array( 'oembed' => 'true' ), home_url( '/' ) );
$url = rest_url( 'oembed/1.0/embed' );
if ( 'json' === $format ) {
$format = false;
@ -545,17 +541,8 @@ function get_oembed_response_data( $post = null, $width ) {
'max' => 600
) );
if ( $width < $min_max_width['min'] ) {
$width = $min_max_width['min'];
} elseif ( $width > $min_max_width['max'] ) {
$width = $min_max_width['max'];
}
$height = ceil( $width / 16 * 9 );
if ( 200 > $height ) {
$height = 200;
}
$width = min( max( $min_max_width['min'], $width ), $min_max_width['max'] );
$height = max( ceil( $width / 16 * 9 ), 200 );
$data = array(
'version' => '1.0',
@ -646,6 +633,61 @@ function wp_oembed_ensure_format( $format ) {
return $format;
}
/**
* Hooks into the REST API output to print XML instead of JSON.
*
* This is only done for the oEmbed API endpoint,
* which supports both formats.
*
* @access private
* @since 4.4.0
*
* @param bool $served Whether the request has already been served.
* @param WP_HTTP_ResponseInterface $result Result to send to the client. Usually a WP_REST_Response.
* @param WP_REST_Request $request Request used to generate the response.
* @param WP_REST_Server $server Server instance.
* @return true
*/
function _oembed_rest_pre_serve_request( $served, $result, $request, $server ) {
$params = $request->get_params();
if ( '/oembed/1.0/embed' !== $request->get_route() || 'GET' !== $request->get_method() ) {
return $served;
}
if ( ! isset( $params['format'] ) || 'xml' !== $params['format'] ) {
return $served;
}
// Embed links inside the request.
$data = $server->response_to_data( $result, false );
if ( 404 === $result->get_status() ) {
$data = $data[0];
}
if ( ! class_exists( 'SimpleXMLElement' ) ) {
status_header( 501 );
die( get_status_header_desc( 501 ) );
}
$result = _oembed_create_xml( $data );
// Bail if there's no XML.
if ( ! $result ) {
status_header( 501 );
return get_status_header_desc( 501 );
}
if ( ! headers_sent() ) {
$server->send_header( 'Content-Type', 'text/xml; charset=' . get_option( 'blog_charset' ) );
}
echo $result;
return true;
}
/**
* Creates an XML string from a given array.
*

View File

@ -4,7 +4,7 @@
*
* @global string $wp_version
*/
$wp_version = '4.4-beta2-35435';
$wp_version = '4.4-beta2-35436';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.