<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[34903] trunk: Embeds: Add oEmbed provider support.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/34903">34903</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/34903","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>pento</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2015-10-07 10:35:18 +0000 (Wed, 07 Oct 2015)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Embeds: Add oEmbed provider support.

For the past 6 years, WordPress has operated as an oEmbed consumer, allowing users to easily embed content from other sites. By adding oEmbed provider support, this allows any oEmbed consumer to embed posts from WordPress sites.

In addition to creating an oEmbed provider, WordPress' oEmbed consumer code has been enhanced to work with any site that provides oEmbed data (as long as it matches some strict security rules), and provides a preview from within the post editor.

For security, embeds appear within a sandboxed iframe - the iframe content is a template that can be styled or replaced entirely by the theme on the provider site.

Props swissspidy, pento, melchoyce, netweb, pfefferle, johnbillion, extendwings, davidbinda, danielbachhuber, SergeyBiryukov, afercia

Fixes <a href="https://core.trac.wordpress.org/ticket/32522">#32522</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkGruntfilejs">trunk/Gruntfile.js</a></li>
<li><a href="#trunksrcwpincludesadminbarphp">trunk/src/wp-includes/admin-bar.php</a></li>
<li><a href="#trunksrcwpincludesclasswpeditorphp">trunk/src/wp-includes/class-wp-editor.php</a></li>
<li><a href="#trunksrcwpincludesclasswpembedphp">trunk/src/wp-includes/class-wp-embed.php</a></li>
<li><a href="#trunksrcwpincludesclasswprewritephp">trunk/src/wp-includes/class-wp-rewrite.php</a></li>
<li><a href="#trunksrcwpincludesclasswpphp">trunk/src/wp-includes/class-wp.php</a></li>
<li><a href="#trunksrcwpincludesdefaultfiltersphp">trunk/src/wp-includes/default-filters.php</a></li>
<li><a href="#trunksrcwpincludesembedfunctionsphp">trunk/src/wp-includes/embed-functions.php</a></li>
<li><a href="#trunksrcwpincludesqueryphp">trunk/src/wp-includes/query.php</a></li>
<li><a href="#trunksrcwpincludesscriptloaderphp">trunk/src/wp-includes/script-loader.php</a></li>
<li><a href="#trunksrcwpincludestemplateloaderphp">trunk/src/wp-includes/template-loader.php</a></li>
<li><a href="#trunksrcwpsettingsphp">trunk/src/wp-settings.php</a></li>
<li><a href="#trunktestsphpunitmultisitexml">trunk/tests/phpunit/multisite.xml</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesclasswpoembedcontrollerphp">trunk/src/wp-includes/class-wp-oembed-controller.php</a></li>
<li><a href="#trunksrcwpincludescsswpoembedembedcss">trunk/src/wp-includes/css/wp-oembed-embed.css</a></li>
<li><a href="#trunksrcwpincludesembedtemplatephp">trunk/src/wp-includes/embed-template.php</a></li>
<li>trunk/src/wp-includes/js/tinymce/plugins/wpoembed/</li>
<li><a href="#trunksrcwpincludesjstinymcepluginswpoembedpluginjs">trunk/src/wp-includes/js/tinymce/plugins/wpoembed/plugin.js</a></li>
<li><a href="#trunksrcwpincludesjswpoembedembedjs">trunk/src/wp-includes/js/wp-oembed-embed.js</a></li>
<li><a href="#trunksrcwpincludesjswpoembedjs">trunk/src/wp-includes/js/wp-oembed.js</a></li>
<li>trunk/tests/phpunit/tests/oembed/</li>
<li><a href="#trunktestsphpunittestsoembedcontrollerphp">trunk/tests/phpunit/tests/oembed/controller.php</a></li>
<li><a href="#trunktestsphpunittestsoembeddiscoveryphp">trunk/tests/phpunit/tests/oembed/discovery.php</a></li>
<li><a href="#trunktestsphpunittestsoembedfilterResultphp">trunk/tests/phpunit/tests/oembed/filterResult.php</a></li>
<li><a href="#trunktestsphpunittestsoembedgetResponseDataphp">trunk/tests/phpunit/tests/oembed/getResponseData.php</a></li>
<li><a href="#trunktestsphpunittestsoembedheadersphp">trunk/tests/phpunit/tests/oembed/headers.php</a></li>
<li><a href="#trunktestsphpunittestsoembedpostEmbedUrlphp">trunk/tests/phpunit/tests/oembed/postEmbedUrl.php</a></li>
<li><a href="#trunktestsphpunittestsoembedtemplatephp">trunk/tests/phpunit/tests/oembed/template.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkGruntfilejs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/Gruntfile.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/Gruntfile.js        2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/Gruntfile.js  2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -232,7 +232,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        'wp-includes/css/*.css',
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                        // Exceptions
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        '!wp-includes/css/dashicons.css'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 '!wp-includes/css/dashicons.css',
+                                       '!wp-includes/css/wp-oembed-embed.css'
</ins><span class="cx" style="display: block; padding: 0 10px">                                 ]
</span><span class="cx" style="display: block; padding: 0 10px">                        },
</span><span class="cx" style="display: block; padding: 0 10px">                        colors: {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -528,6 +529,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        emoji: {
</span><span class="cx" style="display: block; padding: 0 10px">                                src: BUILD_DIR + 'wp-includes/formatting.php',
</span><span class="cx" style="display: block; padding: 0 10px">                                dest: '.'
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        },
+                       oembed: {
+                               src: BUILD_DIR + 'wp-includes/oembed-functions.php',
+                               dest: '.'
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><span class="cx" style="display: block; padding: 0 10px">                _watch: {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -637,6 +642,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                'clean:tinymce',
</span><span class="cx" style="display: block; padding: 0 10px">                'concat:emoji',
</span><span class="cx" style="display: block; padding: 0 10px">                'includes:emoji',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                'includes:oembed',
</ins><span class="cx" style="display: block; padding: 0 10px">                 'jsvalidate:build'
</span><span class="cx" style="display: block; padding: 0 10px">        ] );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpincludesadminbarphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/admin-bar.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/admin-bar.php       2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-includes/admin-bar.php 2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -898,6 +898,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">        if ( defined('XMLRPC_REQUEST') || defined('DOING_AJAX') || defined('IFRAME_REQUEST') )
</span><span class="cx" style="display: block; padding: 0 10px">                return false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if ( is_embed() ) {
+               return false;
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         // Integrated into the admin.
</span><span class="cx" style="display: block; padding: 0 10px">        if ( is_admin() )
</span><span class="cx" style="display: block; padding: 0 10px">                return true;
</span></span></pre></div>
<a id="trunksrcwpincludesclasswpeditorphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-editor.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-editor.php 2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-includes/class-wp-editor.php   2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -401,7 +401,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                                'wplink',
</span><span class="cx" style="display: block; padding: 0 10px">                                                'wpdialogs',
</span><span class="cx" style="display: block; padding: 0 10px">                                                'wptextpattern',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                'wpview'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         'wpview',
+                                               'wpoembed',
</ins><span class="cx" style="display: block; padding: 0 10px">                                         );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                        if ( ! self::$has_medialib ) {
</span></span></pre></div>
<a id="trunksrcwpincludesclasswpembedphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-embed.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-embed.php  2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-includes/class-wp-embed.php    2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -233,12 +233,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                         * Filter whether to inspect the given URL for discoverable link tags.
</span><span class="cx" style="display: block; padding: 0 10px">                         *
</span><span class="cx" style="display: block; padding: 0 10px">                         * @since 2.9.0
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         * @since 4.4.0 The default value changed to true.
</ins><span class="cx" style="display: block; padding: 0 10px">                          *
</span><span class="cx" style="display: block; padding: 0 10px">                         * @see WP_oEmbed::discover()
</span><span class="cx" style="display: block; padding: 0 10px">                         *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                         * @param bool $enable Whether to enable `<link>` tag discovery. Default false.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                  * @param bool $enable Whether to enable `<link>` tag discovery. Default true.
</ins><span class="cx" style="display: block; padding: 0 10px">                          */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $attr['discover'] = ( apply_filters( 'embed_oembed_discover', false ) && author_can( $post_ID, 'unfiltered_html' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $attr['discover'] = ( apply_filters( 'embed_oembed_discover', true ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Use oEmbed to get the HTML
</span><span class="cx" style="display: block; padding: 0 10px">                        $html = wp_oembed_get( $url, $attr );
</span></span></pre></div>
<a id="trunksrcwpincludesclasswpoembedcontrollerphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/src/wp-includes/class-wp-oembed-controller.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-oembed-controller.php                              (rev 0)
+++ trunk/src/wp-includes/class-wp-oembed-controller.php        2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,159 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * WP_oEmbed_Controller class, used to provide an oEmbed endpoint.
+ *
+ * @package WordPress
+ * @subpackage Embeds
+ * @since 4.4.0
+ */
+
+/**
+ * oEmbed API endpoint controller.
+ *
+ * Parses the oEmbed API requests and delivers
+ * XML and JSON responses.
+ *
+ * @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.
+        *
+        * @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 );
+                       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;
+       }
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesclasswprewritephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-rewrite.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-rewrite.php        2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-includes/class-wp-rewrite.php  2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -861,6 +861,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $trackbackregex = 'trackback/?$';
</span><span class="cx" style="display: block; padding: 0 10px">                $pageregex = $this->pagination_base . '/?([0-9]{1,})/?$';
</span><span class="cx" style="display: block; padding: 0 10px">                $commentregex = $this->comments_pagination_base . '-([0-9]{1,})/?$';
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $embedregex = 'embed/?$';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                //build up an array of endpoint regexes to append => queries to append
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $endpoints ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -884,6 +885,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $index = $this->index; //probably 'index.php'
</span><span class="cx" style="display: block; padding: 0 10px">                $feedindex = $index;
</span><span class="cx" style="display: block; padding: 0 10px">                $trackbackindex = $index;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $embedindex = $index;
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 //build a list from the rewritecode and queryreplace arrays, that will look something like
</span><span class="cx" style="display: block; padding: 0 10px">                //tagname=$matches[i] where i is the current $i
</span><span class="cx" style="display: block; padding: 0 10px">                $queries = array();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1029,8 +1032,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        //create query and regex for trackback
</span><span class="cx" style="display: block; padding: 0 10px">                                        $trackbackmatch = $match . $trackbackregex;
</span><span class="cx" style="display: block; padding: 0 10px">                                        $trackbackquery = $trackbackindex . '?' . $query . '&tb=1';
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                                       // Create query and regex for embeds.
+                                       $embedmatch = $match . $embedregex;
+                                       $embedquery = $embedindex . '?' . $query . '&embed=true';
+
</ins><span class="cx" style="display: block; padding: 0 10px">                                         //trim slashes from the end of the regex for this dir
</span><span class="cx" style="display: block; padding: 0 10px">                                        $match = rtrim($match, '/');
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                                         //get rid of brackets
</span><span class="cx" style="display: block; padding: 0 10px">                                        $submatchbase = str_replace( array('(', ')'), '', $match);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1040,6 +1049,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        $sub1feed = $sub1 . $feedregex; //and <permalink>/feed/(atom|...)
</span><span class="cx" style="display: block; padding: 0 10px">                                        $sub1feed2 = $sub1 . $feedregex2; //and <permalink>/(feed|atom...)
</span><span class="cx" style="display: block; padding: 0 10px">                                        $sub1comment = $sub1 . $commentregex; //and <permalink>/comment-page-xx
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                        $sub1embed = $sub1 . $embedregex; //and <permalink>/embed/...
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                        //add another rule to match attachments in the explicit form:
</span><span class="cx" style="display: block; padding: 0 10px">                                        //<permalink>/attachment/some-text
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1048,12 +1058,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        $sub2feed = $sub2 . $feedregex;    //feeds, <permalink>/attachment/feed/(atom|...)
</span><span class="cx" style="display: block; padding: 0 10px">                                        $sub2feed2 = $sub2 . $feedregex2;  //and feeds again on to this <permalink>/attachment/(feed|atom...)
</span><span class="cx" style="display: block; padding: 0 10px">                                        $sub2comment = $sub2 . $commentregex; //and <permalink>/comment-page-xx
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                        $sub2embed = $sub2 . $embedregex; //and <permalink>/embed/...
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                        //create queries for these extra tag-ons we've just dealt with
</span><span class="cx" style="display: block; padding: 0 10px">                                        $subquery = $index . '?attachment=' . $this->preg_index(1);
</span><span class="cx" style="display: block; padding: 0 10px">                                        $subtbquery = $subquery . '&tb=1';
</span><span class="cx" style="display: block; padding: 0 10px">                                        $subfeedquery = $subquery . '&feed=' . $this->preg_index(2);
</span><span class="cx" style="display: block; padding: 0 10px">                                        $subcommentquery = $subquery . '&cpage=' . $this->preg_index(2);
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                        $subembedquery = $subquery . '&embed=true';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                        //do endpoints for attachments
</span><span class="cx" style="display: block; padding: 0 10px">                                        if ( !empty($endpoints) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1092,10 +1104,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        //add trackback
</span><span class="cx" style="display: block; padding: 0 10px">                                        $rewrite = array_merge(array($trackbackmatch => $trackbackquery), $rewrite);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                        // add embed
+                                       $rewrite = array_merge( array( $embedmatch => $embedquery ), $rewrite );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                                         //add regexes/queries for attachments, attachment trackbacks and so on
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        if ( ! $page ) //require <permalink>/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);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 if ( ! $page ) {
+                                               //require <permalink>/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 );
</ins><span class="cx" style="display: block; padding: 0 10px">                                 }
</span><span class="cx" style="display: block; padding: 0 10px">                        } //if($num_toks)
</span><span class="cx" style="display: block; padding: 0 10px">                        //add the rules for this dir to the accumulating $post_rewrite
</span></span></pre></div>
<a id="trunksrcwpincludesclasswpphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp.php        2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-includes/class-wp.php  2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -15,7 +15,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @access public
</span><span class="cx" style="display: block; padding: 0 10px">         * @var array
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        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');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 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' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="cx" style="display: block; padding: 0 10px">         * Private query variables.
</span></span></pre></div>
<a id="trunksrcwpincludescsswpoembedembedcss"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/src/wp-includes/css/wp-oembed-embed.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/css/wp-oembed-embed.css                             (rev 0)
+++ trunk/src/wp-includes/css/wp-oembed-embed.css       2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,359 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+html, body {
+       padding: 0;
+       margin: 0;
+}
+
+body {
+       font-family: sans-serif;
+}
+
+/* Text meant only for screen readers */
+.screen-reader-text {
+       clip: rect(1px, 1px, 1px, 1px);
+       height: 1px;
+       overflow: hidden;
+       position: absolute !important;
+       width: 1px;
+}
+
+/* Dashicons */
+.dashicons {
+       display: inline-block;
+       width: 20px;
+       height: 20px;
+       background-color: transparent;
+       background-repeat: no-repeat;
+       -webkit-background-size: 20px 20px;
+       background-size: 20px;
+       background-position: center;
+       -webkit-transition: background .1s ease-in;
+       transition: background .1s ease-in;
+       position: relative;
+       top: 5px;
+}
+
+.dashicons-no {
+       background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M15.55%2013.7l-2.19%202.06-3.42-3.65-3.64%203.43-2.06-2.18%203.64-3.43-3.42-3.64%202.18-2.06%203.43%203.64%203.64-3.42%202.05%202.18-3.64%203.43z%27%20fill%3D%27%23fff%27%2F%3E%3C%2Fsvg%3E");
+}
+
+.dashicons-admin-comments {
+       background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M5%202h9q.82%200%201.41.59T16%204v7q0%20.82-.59%201.41T14%2013h-2l-5%205v-5H5q-.82%200-1.41-.59T3%2011V4q0-.82.59-1.41T5%202z%27%20fill%3D%27%2382878c%27%2F%3E%3C%2Fsvg%3E");
+}
+
+.wp-embed-comments a:hover .dashicons-admin-comments {
+       background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M5%202h9q.82%200%201.41.59T16%204v7q0%20.82-.59%201.41T14%2013h-2l-5%205v-5H5q-.82%200-1.41-.59T3%2011V4q0-.82.59-1.41T5%202z%27%20fill%3D%27%230073aa%27%2F%3E%3C%2Fsvg%3E");
+}
+
+.dashicons-share {
+       background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.5%2012q1.24%200%202.12.88T17.5%2015t-.88%202.12-2.12.88-2.12-.88T11.5%2015q0-.34.09-.69l-4.38-2.3Q6.32%2013%205%2013q-1.24%200-2.12-.88T2%2010t.88-2.12T5%207q1.3%200%202.21.99l4.38-2.3q-.09-.35-.09-.69%200-1.24.88-2.12T14.5%202t2.12.88T17.5%205t-.88%202.12T14.5%208q-1.3%200-2.21-.99l-4.38%202.3Q8%209.66%208%2010t-.09.69l4.38%202.3q.89-.99%202.21-.99z%27%20fill%3D%27%2382878c%27%2F%3E%3C%2Fsvg%3E");
+}
+
+.wp-embed-share-dialog-open:hover .dashicons-share {
+       background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2020%2020%27%3E%3Cpath%20d%3D%27M14.5%2012q1.24%200%202.12.88T17.5%2015t-.88%202.12-2.12.88-2.12-.88T11.5%2015q0-.34.09-.69l-4.38-2.3Q6.32%2013%205%2013q-1.24%200-2.12-.88T2%2010t.88-2.12T5%207q1.3%200%202.21.99l4.38-2.3q-.09-.35-.09-.69%200-1.24.88-2.12T14.5%202t2.12.88T17.5%205t-.88%202.12T14.5%208q-1.3%200-2.21-.99l-4.38%202.3Q8%209.66%208%2010t-.09.69l4.38%202.3q.89-.99%202.21-.99z%27%20fill%3D%27%230073aa%27%2F%3E%3C%2Fsvg%3E");
+}
+
+.wp-embed {
+       width: 100%;
+       padding: 25px;
+       font: 400 14px/1.5 'Open Sans', sans-serif;
+       color: #82878c;
+       background: white;
+       border: 1px solid #e5e5e5;
+       -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+       box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+       /* Clearfix */
+       overflow: auto;
+       zoom: 1;
+}
+
+.wp-embed a {
+       color: #82878c;
+       text-decoration: none;
+}
+
+.wp-embed a:hover {
+       text-decoration: underline;
+}
+
+.wp-embed-featured-image {
+       margin-bottom: 20px;
+}
+
+.wp-embed-featured-image img {
+       width: 100%;
+       height: auto;
+       border: none;
+}
+
+.wp-embed-featured-image.square {
+       float: left;
+       max-width: 160px;
+       margin-right: 20px;
+}
+
+.wp-embed p {
+       margin: 0;
+}
+
+p.wp-embed-heading {
+       margin: 0 0 15px;
+       font-weight: bold;
+       font-size: 22px;
+       line-height: 1.3;
+}
+
+.wp-embed-heading a {
+       color: #32373c;
+}
+
+.wp-embed .wp-embed-more {
+       color: #b4b9be;
+}
+
+.wp-embed-footer {
+       display: table;
+       width: 100%;
+       margin-top: 30px;
+}
+
+.wp-embed-site-icon {
+       position: absolute;
+       top: 50%;
+       left: 0;
+       -webkit-transform: translateY(-50%);
+       -ms-transform: translateY(-50%);
+       transform: translateY(-50%);
+       height: 25px;
+       width: 25px;
+       border: 0;
+}
+
+.wp-embed-site-title {
+       font-weight: bold;
+       line-height: 25px;
+}
+
+.wp-embed-site-title a {
+       position: relative;
+       display: inline-block;
+       padding-left: 35px;
+}
+
+.wp-embed-site-title,
+.wp-embed-meta {
+       display: table-cell;
+}
+
+.wp-embed-meta {
+       text-align: right;
+       white-space: nowrap;
+       vertical-align: middle;
+}
+
+.wp-embed-comments,
+.wp-embed-share {
+       display: inline;
+}
+
+.wp-embed-meta a:hover {
+       text-decoration: none;
+       color: #0073aa;
+}
+
+.wp-embed-comments a {
+       line-height: 25px;
+       display: inline-block;
+}
+
+.wp-embed-comments + .wp-embed-share {
+       margin-left: 10px;
+}
+
+.wp-embed-share-dialog {
+       position: absolute;
+       top: 0;
+       left: 0;
+       right: 0;
+       bottom: 0;
+       background-color: rgba(10, 10, 10, 0.9);
+       color: #fff;
+       opacity: 1;
+       transition: opacity .25s ease-in-out;
+       -moz-transition: opacity .25s ease-in-out;
+       -webkit-transition: opacity .25s ease-in-out;
+}
+
+.wp-embed-share-dialog.hidden {
+       opacity: 0;
+       visibility: hidden;
+}
+
+.wp-embed-share-dialog-open,
+.wp-embed-share-dialog-close {
+       margin: -8px 0 0;
+       padding: 0;
+       background: transparent;
+       border: none;
+       cursor: pointer;
+       outline: none;
+}
+
+.wp-embed-share-dialog-open .dashicons,
+.wp-embed-share-dialog-close .dashicons {
+       padding: 4px;
+}
+
+.wp-embed-share-dialog-open .dashicons {
+       top: 8px;
+}
+
+.wp-embed-share-dialog-open:focus .dashicons,
+.wp-embed-share-dialog-close:focus .dashicons {
+       -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8);
+       box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8);
+       -webkit-border-radius: 100%;
+       border-radius: 100%;
+}
+
+.wp-embed-share-dialog-close {
+       position: absolute;
+       top: 20px;
+       right: 20px;
+       font-size: 22px;
+}
+
+.wp-embed-share-dialog-close:hover {
+       text-decoration: none;
+}
+
+.wp-embed-share-dialog-close .dashicons {
+       height: 24px;
+       width: 24px;
+       -webkit-background-size: 24px 24px;
+       background-size: 24px;
+}
+
+.wp-embed-share-dialog-content {
+       height: 100%;
+       -webkit-transform-style: preserve-3d;
+       transform-style: preserve-3d;
+       overflow: hidden;
+}
+
+.wp-embed-share-dialog-text {
+       margin-top: 25px;
+       padding: 20px;
+}
+
+.wp-embed-share-tabs {
+       margin: 0 0 20px;
+       padding: 0;
+       list-style: none;
+}
+
+.wp-embed-share-tab-button {
+       display: inline;
+}
+
+.wp-embed-share-tab-button button {
+       margin: 0;
+       padding: 0;
+       border: none;
+       background: transparent;
+       font-size: 16px;
+       line-height: 1.3;
+       color: #aaa;
+       cursor: pointer;
+       -webkit-transition: color .1s ease-in;
+       transition: color .1s ease-in;
+}
+
+.wp-embed-share-tab-button [aria-selected="true"] {
+       color: #fff;
+}
+
+.wp-embed-share-tab-button button:hover {
+       color: #fff;
+}
+
+.wp-embed-share-tab-button + .wp-embed-share-tab-button {
+       margin: 0 0 0 10px;
+       padding: 0 0 0 11px;
+       border-left: 1px solid #aaa;
+}
+
+.wp-embed-share-tab[aria-hidden="true"] {
+       display: none;
+}
+
+p.wp-embed-share-description {
+       margin: 0;
+       font-size: 14px;
+       line-height: 1;
+       font-style: italic;
+       color: #aaa;
+}
+
+.wp-embed-share-input {
+       -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+       box-sizing: border-box;
+       width: 100%;
+       border: none;
+       height: 28px;
+       margin: 0 0 10px 0;
+       padding: 0 5px;
+       font: 400 14px/1.5 'Open Sans', sans-serif;
+       resize: none;
+       cursor: text;
+}
+
+textarea.wp-embed-share-input {
+       height: 72px;
+}
+
+html[dir="rtl"] .wp-embed-featured-image.square {
+       float: right;
+       margin-right: 0;
+
+       margin-left: 20px;
+}
+
+html[dir="rtl"] .wp-embed-site-title a {
+       padding-left: 0;
+       padding-right: 35px;
+}
+
+html[dir="rtl"] .wp-embed-site-icon {
+       margin-right: 0;
+       margin-left: 10px;
+       left: auto;
+       right: 0;
+}
+
+html[dir="rtl"] .wp-embed-meta {
+       text-align: left;
+}
+
+html[dir="rtl"] .wp-embed-footer {
+}
+
+html[dir="rtl"] .wp-embed-share {
+       margin-left: 0;
+       margin-right: 10px;
+}
+
+html[dir="rtl"] .wp-embed-share-dialog-close {
+       right: auto;
+       left: 20px;
+}
+
+html[dir="rtl"] .wp-embed-share-tab-button + .wp-embed-share-tab-button {
+       margin: 0 10px 0 0;
+       padding: 0 11px 0 0;
+       border-left: none;
+       border-right: 1px solid #aaa;
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesdefaultfiltersphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/default-filters.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/default-filters.php 2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-includes/default-filters.php   2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -422,4 +422,33 @@
</span><span class="cx" style="display: block; padding: 0 10px"> add_filter( 'image_send_to_editor', 'image_add_caption', 20, 8 );
</span><span class="cx" style="display: block; padding: 0 10px"> add_filter( 'media_send_to_editor', 'image_media_send_to_editor', 10, 3 );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+// 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', 'print_oembed_embed_styles' );
+add_action( 'oembed_head', 'print_oembed_embed_scripts' );
+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 );
+
</ins><span class="cx" style="display: block; padding: 0 10px"> unset( $filter, $action );
</span></span></pre></div>
<a id="trunksrcwpincludesembedfunctionsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/embed-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/embed-functions.php 2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-includes/embed-functions.php   2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -326,3 +326,529 @@
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+/**
+ * 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 <head>.
+ *
+ * @since 4.4.0
+ */
+function wp_oembed_add_discovery_links() {
+       $output = '';
+
+       if ( is_singular() ) {
+               $output .= '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink() ) ) . '" />' . "\n";
+               $output .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink(), 'xml' ) ) . '" />' . "\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 = "<script type='text/javascript'>\n";
+       if ( SCRIPT_DEBUG ) {
+               $output .= file_get_contents( ABSPATH . WPINC . '/js/wp-oembed.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-oembed.js, instead of using the
+                * file_get_contents() 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-oembed.js directly.
+                */
+               $output .=<<<JS
+               include "js/wp-oembed.min.js"
+JS;
+       }
+       $output .= "\n</script>";
+
+       $output .= sprintf(
+               '<iframe sandbox="allow-scripts" security="restricted" src="%1$s" width="%2$d" height="%3$d" title="%4$s" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" class="wp-embedded-content"></iframe>',
+               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( '<oembed></oembed>' );
+       }
+
+       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( '|^.*(<iframe.*?></iframe>).*$|m', $html, $iframes );
+
+       if ( empty( $iframes ) ) {
+               return false;
+       }
+
+       $html = str_replace( '<iframe', '<iframe sandbox="allow-scripts" security="restricted"', $iframes[1] );
+
+       preg_match( '/ src=[\'"]([^\'"]*)[\'"]/', $html, $results );
+
+       if ( ! empty( $results ) ) {
+               $secret = wp_generate_password( 10, false );
+
+               $url = esc_url( "{$results[1]}#?secret=$secret" );
+
+               $html = str_replace( $results[0], " src=\"$url\" data-secret=\"$secret\"", $html );
+       }
+
+       return $html;
+}
+
+/**
+ * Filters the string in the "more" link displayed after a trimmed excerpt.
+ *
+ * @since 4.4.0
+ *
+ * @param string $more_string The string shown within the more link.
+ * @return string The modified excerpt.
+ */
+function wp_oembed_excerpt_more( $more_string ) {
+       if ( ! is_embed() ) {
+               return $more_string;
+       }
+
+       return sprintf(
+               _x( '&hellip; %s', 'read more link', 'oembed-api' ),
+               sprintf(
+                       '<a class="wp-embed-more" href="%s" target="_top">%s</a>',
+                       get_the_permalink(),
+                       __( 'Read more', 'oembed-api' )
+               )
+       );
+}
+
+/**
+ * Display the post excerpt for the embed template.
+ *
+ * @since 4.4.0
+ */
+function the_excerpt_embed() {
+       $output = get_the_excerpt();
+
+       /**
+        * Filter the post excerpt for the embed template.
+        *
+        * @param string $output The current post excerpt.
+        */
+       echo apply_filters( 'the_excerpt_embed', $output );
+}
+
+/**
+ * Filters the post excerpt for the embed template.
+ *
+ * Shows players for video and audio attachments.
+ *
+ * @since 4.4.0
+ *
+ * @param string $content The current post excerpt.
+ * @return string The modified post excerpt.
+ */
+function wp_oembed_excerpt_attachment( $content ) {
+       if ( is_attachment() ) {
+               return prepend_attachment( '' );
+       }
+
+       return $content;
+}
+
+/**
+ * Print the CSS in the embed iframe header.
+ *
+ * @since 4.4.0
+ */
+function print_oembed_embed_styles() {
+       ?>
+       <style type="text/css">
+       <?php
+               if ( WP_DEBUG ) {
+                       readfile( ABSPATH . WPINC . "/css/wp-oembed-embed.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 WP_DEBUG
+                        * and edit wp-oembed-embed.css directly.
+                        */
+                       ?>
+                       include "css/wp-oembed-embed.min.css"
+                       <?php
+               }
+       ?>
+       </style>
+       <?php
+}
+
+/**
+ * Print the CSS in the embed iframe header.
+ *
+ * @since 4.4.0
+ */
+function print_oembed_embed_scripts() {
+       ?>
+       <script type="text/javascript">
+       <?php
+               if ( SCRIPT_DEBUG ) {
+                       readfile( ABSPATH . WPINC . "/js/wp-oembed-embed.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-oembed-embed.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-oembed-embed.js directly.
+                        */
+                       ?>
+                       include "js/wp-oembed-embed.min.js"
+                       <?php
+               }
+       ?>
+       </script>
+       <?php
+}
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesembedtemplatephp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/src/wp-includes/embed-template.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/embed-template.php                          (rev 0)
+++ trunk/src/wp-includes/embed-template.php    2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,262 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Contains the post embed template.
+ *
+ * When a post is embedded in an iframe, this file is used to
+ * create the output.
+ *
+ * @package WordPress
+ * @subpackage oEmbed
+ * @since 4.4.0
+ */
+
+if ( ! headers_sent() ) {
+       header( 'X-WP-oembed: true' );
+}
+
+wp_enqueue_style( 'open-sans' );
+
+?>
+<!DOCTYPE html>
+<html <?php language_attributes(); ?>>
+<head>
+       <title><?php wp_title( '-', true, 'right' ); ?></title>
+       <meta http-equiv="X-UA-Compatible" content="IE=edge">
+       <?php
+       /**
+        * Print scripts or data in the embed template <head> tag.
+        *
+        * @since 4.4.0
+        */
+       do_action( 'oembed_head' );
+       ?>
+</head>
+<body <?php body_class(); ?>>
+<?php
+if ( have_posts() ) :
+       while ( have_posts() ) : the_post();
+               // Add post thumbnail to response if available.
+               $thumbnail_id = false;
+
+               if ( has_post_thumbnail() ) {
+                       $thumbnail_id = get_post_thumbnail_id();
+               }
+
+               if ( 'attachment' === get_post_type() && wp_attachment_is_image() ) {
+                       $thumbnail_id = get_the_ID();
+               }
+
+               if ( $thumbnail_id ) {
+                       $aspect_ratio = 1;
+                       $measurements = array( 1, 1 );
+                       $image_size   = 'full'; // Fallback.
+
+                       $meta = wp_get_attachment_metadata( $thumbnail_id );
+                       if ( is_array( $meta ) ) {
+                               foreach ( $meta['sizes'] as $size => $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 );
+               }
+               ?>
+               <div <?php post_class( 'wp-embed' ); ?>>
+                       <?php if ( $thumbnail_id && 'rectangular' === $shape ) : ?>
+                               <div class="wp-embed-featured-image rectangular">
+                                       <a href="<?php the_permalink(); ?>" target="_top">
+                                               <?php echo wp_get_attachment_image( $thumbnail_id, $image_size ); ?>
+                                       </a>
+                               </div>
+                       <?php endif; ?>
+
+                       <p class="wp-embed-heading">
+                               <a href="<?php the_permalink(); ?>" target="_top">
+                                       <?php the_title(); ?>
+                               </a>
+                       </p>
+
+                       <?php if ( $thumbnail_id && 'square' === $shape ) : ?>
+                               <div class="wp-embed-featured-image square">
+                                       <a href="<?php the_permalink(); ?>" target="_top">
+                                               <?php echo wp_get_attachment_image( $thumbnail_id, $image_size ); ?>
+                                       </a>
+                               </div>
+                       <?php endif; ?>
+
+                       <div class="wp-embed-excerpt"><?php the_excerpt_embed(); ?></div>
+
+                       <?php
+                       /**
+                        * Print additional content after the embed excerpt.
+                        *
+                        * @since 4.4.0
+                        */
+                       do_action( 'oembed_content' );
+                       ?>
+
+                       <div class="wp-embed-footer">
+                               <div class="wp-embed-site-title">
+                                       <?php
+                                       $site_icon_url = admin_url( 'images/w-logo-blue.png' );
+
+                                       if ( function_exists( 'get_site_icon_url' ) ) {
+                                               $site_icon_url = get_site_icon_url( 32, $site_icon_url );
+                                       }
+
+                                       /**
+                                        * Filters the site icon URL for use in the embed template.
+                                        *
+                                        * @param string $site_icon_url The site icon URL.
+                                        */
+                                       $site_icon_url = apply_filters( 'oembed_site_icon_url', $site_icon_url );
+
+                                       printf(
+                                               '<a href="%s" target="_top"><img src="%s" width="32" height="32" alt="" class="wp-embed-site-icon"/><span>%s</span></a>',
+                                               esc_url( home_url() ),
+                                               esc_url( $site_icon_url ),
+                                               esc_attr( get_bloginfo( 'name' ) )
+                                       );
+                                       ?>
+                               </div>
+
+                               <div class="wp-embed-meta">
+                                       <?php
+                                       /**
+                                        * Print additional meta content in the embed template.
+                                        *
+                                        * @since 4.4.0
+                                        */
+                                       do_action( 'oembed_content_meta');
+                                       ?>
+                                       <?php if ( get_comments_number() || comments_open() ) : ?>
+                                               <div class="wp-embed-comments">
+                                                       <a href="<?php comments_link(); ?>" target="_top">
+                                                               <span class="dashicons dashicons-admin-comments"></span>
+                                                               <?php
+                                                               printf(
+                                                                       _n(
+                                                                               '%s <span class="screen-reader-text">Comment</span>',
+                                                                               '%s <span class="screen-reader-text">Comments</span>',
+                                                                               get_comments_number(),
+                                                                               'oembed-api'
+                                                                       ),
+                                                                       absint( get_comments_number() )
+                                                               );
+                                                               ?>
+                                                       </a>
+                                               </div>
+                                       <?php endif; ?>
+                                       <div class="wp-embed-share">
+                                               <button type="button" class="wp-embed-share-dialog-open"
+                                                       aria-label="<?php esc_attr_e( 'Open sharing dialog', 'oembed-api' ); ?>">
+                                                       <span class="dashicons dashicons-share"></span>
+                                               </button>
+                                       </div>
+                               </div>
+                       </div>
+                       <div class="wp-embed-share-dialog hidden">
+                               <div class="wp-embed-share-dialog-content">
+                                       <div class="wp-embed-share-dialog-text">
+                                               <ul class="wp-embed-share-tabs" role="tablist">
+                                                       <li id="wp-embed-share-tab-button-wordpress" class="wp-embed-share-tab-button" role="presentation">
+                                                               <button role="tab" aria-controls="wp-embed-share-tab-wordpress" aria-selected="true" tabindex="0"><?php esc_html_e( 'WordPress Embed', 'oembed-api' ); ?></button>
+                                                       </li>
+                                                       <li id="wp-embed-share-tab-button-embed" class="wp-embed-share-tab-button" role="presentation">
+                                                               <button role="tab" aria-controls="wp-embed-share-tab-html" aria-selected="false" tabindex="-1"><?php esc_html_e( 'HTML Embed', 'oembed-api' ); ?></button>
+                                                       </li>
+                                               </ul>
+                                               <div id="wp-embed-share-tab-wordpress" class="wp-embed-share-tab" role="tabpanel" aria-labelledby="wp-embed-share-tab-button-wordpress" aria-hidden="false">
+                                                       <input type="text" value="<?php the_permalink(); ?>" class="wp-embed-share-input" tabindex="0" readonly/>
+
+                                                       <p class="wp-embed-share-description">
+                                                               <?php _e( 'Copy and paste this URL into your WordPress site to embed', 'oembed-api' ); ?>
+                                                       </p>
+                                               </div>
+                                               <div id="wp-embed-share-tab-html" class="wp-embed-share-tab" role="tabpanel" aria-labelledby="wp-embed-share-tab-button-html" aria-hidden="true">
+                                                       <textarea class="wp-embed-share-input" tabindex="0" readonly><?php echo esc_attr( get_post_embed_html( null, 600, 400 ) ); ?></textarea>
+
+                                                       <p class="wp-embed-share-description">
+                                                               <?php _e( 'Copy and paste this code into your site to embed', 'oembed-api' ); ?>
+                                                       </p>
+                                               </div>
+                                       </div>
+
+                                       <button type="button" class="wp-embed-share-dialog-close" aria-label="<?php esc_attr_e( 'Close sharing dialog', 'oembed-api' ); ?>">
+                                               <span class="dashicons dashicons-no"></span>
+                                       </button>
+                               </div>
+                       </div>
+               </div>
+               <?php
+       endwhile;
+else :
+       ?>
+       <div class="wp-embed">
+               <p class="wp-embed-heading"><?php _e( 'Page not found', 'oembed-api' ); ?></p>
+
+               <div class="wp-embed-excerpt">
+                       <p><?php _e( 'Error 404! The requested content was not found.', 'oembed-api' ) ?></p>
+               </div>
+
+               <div class="wp-embed-footer">
+                       <div class="wp-embed-site-title">
+                               <?php
+                               $site_icon_url = admin_url( 'images/w-logo-blue.png' );
+
+                               if ( function_exists( 'get_site_icon_url' ) ) {
+                                       $site_icon_url = get_site_icon_url( 32, $site_icon_url );
+                               }
+
+                               /**
+                                * Filters the site icon URL for use in the embed template.
+                                *
+                                * @param string $site_icon_url The site icon URL.
+                                */
+                               $site_icon_url = apply_filters( 'oembed_site_icon_url', $site_icon_url );
+
+                               printf(
+                                       '<a href="%s" target="_top"><img src="%s" width="32" height="32" alt="" class="wp-embed-site-icon"/><span>%s</span></a>',
+                                       esc_url( home_url() ),
+                                       esc_url( $site_icon_url ),
+                                       esc_attr( get_bloginfo( 'name' ) )
+                               );
+                               ?>
+                       </div>
+               </div>
+       </div>
+       <?php
+endif;
+
+/**
+ * Print scripts or data before the closing body tag in the embed template.
+ *
+ * @since 4.4.0
+ */
+do_action( 'oembed_footer' );
+?>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunksrcwpincludesjstinymcepluginswpoembedpluginjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/src/wp-includes/js/tinymce/plugins/wpoembed/plugin.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/tinymce/plugins/wpoembed/plugin.js                               (rev 0)
+++ trunk/src/wp-includes/js/tinymce/plugins/wpoembed/plugin.js 2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,17 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+(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 );
</ins></span></pre></div>
<a id="trunksrcwpincludesjswpoembedembedjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/src/wp-includes/js/wp-oembed-embed.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/wp-oembed-embed.js                               (rev 0)
+++ trunk/src/wp-includes/js/wp-oembed-embed.js 2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,162 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+(function ( window, document ) {
+       'use strict';
+
+       var secret = window.location.hash.replace( /.*secret=([\d\w]{10}).*/, '$1' ),
+               resizing;
+
+       function sendEmbedMessage( message, value ) {
+               window.parent.postMessage( {
+                       message: message,
+                       value: value,
+                       secret: secret
+               }, '*' );
+       }
+
+       function onLoad() {
+               var share_dialog = document.querySelector( '.wp-embed-share-dialog' ),
+                       share_dialog_open = document.querySelector( '.wp-embed-share-dialog-open' ),
+                       share_dialog_close = document.querySelector( '.wp-embed-share-dialog-close' ),
+                       share_input = document.querySelectorAll( '.wp-embed-share-input' ),
+                       share_dialog_tabs = document.querySelectorAll( '.wp-embed-share-tab-button button' ),
+                       links = document.getElementsByTagName( 'a' ),
+                       i;
+
+               if ( share_input ) {
+                       for ( i = 0; i < share_input.length; i++ ) {
+                               share_input[ i ].addEventListener( 'click', function ( e ) {
+                                       e.target.select();
+                               } );
+                       }
+               }
+
+               function openSharingDialog() {
+                       share_dialog.className = share_dialog.className.replace( 'hidden', '' );
+                       share_input[ 0 ].select();
+               }
+
+               function closeSharingDialog() {
+                       share_dialog.className += ' hidden';
+                       document.querySelector( '.wp-embed-share-dialog-open' ).focus();
+               }
+
+               if ( share_dialog_open ) {
+                       share_dialog_open.addEventListener( 'click', function ( e ) {
+                               openSharingDialog();
+                               e.preventDefault();
+                       } );
+               }
+
+               if ( share_dialog_close ) {
+                       share_dialog_close.addEventListener( 'click', function ( e ) {
+                               closeSharingDialog();
+                               e.preventDefault();
+                       } );
+               }
+
+               function shareClickHandler( e ) {
+                       var currentTab = document.querySelector( '.wp-embed-share-tab-button [aria-selected="true"]' );
+                       currentTab.setAttribute( 'aria-selected', 'false' );
+                       document.querySelector( '#' + currentTab.getAttribute( 'aria-controls' ) ).setAttribute( 'aria-hidden', 'true' );
+
+                       e.target.setAttribute( 'aria-selected', 'true' );
+                       document.querySelector( '#' + e.target.getAttribute( 'aria-controls' ) ).setAttribute( 'aria-hidden', 'false' );
+               }
+
+               function shareKeyHandler( e ) {
+                       var target = e.target,
+                               previousSibling = target.parentElement.previousElementSibling,
+                               nextSibling = target.parentElement.nextElementSibling,
+                               newTab, newTabChild;
+
+                       if ( 37 === e.keyCode ) {
+                               newTab = previousSibling;
+                       } else if ( 39 === e.keyCode ) {
+                               newTab = nextSibling;
+                       } else {
+                               return false;
+                       }
+
+                       if ( 'rtl' === document.documentElement.getAttribute( 'dir' ) ) {
+                               newTab = ( newTab === previousSibling ) ? nextSibling : previousSibling;
+                       }
+
+                       if ( newTab ) {
+                               newTabChild = newTab.firstElementChild;
+
+                               target.setAttribute( 'tabindex', '-1' );
+                               target.setAttribute( 'aria-selected', false );
+                               document.querySelector( '#' + target.getAttribute( 'aria-controls' ) ).setAttribute( 'aria-hidden', 'true' );
+
+                               newTabChild.setAttribute( 'tabindex', '0' );
+                               newTabChild.setAttribute( 'aria-selected', 'true' );
+                               newTabChild.focus();
+                               document.querySelector( '#' + newTabChild.getAttribute( 'aria-controls' ) ).setAttribute( 'aria-hidden', 'false' );
+                       }
+               }
+
+               if ( share_dialog_tabs ) {
+                       for ( i = 0; i < share_dialog_tabs.length; i++ ) {
+                               share_dialog_tabs[ i ].addEventListener( 'click', shareClickHandler );
+
+                               share_dialog_tabs[ i ].addEventListener( 'keydown', shareKeyHandler );
+                       }
+               }
+
+               document.addEventListener( 'keydown', function ( e ) {
+                       if ( e.keyCode === 27 && -1 === share_dialog.className.indexOf( 'hidden' ) ) {
+                               closeSharingDialog();
+                       }
+               }, false );
+
+               if ( window.self === window.top ) {
+                       return;
+               }
+
+               /**
+                * Send this document's height to the parent (embedding) site.
+                */
+               sendEmbedMessage( 'height', Math.ceil( document.body.getBoundingClientRect().height ) );
+
+               /**
+                * Detect clicks to external (_top) links.
+                */
+               function linkClickHandler( e ) {
+                       var target = e.target,
+                               href;
+                       if ( target.hasAttribute( 'href' ) ) {
+                               href = target.getAttribute( 'href' );
+                       } else {
+                               href = target.parentElement.getAttribute( 'href' );
+                       }
+
+                       /**
+                        * Send link target to the parent (embedding) site.
+                        */
+                       sendEmbedMessage( 'link', href );
+                       e.preventDefault();
+               }
+
+               for ( i = 0; i < links.length; i++ ) {
+                       links[ i ].addEventListener( 'click', linkClickHandler );
+               }
+       }
+
+       document.addEventListener( 'DOMContentLoaded', onLoad, false );
+
+       /**
+        * Iframe resize handler.
+        */
+       function onResize() {
+               if ( window.self === window.top ) {
+                       return;
+               }
+
+               clearTimeout( resizing );
+
+               resizing = setTimeout( function () {
+                       sendEmbedMessage( 'height', Math.ceil( document.body.getBoundingClientRect().height ) );
+               }, 100 );
+       }
+
+       window.addEventListener( 'resize', onResize, false );
+})( window, document );
</ins></span></pre></div>
<a id="trunksrcwpincludesjswpoembedjs"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/src/wp-includes/js/wp-oembed.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/wp-oembed.js                             (rev 0)
+++ trunk/src/wp-includes/js/wp-oembed.js       2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,67 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+(function ( window, document ) {
+       'use strict';
+
+       window.wp = window.wp || {};
+
+       if ( !! window.wp.receiveEmbedMessage ) {
+               return;
+       }
+
+       window.wp.receiveEmbedMessage = function( e ) {
+               var data = e.data;
+               if ( ! ( data.secret || data.message || data.value ) ) {
+                       return;
+               }
+
+               var iframes = document.querySelectorAll( '.wp-embedded-content[data-secret="' + data.secret + '"]' );
+
+               for ( var i = 0; i < iframes.length; i++ ) {
+                       var source = iframes[ i ];
+
+                       /* Resize the iframe on request. */
+                       if ( 'height' === data.message ) {
+                               var height = 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' === data.message ) {
+                               var sourceURL = document.createElement( 'a' ), targetURL = document.createElement( 'a' );
+                               sourceURL.href = source.getAttribute( 'src' );
+                               targetURL.href = data.value;
+
+                               /* Only continue if link hostname matches iframe's hostname. */
+                               if ( targetURL.host === sourceURL.host && document.activeElement === source ) {
+                                       window.top.location.href = data.value;
+                               }
+                       }
+               }
+       };
+
+       window.addEventListener( 'message', window.wp.receiveEmbedMessage, false );
+
+       function onLoad() {
+               var isIE10 = -1 !== navigator.appVersion.indexOf( 'MSIE 10' ),
+                       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 );
</ins></span></pre></div>
<a id="trunksrcwpincludesqueryphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/query.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/query.php   2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-includes/query.php     2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -719,6 +719,26 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Is the query for an embedded post?
+ *
+ * @since 4.4.0
+ *
+ * @global WP_Query $wp_query Global WP_Query instance.
+ *
+ * @return bool Whether we're in an embedded post or not.
+ */
+function is_embed() {
+       global $wp_query;
+
+       if ( ! isset( $wp_query ) ) {
+               _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+               return false;
+       }
+
+       return $wp_query->is_embed();
+}
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Is the query the main query?
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 3.3.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1201,6 +1221,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public $is_404 = false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Set if query is embed.
+        *
+        * @since 4.4.0
+        * @access public
+        * @var bool
+        */
+       public $is_embed = false;
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Set if query is within comments popup window.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 1.5.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1845,6 +1874,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                if ( '404' == $qv['error'] )
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->set_404();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->is_embed = isset( $qv['embed'] ) && ( $this->is_singular || $this->is_404 );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->query_vars_hash = md5( serialize( $this->query_vars ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->query_vars_changed = false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -4635,6 +4666,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Is the query for an embedded post?
+        *
+        * @since 3.1.0
+        *
+        * @return bool
+        */
+       public function is_embed() {
+               return (bool) $this->is_embed;
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Is the query the main query?
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 3.3.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -4935,6 +4977,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $link = user_trailingslashit( trailingslashit( $link ) . 'feed' );
</span><span class="cx" style="display: block; padding: 0 10px">                } elseif ( isset( $GLOBALS['wp_query']->query_vars['paged'] ) && $GLOBALS['wp_query']->query_vars['paged'] > 1 ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $link = user_trailingslashit( trailingslashit( $link ) . 'page/' . $GLOBALS['wp_query']->query_vars['paged'] );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                } elseif( is_embed() ) {
+                       $link = user_trailingslashit( trailingslashit( $link ) . 'embed' );
</ins><span class="cx" style="display: block; padding: 0 10px">                 } elseif ( is_404() ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        // Add rewrite endpoints if necessary.
</span><span class="cx" style="display: block; padding: 0 10px">                        foreach ( $wp_rewrite->endpoints as $endpoint ) {
</span></span></pre></div>
<a id="trunksrcwpincludesscriptloaderphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/script-loader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/script-loader.php   2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-includes/script-loader.php     2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -466,6 +466,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                ),
</span><span class="cx" style="display: block; padding: 0 10px">        ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $scripts->add( 'wp-oembed', "/wp-includes/js/wp-oembed$suffix.js" );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         // To enqueue media-views or media-editor, call wp_enqueue_media().
</span><span class="cx" style="display: block; padding: 0 10px">        // Both rely on numerous settings, styles, and templates to operate correctly.
</span><span class="cx" style="display: block; padding: 0 10px">        $scripts->add( 'media-views',  "/wp-includes/js/media-views$suffix.js",  array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement' ), false, 1 );
</span></span></pre></div>
<a id="trunksrcwpincludestemplateloaderphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/template-loader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/template-loader.php 2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-includes/template-loader.php   2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -39,6 +39,20 @@
</span><span class="cx" style="display: block; padding: 0 10px"> elseif ( is_trackback() ) :
</span><span class="cx" style="display: block; padding: 0 10px">        include( ABSPATH . 'wp-trackback.php' );
</span><span class="cx" style="display: block; padding: 0 10px">        return;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+elseif ( is_embed() ) :
+       $template = ABSPATH . WPINC . '/embed-template.php';
+
+       /**
+        * Filter the template used for embedded posts.
+        *
+        * @since 4.4.0
+        *
+        * @param string $template Path to the template file.
+        */
+       $template = apply_filters( 'embed_template', $template );
+
+       include ( $template );
+       return;
</ins><span class="cx" style="display: block; padding: 0 10px"> endif;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> if ( defined('WP_USE_THEMES') && WP_USE_THEMES ) :
</span></span></pre></div>
<a id="trunksrcwpsettingsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-settings.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-settings.php 2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/src/wp-settings.php   2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -147,6 +147,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/shortcodes.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/class-wp-embed.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/embed-functions.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require( ABSPATH . WPINC . '/class-wp-oembed-controller.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/media.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/http.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require( ABSPATH . WPINC . '/widgets.php' );
</span></span></pre></div>
<a id="trunktestsphpunitmultisitexml"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/multisite.xml</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/multisite.xml 2015-10-07 07:24:47 UTC (rev 34902)
+++ trunk/tests/phpunit/multisite.xml   2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -25,6 +25,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">             <group>ajax</group>
</span><span class="cx" style="display: block; padding: 0 10px">             <group>ms-files</group>
</span><span class="cx" style="display: block; padding: 0 10px">             <group>external-http</group>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            <group>oembed-headers</group>
</ins><span class="cx" style="display: block; padding: 0 10px">         </exclude>
</span><span class="cx" style="display: block; padding: 0 10px">     </groups>
</span><span class="cx" style="display: block; padding: 0 10px">     <php>
</span></span></pre></div>
<a id="trunktestsphpunittestsoembedcontrollerphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/oembed/controller.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/oembed/controller.php                           (rev 0)
+++ trunk/tests/phpunit/tests/oembed/controller.php     2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,273 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * @group oembed
+ */
+class Test_oEmbed_Controller extends WP_UnitTestCase {
+       function test_request_with_bad_url() {
+               $request = array(
+                       'url'      => '',
+                       'format'   => 'json',
+                       'maxwidth' => 600,
+               );
+
+               $legacy_controller = new WP_oEmbed_Controller();
+
+               $this->assertEquals( 'Invalid URL.', $legacy_controller->dispatch( $request ) );
+       }
+
+       function test_request_json() {
+               $user = $this->factory->user->create_and_get( array(
+                       'display_name' => 'John Doe',
+               ) );
+               $post = $this->factory->post->create_and_get( array(
+                       'post_author' => $user->ID,
+                       'post_title'  => 'Hello World',
+               ) );
+
+               // WP_Query arguments.
+               $request = array(
+                       'url'     => get_permalink( $post->ID ),
+                       'format'   => 'json',
+                       'maxwidth' => 400,
+                       'callback' => '',
+                       'oembed'   => true,
+               );
+
+               $legacy_controller = new WP_oEmbed_Controller();
+
+               $data = json_decode( $legacy_controller->dispatch( $request ), true );
+
+               $this->assertTrue( is_array( $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'] );
+       }
+
+       function test_request_jsonp() {
+               $user = $this->factory->user->create_and_get( array(
+                       'display_name' => 'John Doe',
+               ) );
+               $post = $this->factory->post->create_and_get( array(
+                       'post_author' => $user->ID,
+                       'post_title'  => 'Hello World',
+               ) );
+
+               $request = array(
+                       'url'     => get_permalink( $post->ID ),
+                       'format'   => 'json',
+                       'maxwidth' => 600,
+                       'callback' => 'mycallback',
+               );
+
+               $legacy_controller = new WP_oEmbed_Controller();
+
+               $data = $legacy_controller->dispatch( $request );
+
+               $this->assertEquals( 0, strpos( $data, '/**/mycallback(' ) );
+       }
+
+       function test_request_jsonp_invalid_callback() {
+               $user = $this->factory->user->create_and_get( array(
+                       'display_name' => 'John Doe',
+               ) );
+               $post = $this->factory->post->create_and_get( array(
+                       'post_author' => $user->ID,
+                       'post_title'  => 'Hello World',
+               ) );
+
+               $request = array(
+                       'url'     => get_permalink( $post->ID ),
+                       'format'   => 'json',
+                       'maxwidth' => 600,
+                       'callback' => array( 'foo', 'bar' ),
+               );
+
+               $legacy_controller = new WP_oEmbed_Controller();
+
+               $data = $legacy_controller->dispatch( $request );
+
+               $this->assertFalse( strpos( $data, '/**/' ) );
+       }
+
+       function test_request_json_invalid_data() {
+               $request = array(
+                       'callback' => '',
+               );
+
+               $legacy_controller = new WP_oEmbed_Controller();
+
+               $this->assertEquals( 'Not implemented',  $legacy_controller->json_response( null, $request ) );
+               $this->assertEquals( 'Not implemented',  $legacy_controller->json_response( 123, $request ) );
+               $this->assertEquals( 'Not implemented',  $legacy_controller->json_response( array(), $request ) );
+       }
+
+       function test_request_xml() {
+               $user = $this->factory->user->create_and_get( array(
+                       'display_name' => 'John Doe',
+               ) );
+               $post = $this->factory->post->create_and_get( array(
+                       'post_author' => $user->ID,
+                       'post_title'  => 'Hello World',
+               ) );
+
+               $request = array(
+                       'url'     => get_permalink( $post->ID ),
+                       'format'   => 'xml',
+                       'maxwidth' => 400,
+                       'callback' => '',
+               );
+
+               $legacy_controller = new WP_oEmbed_Controller();
+
+               $data = $legacy_controller->dispatch( $request );
+
+               $data = simplexml_load_string( $data );
+               $this->assertInstanceOf( 'SimpleXMLElement', $data );
+
+               $data = (array) $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'] );
+       }
+
+       function test_request_xml_invalid_data() {
+               $legacy_controller = new WP_oEmbed_Controller();
+
+               $this->assertEquals( 'Not implemented',  $legacy_controller->xml_response( null ) );
+               $this->assertEquals( 'Not implemented',  $legacy_controller->xml_response( 123 ) );
+               $this->assertEquals( 'Not implemented',  $legacy_controller->xml_response( array() ) );
+       }
+
+       /**
+        * @group multisite
+        */
+       function test_request_ms_child_in_root_blog() {
+               if ( ! is_multisite() ) {
+                       $this->markTestSkipped( __METHOD__ . ' is a multisite-only test.' );
+               }
+
+               $child = $this->factory->blog->create();
+
+               switch_to_blog( $child );
+
+               $post = $this->factory->post->create_and_get( array(
+                       'post_title'  => 'Hello Child Blog',
+               ) );
+
+               $request = array(
+                       'url'      => get_permalink( $post->ID ),
+                       'format'   => 'json',
+                       'maxwidth' => 600,
+                       'callback' => '',
+               );
+
+               $legacy_controller = new WP_oEmbed_Controller();
+
+               $data = json_decode( $legacy_controller->dispatch( $request ), true );
+
+               $this->assertInternalType( 'array', $data );
+               $this->assertNotEmpty( $data );
+
+               restore_current_blog();
+       }
+
+       function test_get_oembed_endpoint_url() {
+               $this->assertEquals( home_url() . '/?oembed=true', get_oembed_endpoint_url() );
+               $this->assertEquals( home_url() . '/?oembed=true', get_oembed_endpoint_url( '', 'json' ) );
+               $this->assertEquals( home_url() . '/?oembed=true', get_oembed_endpoint_url( '', 'xml' ) );
+
+               $post_id = $this->factory->post->create();
+               $url     = get_permalink( $post_id );
+
+               $this->assertEquals( home_url() . '/?oembed=true&url=' . $url, get_oembed_endpoint_url( $url ) );
+               $this->assertEquals( home_url() . '/?oembed=true&url=' . $url . '&format=xml', get_oembed_endpoint_url( $url, 'xml' ) );
+       }
+
+       function test_wp_oembed_ensure_format() {
+               $this->assertEquals( 'json', wp_oembed_ensure_format( 'json' ) );
+               $this->assertEquals( 'xml', wp_oembed_ensure_format( 'xml' ) );
+               $this->assertEquals( 'json', wp_oembed_ensure_format( 123 ) );
+               $this->assertEquals( 'json', wp_oembed_ensure_format( 'random' ) );
+               $this->assertEquals( 'json', wp_oembed_ensure_format( array() ) );
+       }
+
+       function test_oembed_create_xml() {
+               $actual = _oembed_create_xml( array(
+                       'foo'  => 'bar',
+                       'bar'  => 'baz',
+                       'ping' => 'pong',
+               ) );
+
+               $expected = '<oembed><foo>bar</foo><bar>baz</bar><ping>pong</ping></oembed>';
+
+               $this->assertStringEndsWith( $expected, trim( $actual ) );
+
+               $actual = _oembed_create_xml( array(
+                       'foo'  => array(
+                               'bar' => 'baz',
+                       ),
+                       'ping' => 'pong',
+               ) );
+
+               $expected = '<oembed><foo><bar>baz</bar></foo><ping>pong</ping></oembed>';
+
+               $this->assertStringEndsWith( $expected, trim( $actual ) );
+
+               $actual = _oembed_create_xml( array(
+                       'foo'   => array(
+                               'bar' => array(
+                                       'ping' => 'pong',
+                               ),
+                       ),
+                       'hello' => 'world',
+               ) );
+
+               $expected = '<oembed><foo><bar><ping>pong</ping></bar></foo><hello>world</hello></oembed>';
+
+               $this->assertStringEndsWith( $expected, trim( $actual ) );
+
+               $actual = _oembed_create_xml( array(
+                       array(
+                               'foo' => array(
+                                       'bar',
+                               ),
+                       ),
+                       'helloworld',
+               ) );
+
+               $expected = '<oembed><oembed><foo><oembed>bar</oembed></foo></oembed><oembed>helloworld</oembed></oembed>';
+
+               $this->assertStringEndsWith( $expected, trim( $actual ) );
+       }
+}
</ins></span></pre></div>
<a id="trunktestsphpunittestsoembeddiscoveryphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/oembed/discovery.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/oembed/discovery.php                            (rev 0)
+++ trunk/tests/phpunit/tests/oembed/discovery.php      2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,68 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * @group oembed
+ */
+class Tests_oEmbed_Discovery extends WP_UnitTestCase {
+       function test_add_oembed_discovery_links_non_singular() {
+               ob_start();
+               wp_oembed_add_discovery_links();
+               $actual = ob_get_clean();
+               $this->assertSame( '', $actual );
+       }
+
+       function test_add_oembed_discovery_links_to_post() {
+               $post_id = $this->factory->post->create();
+               $this->go_to( get_permalink( $post_id ) );
+
+               $this->assertQueryTrue( 'is_single', 'is_singular' );
+
+               ob_start();
+               wp_oembed_add_discovery_links();
+               $actual = ob_get_clean();
+
+               $expected = '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink() ) ) . '" />' . "\n";
+               $expected .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink(), 'xml' ) ) . '" />' . "\n";
+
+               $this->assertEquals( $expected, $actual );
+       }
+
+       function test_add_oembed_discovery_links_to_page() {
+               $post_id = $this->factory->post->create( array(
+                       'post_type' => 'page'
+               ));
+               $this->go_to( get_permalink( $post_id ) );
+
+               $this->assertQueryTrue( 'is_page', 'is_singular' );
+
+               ob_start();
+               wp_oembed_add_discovery_links();
+               $actual = ob_get_clean();
+
+               $expected = '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink() ) ) . '" />' . "\n";
+               $expected .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink(), 'xml' ) ) . '" />' . "\n";
+
+               $this->assertEquals( $expected, $actual );
+       }
+
+       function test_add_oembed_discovery_links_to_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_permalink( $attachment_id ) );
+
+               $this->assertQueryTrue( 'is_attachment', 'is_singular', 'is_single' );
+
+               ob_start();
+               wp_oembed_add_discovery_links();
+               $actual = ob_get_clean();
+
+               $expected = '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink() ) ) . '" />' . "\n";
+               $expected .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink(), 'xml' ) ) . '" />' . "\n";
+
+               $this->assertEquals( $expected, $actual );
+       }
+}
</ins></span></pre></div>
<a id="trunktestsphpunittestsoembedfilterResultphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/oembed/filterResult.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/oembed/filterResult.php                         (rev 0)
+++ trunk/tests/phpunit/tests/oembed/filterResult.php   2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,81 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * @group oembed
+ */
+class Tests_Filter_oEmbed_Result extends WP_UnitTestCase {
+       function test_filter_oembed_result_trusted_malicious_iframe() {
+               $html   = '<p></p><iframe onload="alert(1)"></iframe>';
+
+               $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   = '<p></p><iframe onload="alert(1)" src="http://example.com/sample-page/"></iframe>';
+               $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   = '<div><iframe></iframe><iframe></iframe><p></p></div>';
+               $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), '' );
+
+               $this->assertEquals( '<iframe sandbox="allow-scripts" security="restricted"></iframe>', $actual );
+       }
+
+       function test_filter_oembed_result_with_newlines() {
+               $html = <<<EOD
+<script>var = 1;</script>
+<iframe></iframe>
+<iframe></iframe>
+<p></p>
+EOD;
+
+               $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), '' );
+
+               $this->assertEquals( '<iframe sandbox="allow-scripts" security="restricted"></iframe>', $actual );
+       }
+
+       function test_filter_oembed_result_without_iframe() {
+               $html   = '<span>Hello</span><p>World</p>';
+               $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), '' );
+
+               $this->assertFalse( $actual );
+
+               $html   = '<div><p></p></div><script></script>';
+               $actual = wp_filter_oembed_result( $html, (object) array( 'type' => 'rich' ), '' );
+
+               $this->assertFalse( $actual );
+       }
+
+       function test_filter_oembed_result_secret_param_available() {
+               $html   = '<iframe src="https://wordpress.org"></iframe>';
+               $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' ), '' ) );
+       }
+}
</ins></span></pre></div>
<a id="trunktestsphpunittestsoembedgetResponseDataphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/oembed/getResponseData.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/oembed/getResponseData.php                              (rev 0)
+++ trunk/tests/phpunit/tests/oembed/getResponseData.php        2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,170 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * @group oembed
+ */
+class Tests_oEmbed_Response_Data extends WP_UnitTestCase {
+       function test_get_oembed_response_data_non_existent_post() {
+               $this->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_maxwidth_invalid() {
+               $post = $this->factory->post->create_and_get();
+
+               $data = get_oembed_response_data( $post, '400;" DROP TABLES' );
+
+               $this->assertEquals( 400, $data['width'] );
+               $this->assertEquals( 225, $data['height'] );
+
+               $data = get_oembed_response_data( $post, "lol this isn't even a number?!?!?" );
+
+               $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'] );
+       }
+}
</ins></span></pre></div>
<a id="trunktestsphpunittestsoembedheadersphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/oembed/headers.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/oembed/headers.php                              (rev 0)
+++ trunk/tests/phpunit/tests/oembed/headers.php        2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,66 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * @runTestsInSeparateProcesses
+ * @preserveGlobalState disabled
+ * @group oembed
+ * @group oembed-headers
+ */
+class Tests_oEmbed_HTTP_Headers extends WP_UnitTestCase {
+       function test_request_json_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'   => '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 ) );
+       }
+}
</ins></span></pre></div>
<a id="trunktestsphpunittestsoembedpostEmbedUrlphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/oembed/postEmbedUrl.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/oembed/postEmbedUrl.php                         (rev 0)
+++ trunk/tests/phpunit/tests/oembed/postEmbedUrl.php   2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,31 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * @group oembed
+ */
+class Tests_Post_Embed_URL extends WP_UnitTestCase {
+       function test_get_post_embed_url_non_existent_post() {
+               $embed_url = get_post_embed_url( 0 );
+               $this->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 );
+       }
+}
</ins></span></pre></div>
<a id="trunktestsphpunittestsoembedtemplatephp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/oembed/template.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/oembed/template.php                             (rev 0)
+++ trunk/tests/phpunit/tests/oembed/template.php       2015-10-07 10:35:18 UTC (rev 34903)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,257 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * @group oembed
+ */
+class Tests_Embed_Template extends WP_UnitTestCase {
+       function test_oembed_output_post() {
+               $user = $this->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(
+                       '&hellip; <a class="wp-embed-more" href="%s" target="_top">Read more</a>',
+                       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 = '<iframe sandbox="allow-scripts" security="restricted" src="' . esc_url( get_post_embed_url( $post_id ) ) . '" width="200" height="200" title="Embedded WordPress Post" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" class="wp-embedded-content"></iframe>';
+
+               $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' ) );
+       }
+}
</ins></span></pre>
</div>
</div>

</body>
</html>