diff --git src/wp-includes/admin-bar.php src/wp-includes/admin-bar.php
index a12e9c9..3a2819b 100644
--- src/wp-includes/admin-bar.php
+++ src/wp-includes/admin-bar.php
@@ -910,6 +910,10 @@ function is_admin_bar_showing() {
}
}
+ if ( is_embed() ) {
+ $show_admin_bar = false;
+ }
+
/**
* Filter whether to show the admin bar.
*
diff --git src/wp-includes/class-wp-editor.php src/wp-includes/class-wp-editor.php
index 911aaab..ae6c0eb 100644
--- src/wp-includes/class-wp-editor.php
+++ src/wp-includes/class-wp-editor.php
@@ -401,7 +401,8 @@ final class _WP_Editors {
'wplink',
'wpdialogs',
'wptextpattern',
- 'wpview'
+ 'wpview',
+ 'wpoembed',
);
if ( ! self::$has_medialib ) {
diff --git src/wp-includes/class-wp-embed.php src/wp-includes/class-wp-embed.php
index d4b1ded..730fc4f 100644
--- src/wp-includes/class-wp-embed.php
+++ src/wp-includes/class-wp-embed.php
@@ -233,12 +233,13 @@ class WP_Embed {
* Filter whether to inspect the given URL for discoverable link tags.
*
* @since 2.9.0
+ * @since 4.4.0 The default value changed to true.
*
* @see WP_oEmbed::discover()
*
- * @param bool $enable Whether to enable `` tag discovery. Default false.
+ * @param bool $enable Whether to enable `` tag discovery. Default true.
*/
- $attr['discover'] = ( apply_filters( 'embed_oembed_discover', false ) && author_can( $post_ID, 'unfiltered_html' ) );
+ $attr['discover'] = ( apply_filters( 'embed_oembed_discover', true ) );
// Use oEmbed to get the HTML
$html = wp_oembed_get( $url, $attr );
diff --git src/wp-includes/class-wp-oembed-controller.php src/wp-includes/class-wp-oembed-controller.php
new file mode 100644
index 0000000..0fc25ba
--- /dev/null
+++ src/wp-includes/class-wp-oembed-controller.php
@@ -0,0 +1,159 @@
+get( 'oembed', false ) ) {
+ return;
+ }
+
+ if ( false === $wp_query->get( 'url', false ) ) {
+ status_header( 400 );
+ echo 'URL parameter missing';
+ exit;
+ }
+
+ $url = esc_url_raw( get_query_var( 'url' ) );
+
+ $format = wp_oembed_ensure_format( get_query_var( 'format' ) );
+
+ /**
+ * Filter the maxwidth oEmbed parameter.
+ *
+ * @since 4.4.0
+ *
+ * @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;
+ }
+
+ /**
+ * Handle the whole request and print the response.
+ *
+ * @since 4.4.0
+ *
+ * @param array $request The request arguments.
+ * @return string The oEmbed API response.
+ */
+ public function dispatch( $request ) {
+ $post_id = url_to_postid( $request['url'] );
+
+ /**
+ * Filter the determined post id.
+ *
+ * @since 4.4.0
+ *
+ * @param int $post_id The post ID.
+ * @param string $url The requestd URL.
+ */
+ $post_id = apply_filters( 'oembed_request_post_id', $post_id, $request['url'] );
+
+ $data = get_oembed_response_data( $post_id, $request['maxwidth'] );
+
+ if ( false === $data ) {
+ status_header( 404 );
+ return __( 'Invalid URL.', 'oembed-api' );
+ }
+
+ 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 'Not implemented';
+ }
+
+ 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 ) {
+ $result = _oembed_create_xml( $data );
+
+ // Bail if there's no XML.
+ if ( ! $result ) {
+ status_header( 501 );
+ return 'Not implemented';
+ }
+
+ if ( ! headers_sent() ) {
+ header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ) );
+ }
+
+ return $result;
+ }
+}
diff --git src/wp-includes/class-wp-rewrite.php src/wp-includes/class-wp-rewrite.php
index 84a57c8..b7b3753 100644
--- src/wp-includes/class-wp-rewrite.php
+++ src/wp-includes/class-wp-rewrite.php
@@ -861,6 +861,7 @@ class WP_Rewrite {
$trackbackregex = 'trackback/?$';
$pageregex = $this->pagination_base . '/?([0-9]{1,})/?$';
$commentregex = $this->comments_pagination_base . '-([0-9]{1,})/?$';
+ $embedregex = 'embed/?$';
//build up an array of endpoint regexes to append => queries to append
if ( $endpoints ) {
@@ -884,6 +885,8 @@ class WP_Rewrite {
$index = $this->index; //probably 'index.php'
$feedindex = $index;
$trackbackindex = $index;
+ $embedindex = $index;
+
//build a list from the rewritecode and queryreplace arrays, that will look something like
//tagname=$matches[i] where i is the current $i
$queries = array();
@@ -1029,8 +1032,14 @@ class WP_Rewrite {
//create query and regex for trackback
$trackbackmatch = $match . $trackbackregex;
$trackbackquery = $trackbackindex . '?' . $query . '&tb=1';
+
+ // Create query and regex for embeds.
+ $embedmatch = $match . $embedregex;
+ $embedquery = $embedindex . '?' . $query . '&embed=true';
+
//trim slashes from the end of the regex for this dir
$match = rtrim($match, '/');
+
//get rid of brackets
$submatchbase = str_replace( array('(', ')'), '', $match);
@@ -1040,6 +1049,7 @@ class WP_Rewrite {
$sub1feed = $sub1 . $feedregex; //and /feed/(atom|...)
$sub1feed2 = $sub1 . $feedregex2; //and /(feed|atom...)
$sub1comment = $sub1 . $commentregex; //and /comment-page-xx
+ $sub1embed = $sub1 . $embedregex; //and /embed/...
//add another rule to match attachments in the explicit form:
///attachment/some-text
@@ -1048,12 +1058,14 @@ class WP_Rewrite {
$sub2feed = $sub2 . $feedregex; //feeds, /attachment/feed/(atom|...)
$sub2feed2 = $sub2 . $feedregex2; //and feeds again on to this /attachment/(feed|atom...)
$sub2comment = $sub2 . $commentregex; //and /comment-page-xx
+ $sub2embed = $sub2 . $embedregex; //and /embed/...
//create queries for these extra tag-ons we've just dealt with
$subquery = $index . '?attachment=' . $this->preg_index(1);
$subtbquery = $subquery . '&tb=1';
$subfeedquery = $subquery . '&feed=' . $this->preg_index(2);
$subcommentquery = $subquery . '&cpage=' . $this->preg_index(2);
+ $subembedquery = $subquery . '&embed=true';
//do endpoints for attachments
if ( !empty($endpoints) ) {
@@ -1092,10 +1104,16 @@ class WP_Rewrite {
//add trackback
$rewrite = array_merge(array($trackbackmatch => $trackbackquery), $rewrite);
+ // add embed
+ $rewrite = array_merge( array( $embedmatch => $embedquery ), $rewrite );
+
//add regexes/queries for attachments, attachment trackbacks and so on
- if ( ! $page ) //require /attachment/stuff form for pages because of confusion with subpages
- $rewrite = array_merge($rewrite, array($sub1 => $subquery, $sub1tb => $subtbquery, $sub1feed => $subfeedquery, $sub1feed2 => $subfeedquery, $sub1comment => $subcommentquery));
- $rewrite = array_merge(array($sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery, $sub2comment => $subcommentquery), $rewrite);
+ if ( ! $page ) {
+ //require /attachment/stuff form for pages because of confusion with subpages
+ $rewrite = array_merge( $rewrite, array($sub1 => $subquery, $sub1tb => $subtbquery, $sub1feed => $subfeedquery, $sub1feed2 => $subfeedquery, $sub1comment => $subcommentquery, $sub1embed => $subembedquery ) );
+ }
+
+ $rewrite = array_merge( array( $sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery, $sub2comment => $subcommentquery, $sub2embed => $subembedquery ), $rewrite );
}
} //if($num_toks)
//add the rules for this dir to the accumulating $post_rewrite
diff --git src/wp-includes/class-wp.php src/wp-includes/class-wp.php
index 4fe2757..2ed5564 100644
--- src/wp-includes/class-wp.php
+++ src/wp-includes/class-wp.php
@@ -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');
+ 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');
/**
* Private query variables.
diff --git src/wp-includes/default-filters.php src/wp-includes/default-filters.php
index 30974c2..c1dab72 100644
--- src/wp-includes/default-filters.php
+++ src/wp-includes/default-filters.php
@@ -421,4 +421,31 @@ add_action( 'media_buttons', 'media_buttons' );
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( 'wp_head', 'wp_oembed_add_discovery_links' );
+add_action( 'wp_head', 'wp_oembed_add_host_js' );
+
+add_action( 'oembed_head', 'print_emoji_detection_script' );
+add_action( 'oembed_head', 'print_emoji_styles' );
+add_action( 'oembed_head', 'wp_print_head_scripts', 20 );
+add_action( 'oembed_head', 'wp_print_styles', 20 );
+add_action( 'oembed_head', 'wp_no_robots' );
+add_action( 'oembed_head', 'rel_canonical' );
+add_action( 'oembed_head', 'locale_stylesheet' );
+
+add_action( 'oembed_footer', 'wp_print_footer_scripts', 20 );
+
+add_filter( 'excerpt_more', 'wp_oembed_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_oembed_excerpt_attachment' );
+
+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 );
diff --git src/wp-includes/embed-template.php src/wp-includes/embed-template.php
new file mode 100644
index 0000000..73ba2fd
--- /dev/null
+++ src/wp-includes/embed-template.php
@@ -0,0 +1,769 @@
+
+
+>
+
+
+
+
+
+ tag.
+ *
+ * @since 4.4.0
+ */
+ do_action( 'oembed_head' );
+ ?>
+
+>
+ $data ) {
+ if ( $data['width'] / $data['height'] > $aspect_ratio ) {
+ $aspect_ratio = $data['width'] / $data['height'];
+ $measurements = array( $data['width'], $data['height'] );
+ $image_size = $size;
+ }
+ }
+ }
+
+ /**
+ * Filter the thumbnail image size for use in the embed template.
+ *
+ * @param string $image_size Thumbnail image size.
+ */
+ $image_size = apply_filters( 'oembed_thumbnail_image_size', $image_size );
+
+ $shape = $measurements[0] / $measurements[1] >= 1.75 ? 'rectangular' : 'square';
+
+ /**
+ * Filter the thumbnail shape for use in the embed template.
+ *
+ * Rectangular images are shown above the title
+ * while square images are shown next to the content.
+ *
+ * @since 4.4.0
+ *
+ * @param string $shape Thumbnail image shape. Either 'rectangular' or 'square'.
+ */
+ $shape = apply_filters( 'oembed_thumbnail_image_shape', $shape );
+ }
+ ?>
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git src/wp-includes/js/tinymce/plugins/wpoembed/plugin.js src/wp-includes/js/tinymce/plugins/wpoembed/plugin.js
new file mode 100644
index 0000000..3572426
--- /dev/null
+++ src/wp-includes/js/tinymce/plugins/wpoembed/plugin.js
@@ -0,0 +1,17 @@
+(function ( tinymce ) {
+ 'use strict';
+
+ tinymce.PluginManager.add( 'wpoembed', function ( editor, url ) {
+ editor.on( 'init', function () {
+ var scriptId = editor.dom.uniqueId();
+
+ var scriptElm = editor.dom.create( 'script', {
+ id: scriptId,
+ type: 'text/javascript',
+ src: url + '/../../../wp-oembed.js'
+ } );
+
+ editor.getDoc().getElementsByTagName( 'head' )[ 0 ].appendChild( scriptElm );
+ } );
+ } );
+})( window.tinymce );
diff --git src/wp-includes/js/wp-oembed.js src/wp-includes/js/wp-oembed.js
new file mode 100644
index 0000000..0715905
--- /dev/null
+++ src/wp-includes/js/wp-oembed.js
@@ -0,0 +1,66 @@
+(function ( window, document ) {
+ 'use strict';
+
+ window.wp = window.wp || {};
+
+ if ( !! window.wp.receiveEmbedMessage ) {
+ return;
+ }
+
+ window.wp.receiveEmbedMessage = function( e ) {
+ if ( ! ( e.data.secret || e.data.message || e.data.value ) ) {
+ return;
+ }
+
+ var iframes = document.querySelectorAll( '.wp-embedded-content[data-secret="' + e.data.secret + '"]' );
+
+ for ( var i = 0; i < iframes.length; i++ ) {
+ var source = iframes[ i ];
+
+ /* Resize the iframe on request. */
+ if ( 'height' === e.data.message ) {
+ var height = e.data.value;
+ if ( height > 1000 ) {
+ height = 1000;
+ } else if ( height < 200 ) {
+ height = 200;
+ }
+
+ source.height = (height) + "px";
+ }
+
+ /* Link to a specific URL on request. */
+ if ( 'link' === e.data.message ) {
+ var sourceURL = document.createElement( 'a' ), targetURL = document.createElement( 'a' );
+ sourceURL.href = source.getAttribute( 'src' );
+ targetURL.href = e.data.value;
+
+ /* Only continue if link hostname matches iframe's hostname. */
+ if ( targetURL.host === sourceURL.host && document.activeElement === source ) {
+ window.top.location.href = e.data.value;
+ }
+ }
+ }
+ }
+
+ window.addEventListener( 'message', window.wp.receiveEmbedMessage, false );
+
+ function onLoad() {
+ var isIE10 = 10 === new Function( "/*@cc_on return @_jscript_version; @*/" )(),
+ isIE11 = !!navigator.userAgent.match( /Trident.*rv\:11\./ );
+
+ /* Remove security attribute from iframes in IE10 and IE11. */
+ if ( isIE10 || isIE11 ) {
+ var iframes = document.querySelectorAll( '.wp-embedded-content[security]' ), iframeClone;
+
+ for ( var i = 0; i < iframes.length; i++ ) {
+ iframeClone = iframes[ i ].cloneNode( true );
+ iframeClone.removeAttribute( 'security' );
+ iframes[ i ].parentNode.insertBefore( iframeClone, iframes[ i ].nextSibling );
+ iframes[ i ].parentNode.removeChild( iframes[ i ] );
+ }
+ }
+ }
+
+ document.addEventListener( 'DOMContentLoaded', onLoad, false );
+})( window, document );
diff --git src/wp-includes/media.php src/wp-includes/media.php
index 44e18f4..53503e9 100644
--- src/wp-includes/media.php
+++ src/wp-includes/media.php
@@ -2177,80 +2177,6 @@ function wp_imagecreatetruecolor($width, $height) {
}
/**
- * Registers an embed handler.
- *
- * Should probably only be used for sites that do not support oEmbed.
- *
- * @since 2.9.0
- *
- * @global WP_Embed $wp_embed
- *
- * @param string $id An internal ID/name for the handler. Needs to be unique.
- * @param string $regex The regex that will be used to see if this handler should be used for a URL.
- * @param callable $callback The callback function that will be called if the regex is matched.
- * @param int $priority Optional. Used to specify the order in which the registered handlers will
- * be tested. Default 10.
- */
-function wp_embed_register_handler( $id, $regex, $callback, $priority = 10 ) {
- global $wp_embed;
- $wp_embed->register_handler( $id, $regex, $callback, $priority );
-}
-
-/**
- * Unregisters a previously-registered embed handler.
- *
- * @since 2.9.0
- *
- * @global WP_Embed $wp_embed
- *
- * @param string $id The handler ID that should be removed.
- * @param int $priority Optional. The priority of the handler to be removed. Default 10.
- */
-function wp_embed_unregister_handler( $id, $priority = 10 ) {
- global $wp_embed;
- $wp_embed->unregister_handler( $id, $priority );
-}
-
-/**
- * Create default array of embed parameters.
- *
- * The width defaults to the content width as specified by the theme. If the
- * theme does not specify a content width, then 500px is used.
- *
- * The default height is 1.5 times the width, or 1000px, whichever is smaller.
- *
- * The 'embed_defaults' filter can be used to adjust either of these values.
- *
- * @since 2.9.0
- *
- * @global int $content_width
- *
- * @param string $url Optional. The URL that should be embedded. Default empty.
- *
- * @return array Default embed parameters.
- */
-function wp_embed_defaults( $url = '' ) {
- if ( ! empty( $GLOBALS['content_width'] ) )
- $width = (int) $GLOBALS['content_width'];
-
- if ( empty( $width ) )
- $width = 500;
-
- $height = min( ceil( $width * 1.5 ), 1000 );
-
- /**
- * Filter the default array of embed dimensions.
- *
- * @since 2.9.0
- *
- * @param int $width Width of the embed in pixels.
- * @param int $height Height of the embed in pixels.
- * @param string $url The URL that should be embedded.
- */
- return apply_filters( 'embed_defaults', compact( 'width', 'height' ), $url );
-}
-
-/**
* Based on a supplied width/height example, return the biggest possible dimensions based on the max width/height.
*
* @since 2.9.0
@@ -2273,252 +2199,6 @@ function wp_expand_dimensions( $example_width, $example_height, $max_width, $max
}
/**
- * Attempts to fetch the embed HTML for a provided URL using oEmbed.
- *
- * @since 2.9.0
- *
- * @see WP_oEmbed
- *
- * @param string $url The URL that should be embedded.
- * @param array $args Optional. Additional arguments and parameters for retrieving embed HTML.
- * Default empty.
- * @return false|string False on failure or the embed HTML on success.
- */
-function wp_oembed_get( $url, $args = '' ) {
- require_once( ABSPATH . WPINC . '/class-oembed.php' );
- $oembed = _wp_oembed_get_object();
- return $oembed->get_html( $url, $args );
-}
-
-/**
- * Adds a URL format and oEmbed provider URL pair.
- *
- * @since 2.9.0
- *
- * @see WP_oEmbed
- *
- * @param string $format The format of URL that this provider can handle. You can use asterisks
- * as wildcards.
- * @param string $provider The URL to the oEmbed provider.
- * @param boolean $regex Optional. Whether the `$format` parameter is in a RegEx format. Default false.
- */
-function wp_oembed_add_provider( $format, $provider, $regex = false ) {
- require_once( ABSPATH . WPINC . '/class-oembed.php' );
-
- if ( did_action( 'plugins_loaded' ) ) {
- $oembed = _wp_oembed_get_object();
- $oembed->providers[$format] = array( $provider, $regex );
- } else {
- WP_oEmbed::_add_provider_early( $format, $provider, $regex );
- }
-}
-
-/**
- * Removes an oEmbed provider.
- *
- * @since 3.5.0
- *
- * @see WP_oEmbed
- *
- * @param string $format The URL format for the oEmbed provider to remove.
- * @return bool Was the provider removed successfully?
- */
-function wp_oembed_remove_provider( $format ) {
- require_once( ABSPATH . WPINC . '/class-oembed.php' );
-
- if ( did_action( 'plugins_loaded' ) ) {
- $oembed = _wp_oembed_get_object();
-
- if ( isset( $oembed->providers[ $format ] ) ) {
- unset( $oembed->providers[ $format ] );
- return true;
- }
- } else {
- WP_oEmbed::_remove_provider_early( $format );
- }
-
- return false;
-}
-
-/**
- * Determines if default embed handlers should be loaded.
- *
- * Checks to make sure that the embeds library hasn't already been loaded. If
- * it hasn't, then it will load the embeds library.
- *
- * @since 2.9.0
- *
- * @see wp_embed_register_handler()
- */
-function wp_maybe_load_embeds() {
- /**
- * Filter whether to load the default embed handlers.
- *
- * Returning a falsey value will prevent loading the default embed handlers.
- *
- * @since 2.9.0
- *
- * @param bool $maybe_load_embeds Whether to load the embeds library. Default true.
- */
- if ( ! apply_filters( 'load_default_embeds', true ) ) {
- return;
- }
-
- wp_embed_register_handler( 'youtube_embed_url', '#https?://(www.)?youtube\.com/(?:v|embed)/([^/]+)#i', 'wp_embed_handler_youtube' );
-
- wp_embed_register_handler( 'googlevideo', '#http://video\.google\.([A-Za-z.]{2,5})/videoplay\?docid=([\d-]+)(.*?)#i', 'wp_embed_handler_googlevideo' );
-
- /**
- * Filter the audio embed handler callback.
- *
- * @since 3.6.0
- *
- * @param callable $handler Audio embed handler callback function.
- */
- wp_embed_register_handler( 'audio', '#^https?://.+?\.(' . join( '|', wp_get_audio_extensions() ) . ')$#i', apply_filters( 'wp_audio_embed_handler', 'wp_embed_handler_audio' ), 9999 );
-
- /**
- * Filter the video embed handler callback.
- *
- * @since 3.6.0
- *
- * @param callable $handler Video embed handler callback function.
- */
- wp_embed_register_handler( 'video', '#^https?://.+?\.(' . join( '|', wp_get_video_extensions() ) . ')$#i', apply_filters( 'wp_video_embed_handler', 'wp_embed_handler_video' ), 9999 );
-}
-
-/**
- * The Google Video embed handler callback.
- *
- * Google Video does not support oEmbed.
- *
- * @see WP_Embed::register_handler()
- * @see WP_Embed::shortcode()
- *
- * @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
- * @param array $attr Embed attributes.
- * @param string $url The original URL that was matched by the regex.
- * @param array $rawattr The original unmodified attributes.
- * @return string The embed HTML.
- */
-function wp_embed_handler_googlevideo( $matches, $attr, $url, $rawattr ) {
- // If the user supplied a fixed width AND height, use it
- if ( !empty($rawattr['width']) && !empty($rawattr['height']) ) {
- $width = (int) $rawattr['width'];
- $height = (int) $rawattr['height'];
- } else {
- list( $width, $height ) = wp_expand_dimensions( 425, 344, $attr['width'], $attr['height'] );
- }
-
- /**
- * Filter the Google Video embed output.
- *
- * @since 2.9.0
- *
- * @param string $html Google Video HTML embed markup.
- * @param array $matches The RegEx matches from the provided regex.
- * @param array $attr An array of embed attributes.
- * @param string $url The original URL that was matched by the regex.
- * @param array $rawattr The original unmodified attributes.
- */
- return apply_filters( 'embed_googlevideo', '', $matches, $attr, $url, $rawattr );
-}
-
-/**
- * YouTube iframe embed handler callback.
- *
- * Catches YouTube iframe embed URLs that are not parsable by oEmbed but can be translated into a URL that is.
- *
- * @since 4.0.0
- *
- * @global WP_Embed $wp_embed
- *
- * @param array $matches The RegEx matches from the provided regex when calling
- * wp_embed_register_handler().
- * @param array $attr Embed attributes.
- * @param string $url The original URL that was matched by the regex.
- * @param array $rawattr The original unmodified attributes.
- * @return string The embed HTML.
- */
-function wp_embed_handler_youtube( $matches, $attr, $url, $rawattr ) {
- global $wp_embed;
- $embed = $wp_embed->autoembed( "https://youtube.com/watch?v={$matches[2]}" );
-
- /**
- * Filter the YoutTube embed output.
- *
- * @since 4.0.0
- *
- * @see wp_embed_handler_youtube()
- *
- * @param string $embed YouTube embed output.
- * @param array $attr An array of embed attributes.
- * @param string $url The original URL that was matched by the regex.
- * @param array $rawattr The original unmodified attributes.
- */
- return apply_filters( 'wp_embed_handler_youtube', $embed, $attr, $url, $rawattr );
-}
-
-/**
- * Audio embed handler callback.
- *
- * @since 3.6.0
- *
- * @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
- * @param array $attr Embed attributes.
- * @param string $url The original URL that was matched by the regex.
- * @param array $rawattr The original unmodified attributes.
- * @return string The embed HTML.
- */
-function wp_embed_handler_audio( $matches, $attr, $url, $rawattr ) {
- $audio = sprintf( '[audio src="%s" /]', esc_url( $url ) );
-
- /**
- * Filter the audio embed output.
- *
- * @since 3.6.0
- *
- * @param string $audio Audio embed output.
- * @param array $attr An array of embed attributes.
- * @param string $url The original URL that was matched by the regex.
- * @param array $rawattr The original unmodified attributes.
- */
- return apply_filters( 'wp_embed_handler_audio', $audio, $attr, $url, $rawattr );
-}
-
-/**
- * Video embed handler callback.
- *
- * @since 3.6.0
- *
- * @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
- * @param array $attr Embed attributes.
- * @param string $url The original URL that was matched by the regex.
- * @param array $rawattr The original unmodified attributes.
- * @return string The embed HTML.
- */
-function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) {
- $dimensions = '';
- if ( ! empty( $rawattr['width'] ) && ! empty( $rawattr['height'] ) ) {
- $dimensions .= sprintf( 'width="%d" ', (int) $rawattr['width'] );
- $dimensions .= sprintf( 'height="%d" ', (int) $rawattr['height'] );
- }
- $video = sprintf( '[video %s src="%s" /]', $dimensions, esc_url( $url ) );
-
- /**
- * Filter the video embed output.
- *
- * @since 3.6.0
- *
- * @param string $video Video embed output.
- * @param array $attr An array of embed attributes.
- * @param string $url The original URL that was matched by the regex.
- * @param array $rawattr The original unmodified attributes.
- */
- return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr );
-}
-
-/**
* Converts a shorthand byte value to an integer byte value.
*
* @since 2.3.0
diff --git src/wp-includes/oembed-functions.php src/wp-includes/oembed-functions.php
new file mode 100644
index 0000000..9630b23
--- /dev/null
+++ src/wp-includes/oembed-functions.php
@@ -0,0 +1,776 @@
+register_handler( $id, $regex, $callback, $priority );
+}
+
+/**
+ * Unregisters a previously-registered embed handler.
+ *
+ * @since 2.9.0
+ *
+ * @global WP_Embed $wp_embed
+ *
+ * @param string $id The handler ID that should be removed.
+ * @param int $priority Optional. The priority of the handler to be removed. Default 10.
+ */
+function wp_embed_unregister_handler( $id, $priority = 10 ) {
+ global $wp_embed;
+ $wp_embed->unregister_handler( $id, $priority );
+}
+
+/**
+ * Create default array of embed parameters.
+ *
+ * The width defaults to the content width as specified by the theme. If the
+ * theme does not specify a content width, then 500px is used.
+ *
+ * The default height is 1.5 times the width, or 1000px, whichever is smaller.
+ *
+ * The 'embed_defaults' filter can be used to adjust either of these values.
+ *
+ * @since 2.9.0
+ *
+ * @global int $content_width
+ *
+ * @param string $url Optional. The URL that should be embedded. Default empty.
+ *
+ * @return array Default embed parameters.
+ */
+function wp_embed_defaults( $url = '' ) {
+ if ( ! empty( $GLOBALS['content_width'] ) )
+ $width = (int) $GLOBALS['content_width'];
+
+ if ( empty( $width ) )
+ $width = 500;
+
+ $height = min( ceil( $width * 1.5 ), 1000 );
+
+ /**
+ * Filter the default array of embed dimensions.
+ *
+ * @since 2.9.0
+ *
+ * @param int $width Width of the embed in pixels.
+ * @param int $height Height of the embed in pixels.
+ * @param string $url The URL that should be embedded.
+ */
+ return apply_filters( 'embed_defaults', compact( 'width', 'height' ), $url );
+}
+
+/**
+ * Attempts to fetch the embed HTML for a provided URL using oEmbed.
+ *
+ * @since 2.9.0
+ *
+ * @see WP_oEmbed
+ *
+ * @param string $url The URL that should be embedded.
+ * @param array $args Optional. Additional arguments and parameters for retrieving embed HTML.
+ * Default empty.
+ * @return false|string False on failure or the embed HTML on success.
+ */
+function wp_oembed_get( $url, $args = '' ) {
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
+ $oembed = _wp_oembed_get_object();
+ return $oembed->get_html( $url, $args );
+}
+
+/**
+ * Adds a URL format and oEmbed provider URL pair.
+ *
+ * @since 2.9.0
+ *
+ * @see WP_oEmbed
+ *
+ * @param string $format The format of URL that this provider can handle. You can use asterisks
+ * as wildcards.
+ * @param string $provider The URL to the oEmbed provider.
+ * @param boolean $regex Optional. Whether the `$format` parameter is in a RegEx format. Default false.
+ */
+function wp_oembed_add_provider( $format, $provider, $regex = false ) {
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
+
+ if ( did_action( 'plugins_loaded' ) ) {
+ $oembed = _wp_oembed_get_object();
+ $oembed->providers[$format] = array( $provider, $regex );
+ } else {
+ WP_oEmbed::_add_provider_early( $format, $provider, $regex );
+ }
+}
+
+/**
+ * Removes an oEmbed provider.
+ *
+ * @since 3.5.0
+ *
+ * @see WP_oEmbed
+ *
+ * @param string $format The URL format for the oEmbed provider to remove.
+ * @return bool Was the provider removed successfully?
+ */
+function wp_oembed_remove_provider( $format ) {
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
+
+ if ( did_action( 'plugins_loaded' ) ) {
+ $oembed = _wp_oembed_get_object();
+
+ if ( isset( $oembed->providers[ $format ] ) ) {
+ unset( $oembed->providers[ $format ] );
+ return true;
+ }
+ } else {
+ WP_oEmbed::_remove_provider_early( $format );
+ }
+
+ return false;
+}
+
+/**
+ * Determines if default embed handlers should be loaded.
+ *
+ * Checks to make sure that the embeds library hasn't already been loaded. If
+ * it hasn't, then it will load the embeds library.
+ *
+ * @since 2.9.0
+ *
+ * @see wp_embed_register_handler()
+ */
+function wp_maybe_load_embeds() {
+ /**
+ * Filter whether to load the default embed handlers.
+ *
+ * Returning a falsey value will prevent loading the default embed handlers.
+ *
+ * @since 2.9.0
+ *
+ * @param bool $maybe_load_embeds Whether to load the embeds library. Default true.
+ */
+ if ( ! apply_filters( 'load_default_embeds', true ) ) {
+ return;
+ }
+
+ wp_embed_register_handler( 'youtube_embed_url', '#https?://(www.)?youtube\.com/(?:v|embed)/([^/]+)#i', 'wp_embed_handler_youtube' );
+
+ wp_embed_register_handler( 'googlevideo', '#http://video\.google\.([A-Za-z.]{2,5})/videoplay\?docid=([\d-]+)(.*?)#i', 'wp_embed_handler_googlevideo' );
+
+ /**
+ * Filter the audio embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param callable $handler Audio embed handler callback function.
+ */
+ wp_embed_register_handler( 'audio', '#^https?://.+?\.(' . join( '|', wp_get_audio_extensions() ) . ')$#i', apply_filters( 'wp_audio_embed_handler', 'wp_embed_handler_audio' ), 9999 );
+
+ /**
+ * Filter the video embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param callable $handler Video embed handler callback function.
+ */
+ wp_embed_register_handler( 'video', '#^https?://.+?\.(' . join( '|', wp_get_video_extensions() ) . ')$#i', apply_filters( 'wp_video_embed_handler', 'wp_embed_handler_video' ), 9999 );
+}
+
+/**
+ * The Google Video embed handler callback.
+ *
+ * Google Video does not support oEmbed.
+ *
+ * @see WP_Embed::register_handler()
+ * @see WP_Embed::shortcode()
+ *
+ * @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
+ * @param array $attr Embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_googlevideo( $matches, $attr, $url, $rawattr ) {
+ // If the user supplied a fixed width AND height, use it
+ if ( !empty($rawattr['width']) && !empty($rawattr['height']) ) {
+ $width = (int) $rawattr['width'];
+ $height = (int) $rawattr['height'];
+ } else {
+ list( $width, $height ) = wp_expand_dimensions( 425, 344, $attr['width'], $attr['height'] );
+ }
+
+ /**
+ * Filter the Google Video embed output.
+ *
+ * @since 2.9.0
+ *
+ * @param string $html Google Video HTML embed markup.
+ * @param array $matches The RegEx matches from the provided regex.
+ * @param array $attr An array of embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ */
+ return apply_filters( 'embed_googlevideo', '', $matches, $attr, $url, $rawattr );
+}
+
+/**
+ * YouTube iframe embed handler callback.
+ *
+ * Catches YouTube iframe embed URLs that are not parsable by oEmbed but can be translated into a URL that is.
+ *
+ * @since 4.0.0
+ *
+ * @global WP_Embed $wp_embed
+ *
+ * @param array $matches The RegEx matches from the provided regex when calling
+ * wp_embed_register_handler().
+ * @param array $attr Embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_youtube( $matches, $attr, $url, $rawattr ) {
+ global $wp_embed;
+ $embed = $wp_embed->autoembed( "https://youtube.com/watch?v={$matches[2]}" );
+
+ /**
+ * Filter the YoutTube embed output.
+ *
+ * @since 4.0.0
+ *
+ * @see wp_embed_handler_youtube()
+ *
+ * @param string $embed YouTube embed output.
+ * @param array $attr An array of embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ */
+ return apply_filters( 'wp_embed_handler_youtube', $embed, $attr, $url, $rawattr );
+}
+
+/**
+ * Audio embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
+ * @param array $attr Embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_audio( $matches, $attr, $url, $rawattr ) {
+ $audio = sprintf( '[audio src="%s" /]', esc_url( $url ) );
+
+ /**
+ * Filter the audio embed output.
+ *
+ * @since 3.6.0
+ *
+ * @param string $audio Audio embed output.
+ * @param array $attr An array of embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ */
+ return apply_filters( 'wp_embed_handler_audio', $audio, $attr, $url, $rawattr );
+}
+
+/**
+ * Video embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
+ * @param array $attr Embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) {
+ $dimensions = '';
+ if ( ! empty( $rawattr['width'] ) && ! empty( $rawattr['height'] ) ) {
+ $dimensions .= sprintf( 'width="%d" ', (int) $rawattr['width'] );
+ $dimensions .= sprintf( 'height="%d" ', (int) $rawattr['height'] );
+ }
+ $video = sprintf( '[video %s src="%s" /]', $dimensions, esc_url( $url ) );
+
+ /**
+ * Filter the video embed output.
+ *
+ * @since 3.6.0
+ *
+ * @param string $video Video embed output.
+ * @param array $attr An array of embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ */
+ return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr );
+}
+
+/**
+ * Parse an oEmbed API query.
+ *
+ * @since 4.4.0
+ */
+function wp_oembed_parse_query( $wp_query ) {
+ $controller = new WP_oEmbed_Controller;
+ $controller->parse_query( $wp_query );
+}
+
+/**
+ * Adds oEmbed discovery links in the website .
+ *
+ * @since 4.4.0
+ */
+function wp_oembed_add_discovery_links() {
+ $output = '';
+
+ if ( is_singular() ) {
+ $output .= '' . "\n";
+ $output .= '' . "\n";
+ }
+
+ /**
+ * Filter the oEmbed discovery links.
+ *
+ * @since 4.4.0
+ *
+ * @param string $output HTML of the discovery links.
+ */
+ echo apply_filters( 'oembed_discovery_links', $output );
+}
+
+/**
+ * Add the necessary JavaScript to communicate with the embedded iframes.
+ *
+ * @since 4.4.0
+ */
+function wp_oembed_add_host_js() {
+ wp_enqueue_script( 'wp-oembed' );
+}
+
+
+/**
+ * Get the URL to embed a specific post in an iframe.
+ *
+ * @since 4.4.0
+ *
+ * @param int|WP_Post $post Optional. Post ID or object. Defaults to the current post.
+ * @return string|false The post embed URL on success, false if the post doesn't exist.
+ */
+function get_post_embed_url( $post = null ) {
+ $post = get_post( $post );
+
+ if ( ! $post ) {
+ return false;
+ }
+
+ if ( get_option( 'permalink_structure' ) ) {
+ $embed_url = trailingslashit( get_permalink( $post ) ) . user_trailingslashit( 'embed' );
+ } else {
+ $embed_url = add_query_arg( array( 'embed' => 'true' ), get_permalink( $post ) );
+ }
+
+ /**
+ * Filter the URL to embed a specific post.
+ *
+ * @since 4.4.0
+ *
+ * @param string $embed_url The post embed URL.
+ * @param WP_Post $post The corresponding post object.
+ */
+ return esc_url_raw( apply_filters( 'post_embed_url', $embed_url, $post ) );
+}
+
+/**
+ * Get the oEmbed endpoint URL for a given permalink.
+ *
+ * Pass an empty string as the first argument
+ * to get the endpoint base URL.
+ *
+ * @since 4.4.0
+ *
+ * @param string $permalink Optional. The permalink used for the `url` query arg. Default empty.
+ * @param string $format Optional. The requested response format. Default 'json'.
+ * @return string The oEmbed endpoint URL.
+ */
+function get_oembed_endpoint_url( $permalink = '', $format = 'json' ) {
+ $url = add_query_arg( array( 'oembed' => 'true' ), home_url( '/' ) );
+
+ if ( 'json' === $format ) {
+ $format = false;
+ }
+
+ if ( '' !== $permalink ) {
+ $url = add_query_arg( array(
+ 'url' => $permalink,
+ 'format' => $format,
+ ), $url );
+ }
+
+ /**
+ * Filter the oEmbed endpoint URL.
+ *
+ * @since 4.4.0
+ *
+ * @param string $url The URL to the oEmbed endpoint.
+ * @param string $permalink The permalink used for the `url` query arg.
+ * @param string $format The requested response format.
+ */
+ return apply_filters( 'oembed_endpoint_url', $url, $permalink, $format );
+}
+
+/**
+ * Get the embed code for a specific post.
+ *
+ * @since 4.4.0
+ *
+ * @param int|WP_Post $post Optional. Post ID or object. Default is global `$post`.
+ * @param int $width The width for the response.
+ * @param int $height The height for the response.
+ * @return string|false Embed code on success, false if post doesn't exist.
+ */
+function get_post_embed_html( $post = null, $width, $height ) {
+ $post = get_post( $post );
+
+ if ( ! $post ) {
+ return false;
+ }
+
+ $embed_url = get_post_embed_url( $post );
+
+ $output = "";
+
+ $output .= sprintf(
+ '',
+ esc_url( $embed_url ),
+ absint( $width ),
+ absint( $height ),
+ esc_attr__( 'Embedded WordPress Post', 'oembed-api' )
+ );
+
+ /**
+ * Filters the oEmbed HTML output.
+ *
+ * @since 4.4.0
+ *
+ * @param string $output The default HTML.
+ * @param WP_Post $post Current post object.
+ * @param int $width Width of the response.
+ * @param int $height Height of the response.
+ */
+ return apply_filters( 'oembed_html', $output, $post, $width, $height );
+}
+
+/**
+ * Get the oEmbed response data for a given post.
+ *
+ * @since 4.4.0
+ *
+ * @param WP_Post|int $post Optional. Post object or ID. Default is global `$post`.
+ * @param int $width The requested width.
+ * @return array|false Response data on success, false if post doesn't exist.
+ */
+function get_oembed_response_data( $post = null, $width ) {
+ $post = get_post( $post );
+
+ if ( ! $post ) {
+ return false;
+ }
+
+ if ( 'publish' !== get_post_status( $post ) ) {
+ return false;
+ }
+
+ /**
+ * Filter the allowed minimum width for the oEmbed response.
+ *
+ * @param int $width The minimum width. Defaults to 200.
+ */
+ $minwidth = apply_filters( 'oembed_minwidth', 200 );
+
+ /**
+ * Filter the allowed maximum width for the oEmbed response.
+ *
+ * @param int $width The maximum width. Defaults to 600.
+ */
+ $maxwidth = apply_filters( 'oembed_maxwidth', 600 );
+
+ if ( $width < $minwidth ) {
+ $width = $minwidth;
+ } else if ( $width > $maxwidth ) {
+ $width = $maxwidth;
+ }
+
+ $height = ceil( $width / 16 * 9 );
+
+ if ( 200 > $height ) {
+ $height = 200;
+ }
+
+ $data = array(
+ 'version' => '1.0',
+ 'provider_name' => get_bloginfo( 'name' ),
+ 'provider_url' => get_home_url(),
+ 'author_name' => get_bloginfo( 'name' ),
+ 'author_url' => get_home_url(),
+ 'title' => $post->post_title,
+ 'type' => 'link',
+ );
+
+ $author = get_userdata( $post->post_author );
+
+ if ( $author ) {
+ $data['author_name'] = $author->display_name;
+ $data['author_url'] = get_author_posts_url( $author->ID );
+ }
+
+ /**
+ * Filter the oEmbed response data.
+ *
+ * @since 4.4.0
+ *
+ * @param array $data The response data.
+ * @param WP_Post $post The post object.
+ * @param int $width The requested width.
+ * @param int $height The calculated height.
+ */
+ return apply_filters( 'oembed_response_data', $data, $post, $width, $height );
+}
+
+/**
+ * Filters the oEmbed response data to return an iframe embed code.
+ *
+ * @since 4.4.0
+ *
+ * @param array $data The response data.
+ * @param WP_Post $post The post object.
+ * @param int $width The requested width.
+ * @param int $height The calculated height.
+ * @return array The modified response data.
+ */
+function get_oembed_response_data_rich( $data, $post, $width, $height ) {
+ $data['width'] = absint( $width );
+ $data['height'] = absint( $height );
+ $data['type'] = 'rich';
+ $data['html'] = get_post_embed_html( $post, $width, $height );
+
+ // Add post thumbnail to response if available.
+ $thumbnail_id = false;
+
+ if ( has_post_thumbnail( $post->ID ) ) {
+ $thumbnail_id = get_post_thumbnail_id( $post->ID );
+ }
+
+ if ( 'attachment' === get_post_type( $post ) ) {
+ if ( wp_attachment_is_image( $post ) ) {
+ $thumbnail_id = $post->ID;
+ } else if ( wp_attachment_is( 'video', $post ) ) {
+ $thumbnail_id = get_post_thumbnail_id( $post );
+ $data['type'] = 'video';
+ }
+ }
+
+ 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;
+ }
+
+ return $data;
+}
+
+/**
+ * Ensures that the specified format is either 'json' or 'xml'.
+ *
+ * @since 4.4.0
+ *
+ * @param string $format The oEmbed response format. Accepts 'json', 'xml'.
+ * @return string The format, either 'xml' or 'json'. Default 'json'.
+ */
+function wp_oembed_ensure_format( $format ) {
+ if ( ! in_array( $format, array( 'json', 'xml' ), true ) ) {
+ return 'json';
+ }
+
+ return $format;
+}
+
+/**
+ * Creates an XML string from a given array.
+ *
+ * @since 4.4.0
+ * @access private
+ *
+ * @param array $data The original oEmbed response data.
+ * @param SimpleXMLElement $node Optional. XML node to append the result to recursively.
+ * @return string|false XML string on success, false on error.
+ */
+function _oembed_create_xml( $data, $node = null ) {
+ if ( ! is_array( $data ) || empty( $data ) ) {
+ return false;
+ }
+
+ if ( null === $node ) {
+ $node = new SimpleXMLElement( '' );
+ }
+
+ foreach ( $data as $key => $value ) {
+ if ( is_numeric( $key ) ) {
+ $key = 'oembed';
+ }
+
+ if ( is_array( $value ) ) {
+ $item = $node->addChild( $key );
+ _oembed_create_xml( $value, $item );
+ } else {
+ $node->addChild( $key, esc_html( $value ) );
+ }
+ }
+
+ return $node->asXML();
+}
+
+/**
+ * Filters the returned oEmbed HTML.
+ *
+ * If the $url isn't on the trusted providers list,
+ * we need to filter the HTML heavily for security.
+ *
+ * Only filters 'rich' and 'html' response types.
+ *
+ * @since 4.4.0
+ *
+ * @param string $return The returned oEmbed HTML.
+ * @param object $data A data object result from an oEmbed provider.
+ * @param string $url The URL of the content to be embedded.
+ * @return string The filtered and sanitized oEmbed result.
+ */
+function wp_filter_oembed_result( $return, $data, $url ) {
+ if ( false === $return || ! in_array( $data->type, array( 'rich', 'video' ) ) ) {
+ return $return;
+ }
+
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
+ $wp_oembed = _wp_oembed_get_object();
+
+ // Don't modify the HTML for trusted providers.
+ if ( false !== $wp_oembed->get_provider( $url, array( 'discover' => false ) ) ) {
+ return $return;
+ }
+
+ $allowed_html = array(
+ 'iframe' => array(
+ 'src' => true,
+ 'width' => true,
+ 'height' => true,
+ 'frameborder' => true,
+ 'marginwidth' => true,
+ 'marginheight' => true,
+ 'scrolling' => true,
+ 'title' => true,
+ 'class' => true,
+ ),
+ );
+
+ $html = wp_kses( $return, $allowed_html );
+ preg_match( '|^.*().*$|m', $html, $iframes );
+
+ if ( empty( $iframes ) ) {
+ return false;
+ }
+
+ $html = str_replace( '
';
+
+ $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' );
+
+ $this->assertEquals( $html, $actual );
+ }
+
+ function test_filter_oembed_result_with_untrusted_provider() {
+ $html = '';
+ $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), 'http://example.com/sample-page/' );
+
+ $matches = array();
+ preg_match( '|src=".*#\?secret=([\w\d]+)" data-secret="([\w\d]+)"|', $actual, $matches );
+
+ $this->assertTrue( isset( $matches[1] ) );
+ $this->assertTrue( isset( $matches[2] ) );
+ $this->assertEquals( $matches[1], $matches[2] );
+ }
+
+ function test_filter_oembed_result_only_one_iframe_is_allowed() {
+ $html = '';
+ $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), '' );
+
+ $this->assertEquals( '', $actual );
+ }
+
+ function test_filter_oembed_result_with_newlines() {
+ $html = <<var = 1;
+
+
+
+EOD;
+
+ $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), '' );
+
+ $this->assertEquals( '', $actual );
+ }
+
+ function test_filter_oembed_result_without_iframe() {
+ $html = 'HelloWorld
';
+ $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), '' );
+
+ $this->assertFalse( $actual );
+
+ $html = '';
+ $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), '' );
+
+ $this->assertFalse( $actual );
+ }
+
+ function test_filter_oembed_result_secret_param_available() {
+ $html = '';
+ $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), '' );
+
+ $matches = array();
+ preg_match( '|src="https://wordpress.org#\?secret=([\w\d]+)" data-secret="([\w\d]+)"|', $actual, $matches );
+
+ $this->assertTrue( isset( $matches[1] ) );
+ $this->assertTrue( isset( $matches[2] ) );
+ $this->assertEquals( $matches[1], $matches[2] );
+ }
+
+ function test_filter_oembed_result_wrong_type_provided() {
+ $actual = wp_filter_oembed_result( 'some string', (object) array( 'type' => 'link' ), '' );
+
+ $this->assertEquals( 'some string', $actual );
+ }
+
+ function test_filter_oembed_result_invalid_result() {
+ $this->assertFalse( wp_filter_oembed_result( false, (object) array( 'type' => 'rich' ), '' ) );
+ $this->assertFalse( wp_filter_oembed_result( '', (object) array( 'type' => 'rich' ), '' ) );
+ }
+}
diff --git tests/phpunit/tests/oembed/getResponseData.php tests/phpunit/tests/oembed/getResponseData.php
new file mode 100644
index 0000000..3f37a21
--- /dev/null
+++ tests/phpunit/tests/oembed/getResponseData.php
@@ -0,0 +1,156 @@
+assertFalse( get_oembed_response_data( 0, 100 ) );
+ }
+
+ function test_get_oembed_response_data() {
+ $post = $this->factory->post->create_and_get( array(
+ 'post_title' => 'Some Post',
+ ) );
+
+ $data = get_oembed_response_data( $post, 400 );
+
+ $this->assertEqualSets( array(
+ 'version' => '1.0',
+ 'provider_name' => get_bloginfo( 'name' ),
+ 'provider_url' => get_home_url( '/' ),
+ 'author_name' => get_bloginfo( 'name' ),
+ 'author_url' => get_home_url( '/' ),
+ 'title' => 'Some Post',
+ 'type' => 'rich',
+ 'width' => 400,
+ 'height' => 225,
+ 'html' => get_post_embed_html( $post, 400, 225 ),
+ ), $data );
+ }
+
+ /**
+ * Test get_oembed_response_data with an author.
+ */
+ function test_get_oembed_response_data_author() {
+ $user_id = $this->factory->user->create( array(
+ 'display_name' => 'John Doe',
+ ) );
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_title' => 'Some Post',
+ 'post_author' => $user_id,
+ ) );
+
+ $data = get_oembed_response_data( $post, 400 );
+
+ $this->assertEqualSets( array(
+ 'version' => '1.0',
+ 'provider_name' => get_bloginfo( 'name' ),
+ 'provider_url' => get_home_url( '/' ),
+ 'author_name' => 'John Doe',
+ 'author_url' => get_author_posts_url( $user_id ),
+ 'title' => 'Some Post',
+ 'type' => 'rich',
+ 'width' => 400,
+ 'height' => 225,
+ 'html' => get_post_embed_html( $post, 400, 225 ),
+ ), $data );
+ }
+
+ function test_get_oembed_response_link() {
+ remove_filter( 'oembed_response_data', 'get_oembed_response_data_rich' );
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_title' => 'Some Post',
+ ) );
+
+ $data = get_oembed_response_data( $post, 600 );
+
+ $this->assertEqualSets( array(
+ 'version' => '1.0',
+ 'provider_name' => get_bloginfo( 'name' ),
+ 'provider_url' => get_home_url( '/' ),
+ 'author_name' => get_bloginfo( 'name' ),
+ 'author_url' => get_home_url( '/' ),
+ 'title' => 'Some Post',
+ 'type' => 'link',
+ ), $data );
+
+ add_filter( 'oembed_response_data', 'get_oembed_response_data_rich', 10, 4 );
+ }
+
+ function test_get_oembed_response_data_with_draft_post() {
+ $post = $this->factory->post->create_and_get( array(
+ 'post_status' => 'draft',
+ ) );
+
+ $this->assertFalse( get_oembed_response_data( $post, 100 ) );
+ }
+
+ function test_get_oembed_response_data_with_scheduled_post() {
+ $post = $this->factory->post->create_and_get( array(
+ 'post_status' => 'future',
+ 'post_date' => strftime( '%Y-%m-%d %H:%M:%S', strtotime( '+1 day' ) ),
+ ) );
+
+ $this->assertFalse( get_oembed_response_data( $post, 100 ) );
+ }
+
+ function test_get_oembed_response_data_with_private_post() {
+ $post = $this->factory->post->create_and_get( array(
+ 'post_status' => 'private',
+ ) );
+
+ $this->assertFalse( get_oembed_response_data( $post, 100 ) );
+ }
+
+ function test_get_oembed_response_data_maxwidth_too_high() {
+ $post = $this->factory->post->create_and_get();
+
+ $data = get_oembed_response_data( $post, 1000 );
+
+ $this->assertEquals( 600, $data['width'] );
+ $this->assertEquals( 338, $data['height'] );
+ }
+
+ function test_get_oembed_response_data_maxwidth_too_low() {
+ $post = $this->factory->post->create_and_get();
+
+ $data = get_oembed_response_data( $post, 100 );
+
+ $this->assertEquals( 200, $data['width'] );
+ $this->assertEquals( 200, $data['height'] );
+ }
+
+ function test_get_oembed_response_data_with_thumbnail() {
+ $post = $this->factory->post->create_and_get();
+ $file = DIR_TESTDATA . '/images/canola.jpg';
+ $attachment_id = $this->factory->attachment->create_object( $file, $post->ID, array(
+ 'post_mime_type' => 'image/jpeg',
+ ) );
+ set_post_thumbnail( $post, $attachment_id );
+
+ $data = get_oembed_response_data( $post, 400 );
+
+ $this->assertArrayHasKey( 'thumbnail_url', $data );
+ $this->assertArrayHasKey( 'thumbnail_width', $data );
+ $this->assertArrayHasKey( 'thumbnail_height', $data );
+ $this->assertTrue( 400 >= $data['thumbnail_width'] );
+ }
+
+ function test_get_oembed_response_data_for_attachment() {
+ $parent = $this->factory->post->create();
+ $file = DIR_TESTDATA . '/images/canola.jpg';
+ $post = $this->factory->attachment->create_object( $file, $parent, array(
+ 'post_mime_type' => 'image/jpeg',
+ ) );
+
+ $data = get_oembed_response_data( $post, 400 );
+
+ $this->assertArrayHasKey( 'thumbnail_url', $data );
+ $this->assertArrayHasKey( 'thumbnail_width', $data );
+ $this->assertArrayHasKey( 'thumbnail_height', $data );
+ $this->assertTrue( 400 >= $data['thumbnail_width'] );
+ }
+}
diff --git tests/phpunit/tests/oembed/headers.php tests/phpunit/tests/oembed/headers.php
new file mode 100644
index 0000000..f2e8979
--- /dev/null
+++ tests/phpunit/tests/oembed/headers.php
@@ -0,0 +1,64 @@
+markTestSkipped( 'xdebug is required for this test' );
+ }
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_title' => 'Hello World',
+ ) );
+
+ $request = array(
+ 'url' => get_permalink( $post->ID ),
+ 'format' => 'json',
+ 'maxwidth' => 600,
+ 'callback' => '',
+ );
+
+ $legacy_controller = new WP_oEmbed_Controller();
+ $legacy_controller->dispatch( $request );
+
+ $headers = xdebug_get_headers();
+
+ $this->assertTrue( in_array( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ), $headers ) );
+ $this->assertTrue( in_array( 'X-Content-Type-Options: nosniff', $headers ) );
+
+ $request['callback'] = 'foobar';
+
+ $legacy_controller->dispatch( $request );
+
+ $headers = xdebug_get_headers();
+
+ $this->assertTrue( in_array( 'Content-Type: application/javascript; charset=' . get_option( 'blog_charset' ), $headers ) );
+ $this->assertTrue( in_array( 'X-Content-Type-Options: nosniff', $headers ) );
+ }
+
+ function test_request_xml_response_headers() {
+ if ( ! function_exists( 'xdebug_get_headers' ) ) {
+ $this->markTestSkipped( 'xdebug is required for this test' );
+ }
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_title' => 'Hello World',
+ ) );
+
+ $request = array(
+ 'url' => get_permalink( $post->ID ),
+ 'format' => 'xml',
+ 'maxwidth' => 600,
+ );
+
+ $legacy_controller = new WP_oEmbed_Controller();
+ $legacy_controller->dispatch( $request );
+
+ $headers = xdebug_get_headers();
+
+ $this->assertTrue( in_array( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), $headers ) );
+ }
+}
diff --git tests/phpunit/tests/oembed/postEmbedUrl.php tests/phpunit/tests/oembed/postEmbedUrl.php
new file mode 100644
index 0000000..26e57ce
--- /dev/null
+++ tests/phpunit/tests/oembed/postEmbedUrl.php
@@ -0,0 +1,31 @@
+assertFalse( $embed_url );
+ }
+
+ function test_get_post_embed_url_with_pretty_permalinks() {
+ update_option( 'permalink_structure', '/%postname%' );
+
+ $post_id = $this->factory->post->create();
+ $permalink = get_permalink( $post_id );
+ $embed_url = get_post_embed_url( $post_id );
+
+ $this->assertEquals( user_trailingslashit( trailingslashit( $permalink ) . 'embed' ), $embed_url );
+
+ update_option( 'permalink_structure', '' );
+ }
+
+ function test_get_post_embed_url_with_ugly_permalinks() {
+ $post_id = $this->factory->post->create();
+ $permalink = get_permalink( $post_id );
+ $embed_url = get_post_embed_url( $post_id );
+
+ $this->assertEquals( $permalink . '&embed=true', $embed_url );
+ }
+}
diff --git tests/phpunit/tests/oembed/template.php tests/phpunit/tests/oembed/template.php
new file mode 100644
index 0000000..2c97d2c
--- /dev/null
+++ tests/phpunit/tests/oembed/template.php
@@ -0,0 +1,257 @@
+factory->user->create_and_get( array(
+ 'display_name' => 'John Doe',
+ ) );
+
+ $post_id = $this->factory->post->create( array(
+ 'post_author' => $user->ID,
+ 'post_title' => 'Hello World',
+ 'post_content' => 'Foo Bar',
+ 'post_excerpt' => 'Bar Baz',
+ ) );
+ $this->go_to( get_post_embed_url( $post_id ) );
+
+ $this->assertQueryTrue( 'is_single', 'is_singular' );
+
+ ob_start();
+ include( ABSPATH . WPINC . '/embed-template.php' );
+ $actual = ob_get_clean();
+
+ $doc = new DOMDocument();
+ $this->assertTrue( $doc->loadHTML( $actual ) );
+ $this->assertTrue( false === strpos( $actual, 'Page not found' ) );
+ $this->assertTrue( false !== strpos( $actual, 'Hello World' ) );
+ }
+
+ function test_oembed_output_post_with_thumbnail() {
+ $post_id = $this->factory->post->create( array(
+ 'post_title' => 'Hello World',
+ 'post_content' => 'Foo Bar',
+ 'post_excerpt' => 'Bar Baz',
+ ) );
+ $file = DIR_TESTDATA . '/images/canola.jpg';
+ $attachment_id = $this->factory->attachment->create_object( $file, $post_id, array(
+ 'post_mime_type' => 'image/jpeg',
+ ) );
+ set_post_thumbnail( $post_id, $attachment_id );
+
+ $this->go_to( get_post_embed_url( $post_id ) );
+
+ $this->assertQueryTrue( 'is_single', 'is_singular' );
+
+ ob_start();
+ include( ABSPATH . WPINC . '/embed-template.php' );
+ $actual = ob_get_clean();
+
+ $doc = new DOMDocument();
+ $this->assertTrue( $doc->loadHTML( $actual ) );
+ $this->assertFalse( strpos( $actual, 'Page not found' ) );
+ $this->assertTrue( false !== strpos( $actual, 'Hello World' ) );
+ $this->assertTrue( false !== strpos( $actual, 'canola.jpg' ) );
+ }
+
+ function test_oembed_output_404() {
+ $this->go_to( home_url( '/?p=123&embed=true' ) );
+ $GLOBALS['wp_query']->query_vars['embed'] = true;
+
+ $this->assertQueryTrue( 'is_404' );
+
+ ob_start();
+ include( ABSPATH . WPINC . '/embed-template.php' );
+ $actual = ob_get_clean();
+
+ $doc = new DOMDocument();
+ $this->assertTrue( $doc->loadHTML( $actual ) );
+ $this->assertTrue( false !== strpos( $actual, 'Page not found' ) );
+ }
+
+ function test_oembed_output_attachment() {
+ $post = $this->factory->post->create_and_get();
+ $file = DIR_TESTDATA . '/images/canola.jpg';
+ $attachment_id = $this->factory->attachment->create_object( $file, $post->ID, array(
+ 'post_mime_type' => 'image/jpeg',
+ 'post_title' => 'Hello World',
+ 'post_content' => 'Foo Bar',
+ 'post_excerpt' => 'Bar Baz',
+ ) );
+
+ $this->go_to( get_post_embed_url( $attachment_id ) );
+
+ $this->assertQueryTrue( 'is_single', 'is_singular', 'is_attachment' );
+
+ ob_start();
+ include( ABSPATH . WPINC . '/embed-template.php' );
+ $actual = ob_get_clean();
+
+ $doc = new DOMDocument();
+ $this->assertTrue( $doc->loadHTML( $actual ) );
+ $this->assertFalse( strpos( $actual, 'Page not found' ) );
+ $this->assertTrue( false !== strpos( $actual, 'Hello World' ) );
+ $this->assertTrue( false !== strpos( $actual, 'canola.jpg' ) );
+ }
+
+ function test_oembed_output_draft_post() {
+ $post_id = $this->factory->post->create( array(
+ 'post_title' => 'Hello World',
+ 'post_content' => 'Foo Bar',
+ 'post_excerpt' => 'Bar Baz',
+ 'post_status' => 'draft',
+ ) );
+
+ $this->go_to( get_post_embed_url( $post_id ) );
+
+ $this->assertQueryTrue( 'is_404' );
+
+ ob_start();
+ include( ABSPATH . WPINC . '/embed-template.php' );
+ $actual = ob_get_clean();
+
+ $doc = new DOMDocument();
+ $this->assertTrue( $doc->loadHTML( $actual ) );
+ $this->assertTrue( false !== strpos( $actual, 'Page not found' ) );
+ }
+
+ function test_oembed_output_scheduled_post() {
+ $post_id = $this->factory->post->create( array(
+ 'post_title' => 'Hello World',
+ 'post_content' => 'Foo Bar',
+ 'post_excerpt' => 'Bar Baz',
+ 'post_status' => 'future',
+ 'post_date' => strftime( '%Y-%m-%d %H:%M:%S', strtotime( '+1 day' ) ),
+ ) );
+
+ $this->go_to( get_post_embed_url( $post_id ) );
+
+ $this->assertQueryTrue( 'is_404' );
+
+ ob_start();
+ include( ABSPATH . WPINC . '/embed-template.php' );
+ $actual = ob_get_clean();
+
+ $doc = new DOMDocument();
+ $this->assertTrue( $doc->loadHTML( $actual ) );
+ $this->assertTrue( false !== strpos( $actual, 'Page not found' ) );
+ }
+
+ function test_oembed_output_private_post() {
+ $post_id = $this->factory->post->create( array(
+ 'post_title' => 'Hello World',
+ 'post_content' => 'Foo Bar',
+ 'post_excerpt' => 'Bar Baz',
+ 'post_status' => 'private',
+ ) );
+
+ $this->go_to( get_post_embed_url( $post_id ) );
+
+ $this->assertQueryTrue( 'is_404' );
+
+ ob_start();
+ include( ABSPATH . WPINC . '/embed-template.php' );
+ $actual = ob_get_clean();
+
+ $doc = new DOMDocument();
+ $this->assertTrue( $doc->loadHTML( $actual ) );
+ $this->assertTrue( false !== strpos( $actual, 'Page not found' ) );
+ }
+
+ function test_oembed_output_private_post_with_permissions() {
+ $user_id = $this->factory->user->create( array( 'role' => 'editor' ) );
+ wp_set_current_user( $user_id );
+
+ $post_id = $this->factory->post->create( array(
+ 'post_title' => 'Hello World',
+ 'post_content' => 'Foo Bar',
+ 'post_excerpt' => 'Bar Baz',
+ 'post_status' => 'private',
+ 'post_author' => $user_id,
+ ) );
+
+ $this->go_to( get_post_embed_url( $post_id ) );
+
+ $this->assertQueryTrue( 'is_single', 'is_singular' );
+
+ ob_start();
+ include( ABSPATH . WPINC . '/embed-template.php' );
+ $actual = ob_get_clean();
+
+ $doc = new DOMDocument();
+ $this->assertTrue( $doc->loadHTML( $actual ) );
+ $this->assertTrue( false === strpos( $actual, 'Page not found' ) );
+ $this->assertTrue( false !== strpos( $actual, 'Hello World' ) );
+ }
+
+ function test_wp_oembed_excerpt_more_no_embed() {
+ $GLOBALS['wp_query'] = new WP_Query();
+
+ $this->assertEquals( 'foo bar', wp_oembed_excerpt_more( 'foo bar' ) );
+ }
+
+ function test_wp_oembed_excerpt_more() {
+ $post_id = $this->factory->post->create( array(
+ 'post_content' => 'Foo Bar',
+ ) );
+
+ $this->assertEquals( '', wp_oembed_excerpt_more( '' ) );
+
+ $this->go_to( get_post_embed_url( $post_id ) );
+
+ $actual = wp_oembed_excerpt_more( '' );
+
+ $expected = sprintf(
+ '… Read more',
+ get_the_permalink()
+ );
+
+ $this->assertEquals( $expected, $actual );
+ }
+
+ function test_is_embed_post() {
+ $this->assertFalse( is_embed() );
+
+ $post_id = $this->factory->post->create();
+ $this->go_to( get_post_embed_url( $post_id ) );
+ $this->assertTrue( is_embed() );
+ }
+
+ function test_is_embed_attachment() {
+ $post_id = $this->factory->post->create();
+ $file = DIR_TESTDATA . '/images/canola.jpg';
+ $attachment_id = $this->factory->attachment->create_object( $file, $post_id, array(
+ 'post_mime_type' => 'image/jpeg',
+ ) );
+ $this->go_to( get_post_embed_url( $attachment_id ) );
+ $this->assertTrue( is_embed() );
+ }
+
+ function test_is_embed_404() {
+ $this->go_to( home_url( '/?p=12345&embed=true' ) );
+ $this->assertTrue( is_embed() );
+ }
+
+ function test_get_post_embed_html_non_existent_post() {
+ $this->assertFalse( get_post_embed_html( 0, 200, 200 ) );
+ $this->assertFalse( get_post_embed_html( null, 200, 200 ) );
+ }
+
+ function test_get_post_embed_html() {
+ $post_id = $this->factory->post->create();
+
+ $expected = '';
+
+ $this->assertStringEndsWith( $expected, get_post_embed_html( $post_id, 200, 200 ) );
+ }
+
+ function test_add_host_js() {
+ ob_start();
+ wp_oembed_add_host_js();
+ ob_end_clean();
+
+ $this->assertTrue( wp_script_is( 'wp-oembed' ) );
+ }
+}