From 83c3e3e00eee7563a9f25bfba94c28514e8f0435 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Wed, 7 Oct 2015 10:36:25 +0000 Subject: [PATCH] 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 #32522. Built from https://develop.svn.wordpress.org/trunk@34903 git-svn-id: http://core.svn.wordpress.org/trunk@34868 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/admin-bar.php | 4 + wp-includes/class-wp-editor.php | 3 +- wp-includes/class-wp-embed.php | 5 +- wp-includes/class-wp-oembed-controller.php | 159 ++++++ wp-includes/class-wp-rewrite.php | 24 +- wp-includes/class-wp.php | 2 +- wp-includes/css/wp-oembed-embed.css | 359 ++++++++++++ wp-includes/css/wp-oembed-embed.min.css | 1 + wp-includes/default-filters.php | 29 + wp-includes/embed-functions.php | 526 ++++++++++++++++++ wp-includes/embed-template.php | 262 +++++++++ .../js/tinymce/plugins/wpoembed/plugin.js | 17 + .../js/tinymce/plugins/wpoembed/plugin.min.js | 1 + wp-includes/js/tinymce/wp-tinymce.js.gz | Bin 147536 -> 147640 bytes wp-includes/js/wp-oembed-embed.js | 162 ++++++ wp-includes/js/wp-oembed-embed.min.js | 1 + wp-includes/js/wp-oembed.js | 67 +++ wp-includes/js/wp-oembed.min.js | 1 + wp-includes/query.php | 44 ++ wp-includes/script-loader.php | 2 + wp-includes/template-loader.php | 14 + wp-includes/version.php | 2 +- wp-settings.php | 1 + 23 files changed, 1678 insertions(+), 8 deletions(-) create mode 100644 wp-includes/class-wp-oembed-controller.php create mode 100644 wp-includes/css/wp-oembed-embed.css create mode 100644 wp-includes/css/wp-oembed-embed.min.css create mode 100644 wp-includes/embed-template.php create mode 100644 wp-includes/js/tinymce/plugins/wpoembed/plugin.js create mode 100644 wp-includes/js/tinymce/plugins/wpoembed/plugin.min.js create mode 100644 wp-includes/js/wp-oembed-embed.js create mode 100644 wp-includes/js/wp-oembed-embed.min.js create mode 100644 wp-includes/js/wp-oembed.js create mode 100644 wp-includes/js/wp-oembed.min.js diff --git a/wp-includes/admin-bar.php b/wp-includes/admin-bar.php index a12e9c9e71..696c369978 100644 --- a/wp-includes/admin-bar.php +++ b/wp-includes/admin-bar.php @@ -898,6 +898,10 @@ function is_admin_bar_showing() { if ( defined('XMLRPC_REQUEST') || defined('DOING_AJAX') || defined('IFRAME_REQUEST') ) return false; + if ( is_embed() ) { + return false; + } + // Integrated into the admin. if ( is_admin() ) return true; diff --git a/wp-includes/class-wp-editor.php b/wp-includes/class-wp-editor.php index 911aaab540..8a6dc3bd02 100644 --- a/wp-includes/class-wp-editor.php +++ b/wp-includes/class-wp-editor.php @@ -401,7 +401,8 @@ final class _WP_Editors { 'wplink', 'wpdialogs', 'wptextpattern', - 'wpview' + 'wpview', + 'wpoembed', ); if ( ! self::$has_medialib ) { diff --git a/wp-includes/class-wp-embed.php b/wp-includes/class-wp-embed.php index d4b1ded4f0..730fc4fc91 100644 --- a/wp-includes/class-wp-embed.php +++ b/wp-includes/class-wp-embed.php @@ -233,12 +233,13 @@ class WP_Embed { * Filter whether to inspect the given URL for discoverable link tags. * * @since 2.9.0 + * @since 4.4.0 The default value changed to true. * * @see WP_oEmbed::discover() * - * @param bool $enable Whether to enable `` tag discovery. Default false. + * @param bool $enable Whether to enable `` tag discovery. Default true. */ - $attr['discover'] = ( apply_filters( 'embed_oembed_discover', false ) && author_can( $post_ID, 'unfiltered_html' ) ); + $attr['discover'] = ( apply_filters( 'embed_oembed_discover', true ) ); // Use oEmbed to get the HTML $html = wp_oembed_get( $url, $attr ); diff --git a/wp-includes/class-wp-oembed-controller.php b/wp-includes/class-wp-oembed-controller.php new file mode 100644 index 0000000000..0fc25ba817 --- /dev/null +++ b/wp-includes/class-wp-oembed-controller.php @@ -0,0 +1,159 @@ +get( 'oembed', false ) ) { + return; + } + + if ( false === $wp_query->get( 'url', false ) ) { + status_header( 400 ); + echo 'URL parameter missing'; + exit; + } + + $url = esc_url_raw( get_query_var( 'url' ) ); + + $format = wp_oembed_ensure_format( get_query_var( 'format' ) ); + + /** + * Filter the maxwidth oEmbed parameter. + * + * @since 4.4.0 + * + * @param int $maxwidth Maximum allowed width. Default 600. + */ + $maxwidth = apply_filters( 'oembed_default_width', 600 ); + $maxwidth = absint( get_query_var( 'maxwidth', $maxwidth ) ); + + $callback = get_query_var( '_jsonp', false ); + + $request = array( + 'url' => $url, + 'format' => $format, + 'maxwidth' => $maxwidth, + 'callback' => $callback, + ); + + echo $this->dispatch( $request ); + exit; + } + + /** + * Handle the whole request and print the response. + * + * @since 4.4.0 + * + * @param array $request The request arguments. + * @return string The oEmbed API response. + */ + public function dispatch( $request ) { + $post_id = url_to_postid( $request['url'] ); + + /** + * Filter the determined post id. + * + * @since 4.4.0 + * + * @param int $post_id The post ID. + * @param string $url The requestd URL. + */ + $post_id = apply_filters( 'oembed_request_post_id', $post_id, $request['url'] ); + + $data = get_oembed_response_data( $post_id, $request['maxwidth'] ); + + if ( false === $data ) { + status_header( 404 ); + return __( 'Invalid URL.', 'oembed-api' ); + } + + if ( 'json' === $request['format'] ) { + return $this->json_response( $data, $request ); + } + + return $this->xml_response( $data ); + } + + /** + * Print the oEmbed JSON response. + * + * @since 4.4.0 + * + * @param array $data The oEmbed response data. + * @param array $request The request arguments. + * @return string The JSON response data. + */ + public function json_response( $data, $request ) { + if ( ! is_string( $request['callback'] ) || preg_match( '/[^\w\.]/', $request['callback'] ) ) { + $request['callback'] = false; + } + + $result = wp_json_encode( $data ); + + // Bail if the result couldn't be JSON encoded. + if ( ! $result || ! is_array( $data ) || empty( $data ) ) { + status_header( 501 ); + return 'Not implemented'; + } + + if ( ! headers_sent() ) { + $content_type = $request['callback'] ? 'application/javascript' : 'application/json'; + header( 'Content-Type: ' . $content_type . '; charset=' . get_option( 'blog_charset' ) ); + header( 'X-Content-Type-Options: nosniff' ); + } + + if ( $request['callback'] ) { + return '/**/' . $request['callback'] . '(' . $result . ')'; + } + + return $result; + } + + /** + * Print the oEmbed XML response. + * + * @since 4.4.0 + * + * @param array $data The oEmbed response data. + * @return string The XML response data. + */ + public function xml_response( $data ) { + $result = _oembed_create_xml( $data ); + + // Bail if there's no XML. + if ( ! $result ) { + status_header( 501 ); + return 'Not implemented'; + } + + if ( ! headers_sent() ) { + header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ) ); + } + + return $result; + } +} diff --git a/wp-includes/class-wp-rewrite.php b/wp-includes/class-wp-rewrite.php index 84a57c8107..b7b3753dd4 100644 --- a/wp-includes/class-wp-rewrite.php +++ b/wp-includes/class-wp-rewrite.php @@ -861,6 +861,7 @@ class WP_Rewrite { $trackbackregex = 'trackback/?$'; $pageregex = $this->pagination_base . '/?([0-9]{1,})/?$'; $commentregex = $this->comments_pagination_base . '-([0-9]{1,})/?$'; + $embedregex = 'embed/?$'; //build up an array of endpoint regexes to append => queries to append if ( $endpoints ) { @@ -884,6 +885,8 @@ class WP_Rewrite { $index = $this->index; //probably 'index.php' $feedindex = $index; $trackbackindex = $index; + $embedindex = $index; + //build a list from the rewritecode and queryreplace arrays, that will look something like //tagname=$matches[i] where i is the current $i $queries = array(); @@ -1029,8 +1032,14 @@ class WP_Rewrite { //create query and regex for trackback $trackbackmatch = $match . $trackbackregex; $trackbackquery = $trackbackindex . '?' . $query . '&tb=1'; + + // Create query and regex for embeds. + $embedmatch = $match . $embedregex; + $embedquery = $embedindex . '?' . $query . '&embed=true'; + //trim slashes from the end of the regex for this dir $match = rtrim($match, '/'); + //get rid of brackets $submatchbase = str_replace( array('(', ')'), '', $match); @@ -1040,6 +1049,7 @@ class WP_Rewrite { $sub1feed = $sub1 . $feedregex; //and /feed/(atom|...) $sub1feed2 = $sub1 . $feedregex2; //and /(feed|atom...) $sub1comment = $sub1 . $commentregex; //and /comment-page-xx + $sub1embed = $sub1 . $embedregex; //and /embed/... //add another rule to match attachments in the explicit form: ///attachment/some-text @@ -1048,12 +1058,14 @@ class WP_Rewrite { $sub2feed = $sub2 . $feedregex; //feeds, /attachment/feed/(atom|...) $sub2feed2 = $sub2 . $feedregex2; //and feeds again on to this /attachment/(feed|atom...) $sub2comment = $sub2 . $commentregex; //and /comment-page-xx + $sub2embed = $sub2 . $embedregex; //and /embed/... //create queries for these extra tag-ons we've just dealt with $subquery = $index . '?attachment=' . $this->preg_index(1); $subtbquery = $subquery . '&tb=1'; $subfeedquery = $subquery . '&feed=' . $this->preg_index(2); $subcommentquery = $subquery . '&cpage=' . $this->preg_index(2); + $subembedquery = $subquery . '&embed=true'; //do endpoints for attachments if ( !empty($endpoints) ) { @@ -1092,10 +1104,16 @@ class WP_Rewrite { //add trackback $rewrite = array_merge(array($trackbackmatch => $trackbackquery), $rewrite); + // add embed + $rewrite = array_merge( array( $embedmatch => $embedquery ), $rewrite ); + //add regexes/queries for attachments, attachment trackbacks and so on - if ( ! $page ) //require /attachment/stuff form for pages because of confusion with subpages - $rewrite = array_merge($rewrite, array($sub1 => $subquery, $sub1tb => $subtbquery, $sub1feed => $subfeedquery, $sub1feed2 => $subfeedquery, $sub1comment => $subcommentquery)); - $rewrite = array_merge(array($sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery, $sub2comment => $subcommentquery), $rewrite); + if ( ! $page ) { + //require /attachment/stuff form for pages because of confusion with subpages + $rewrite = array_merge( $rewrite, array($sub1 => $subquery, $sub1tb => $subtbquery, $sub1feed => $subfeedquery, $sub1feed2 => $subfeedquery, $sub1comment => $subcommentquery, $sub1embed => $subembedquery ) ); + } + + $rewrite = array_merge( array( $sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery, $sub2comment => $subcommentquery, $sub2embed => $subembedquery ), $rewrite ); } } //if($num_toks) //add the rules for this dir to the accumulating $post_rewrite diff --git a/wp-includes/class-wp.php b/wp-includes/class-wp.php index 4fe275742d..bba47ffb71 100644 --- a/wp-includes/class-wp.php +++ b/wp-includes/class-wp.php @@ -15,7 +15,7 @@ class WP { * @access public * @var array */ - public $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type', 'title'); + public $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type', 'title', 'embed', 'oembed', 'format', 'url', '_jsonp', 'maxwidth' ); /** * Private query variables. diff --git a/wp-includes/css/wp-oembed-embed.css b/wp-includes/css/wp-oembed-embed.css new file mode 100644 index 0000000000..7c1be9b897 --- /dev/null +++ b/wp-includes/css/wp-oembed-embed.css @@ -0,0 +1,359 @@ +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; +} diff --git a/wp-includes/css/wp-oembed-embed.min.css b/wp-includes/css/wp-oembed-embed.min.css new file mode 100644 index 0000000000..2e36f2d500 --- /dev/null +++ b/wp-includes/css/wp-oembed-embed.min.css @@ -0,0 +1 @@ +body,html{padding:0;margin:0}body{font-family:sans-serif}.screen-reader-text{clip:rect(1px,1px,1px,1px);height:1px;overflow:hidden;position:absolute!important;width:1px}.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:#fff;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;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:10pc;margin-right:20px}.wp-embed p{margin:0}p.wp-embed-heading{margin:0 0 15px;font-weight:700;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:700;line-height:25px}.wp-embed-site-title a{position:relative;display:inline-block;padding-left:35px}.wp-embed-meta,.wp-embed-site-title{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,.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-close,.wp-embed-share-dialog-open{margin:-8px 0 0;padding:0;background:0 0;border:none;cursor:pointer;outline:0}.wp-embed-share-dialog-close .dashicons,.wp-embed-share-dialog-open .dashicons{padding:4px}.wp-embed-share-dialog-open .dashicons{top:8px}.wp-embed-share-dialog-close:focus .dashicons,.wp-embed-share-dialog-open: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:0 0;font-size:1pc;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],.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;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-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} \ No newline at end of file diff --git a/wp-includes/default-filters.php b/wp-includes/default-filters.php index c9eb06b133..20dbaeab91 100644 --- a/wp-includes/default-filters.php +++ b/wp-includes/default-filters.php @@ -422,4 +422,33 @@ add_action( 'media_buttons', 'media_buttons' ); add_filter( 'image_send_to_editor', 'image_add_caption', 20, 8 ); add_filter( 'media_send_to_editor', 'image_media_send_to_editor', 10, 3 ); +// Embeds + +add_action( 'parse_query', 'wp_oembed_parse_query' ); + +add_action( 'wp_head', 'wp_oembed_add_discovery_links' ); +add_action( 'wp_head', 'wp_oembed_add_host_js' ); + +add_action( 'oembed_head', 'print_emoji_detection_script' ); +add_action( 'oembed_head', 'print_emoji_styles' ); +add_action( 'oembed_head', '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 ); + unset( $filter, $action ); diff --git a/wp-includes/embed-functions.php b/wp-includes/embed-functions.php index 2fc255549b..ad5bfd711e 100644 --- a/wp-includes/embed-functions.php +++ b/wp-includes/embed-functions.php @@ -326,3 +326,529 @@ function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) { */ return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr ); } + +/** + * Parse an oEmbed API query. + * + * @since 4.4.0 + */ +function wp_oembed_parse_query( $wp_query ) { + $controller = new WP_oEmbed_Controller; + $controller->parse_query( $wp_query ); +} + +/** + * Adds oEmbed discovery links in the website . + * + * @since 4.4.0 + */ +function wp_oembed_add_discovery_links() { + $output = ''; + + if ( is_singular() ) { + $output .= '' . "\n"; + $output .= '' . "\n"; + } + + /** + * Filter the oEmbed discovery links. + * + * @since 4.4.0 + * + * @param string $output HTML of the discovery links. + */ + echo apply_filters( 'oembed_discovery_links', $output ); +} + +/** + * Add the necessary JavaScript to communicate with the embedded iframes. + * + * @since 4.4.0 + */ +function wp_oembed_add_host_js() { + wp_enqueue_script( 'wp-oembed' ); +} + + +/** + * Get the URL to embed a specific post in an iframe. + * + * @since 4.4.0 + * + * @param int|WP_Post $post Optional. Post ID or object. Defaults to the current post. + * @return string|false The post embed URL on success, false if the post doesn't exist. + */ +function get_post_embed_url( $post = null ) { + $post = get_post( $post ); + + if ( ! $post ) { + return false; + } + + if ( get_option( 'permalink_structure' ) ) { + $embed_url = trailingslashit( get_permalink( $post ) ) . user_trailingslashit( 'embed' ); + } else { + $embed_url = add_query_arg( array( 'embed' => 'true' ), get_permalink( $post ) ); + } + + /** + * Filter the URL to embed a specific post. + * + * @since 4.4.0 + * + * @param string $embed_url The post embed URL. + * @param WP_Post $post The corresponding post object. + */ + return esc_url_raw( apply_filters( 'post_embed_url', $embed_url, $post ) ); +} + +/** + * Get the oEmbed endpoint URL for a given permalink. + * + * Pass an empty string as the first argument + * to get the endpoint base URL. + * + * @since 4.4.0 + * + * @param string $permalink Optional. The permalink used for the `url` query arg. Default empty. + * @param string $format Optional. The requested response format. Default 'json'. + * @return string The oEmbed endpoint URL. + */ +function get_oembed_endpoint_url( $permalink = '', $format = 'json' ) { + $url = add_query_arg( array( 'oembed' => 'true' ), home_url( '/' ) ); + + if ( 'json' === $format ) { + $format = false; + } + + if ( '' !== $permalink ) { + $url = add_query_arg( array( + 'url' => $permalink, + 'format' => $format, + ), $url ); + } + + /** + * Filter the oEmbed endpoint URL. + * + * @since 4.4.0 + * + * @param string $url The URL to the oEmbed endpoint. + * @param string $permalink The permalink used for the `url` query arg. + * @param string $format The requested response format. + */ + return apply_filters( 'oembed_endpoint_url', $url, $permalink, $format ); +} + +/** + * Get the embed code for a specific post. + * + * @since 4.4.0 + * + * @param int|WP_Post $post Optional. Post ID or object. Default is global `$post`. + * @param int $width The width for the response. + * @param int $height The height for the response. + * @return string|false Embed code on success, false if post doesn't exist. + */ +function get_post_embed_html( $post = null, $width, $height ) { + $post = get_post( $post ); + + if ( ! $post ) { + return false; + } + + $embed_url = get_post_embed_url( $post ); + + $output = ""; + + $output .= sprintf( + '', + esc_url( $embed_url ), + absint( $width ), + absint( $height ), + esc_attr__( 'Embedded WordPress Post', 'oembed-api' ) + ); + + /** + * Filters the oEmbed HTML output. + * + * @since 4.4.0 + * + * @param string $output The default HTML. + * @param WP_Post $post Current post object. + * @param int $width Width of the response. + * @param int $height Height of the response. + */ + return apply_filters( 'oembed_html', $output, $post, $width, $height ); +} + +/** + * Get the oEmbed response data for a given post. + * + * @since 4.4.0 + * + * @param WP_Post|int $post Optional. Post object or ID. Default is global `$post`. + * @param int $width The requested width. + * @return array|false Response data on success, false if post doesn't exist. + */ +function get_oembed_response_data( $post = null, $width ) { + $post = get_post( $post ); + + if ( ! $post ) { + return false; + } + + if ( 'publish' !== get_post_status( $post ) ) { + return false; + } + + /** + * Filter the allowed minimum width for the oEmbed response. + * + * @param int $width The minimum width. Defaults to 200. + */ + $minwidth = apply_filters( 'oembed_minwidth', 200 ); + + /** + * Filter the allowed maximum width for the oEmbed response. + * + * @param int $width The maximum width. Defaults to 600. + */ + $maxwidth = apply_filters( 'oembed_maxwidth', 600 ); + + if ( $width < $minwidth ) { + $width = $minwidth; + } else if ( $width > $maxwidth ) { + $width = $maxwidth; + } + + $height = ceil( $width / 16 * 9 ); + + if ( 200 > $height ) { + $height = 200; + } + + $data = array( + 'version' => '1.0', + 'provider_name' => get_bloginfo( 'name' ), + 'provider_url' => get_home_url(), + 'author_name' => get_bloginfo( 'name' ), + 'author_url' => get_home_url(), + 'title' => $post->post_title, + 'type' => 'link', + ); + + $author = get_userdata( $post->post_author ); + + if ( $author ) { + $data['author_name'] = $author->display_name; + $data['author_url'] = get_author_posts_url( $author->ID ); + } + + /** + * Filter the oEmbed response data. + * + * @since 4.4.0 + * + * @param array $data The response data. + * @param WP_Post $post The post object. + * @param int $width The requested width. + * @param int $height The calculated height. + */ + return apply_filters( 'oembed_response_data', $data, $post, $width, $height ); +} + +/** + * Filters the oEmbed response data to return an iframe embed code. + * + * @since 4.4.0 + * + * @param array $data The response data. + * @param WP_Post $post The post object. + * @param int $width The requested width. + * @param int $height The calculated height. + * @return array The modified response data. + */ +function get_oembed_response_data_rich( $data, $post, $width, $height ) { + $data['width'] = absint( $width ); + $data['height'] = absint( $height ); + $data['type'] = 'rich'; + $data['html'] = get_post_embed_html( $post, $width, $height ); + + // Add post thumbnail to response if available. + $thumbnail_id = false; + + if ( has_post_thumbnail( $post->ID ) ) { + $thumbnail_id = get_post_thumbnail_id( $post->ID ); + } + + if ( 'attachment' === get_post_type( $post ) ) { + if ( wp_attachment_is_image( $post ) ) { + $thumbnail_id = $post->ID; + } else if ( wp_attachment_is( 'video', $post ) ) { + $thumbnail_id = get_post_thumbnail_id( $post ); + $data['type'] = 'video'; + } + } + + if ( $thumbnail_id ) { + list( $thumbnail_url, $thumbnail_width, $thumbnail_height ) = wp_get_attachment_image_src( $thumbnail_id, array( $width, 99999 ) ); + $data['thumbnail_url'] = $thumbnail_url; + $data['thumbnail_width'] = $thumbnail_width; + $data['thumbnail_height'] = $thumbnail_height; + } + + return $data; +} + +/** + * Ensures that the specified format is either 'json' or 'xml'. + * + * @since 4.4.0 + * + * @param string $format The oEmbed response format. Accepts 'json', 'xml'. + * @return string The format, either 'xml' or 'json'. Default 'json'. + */ +function wp_oembed_ensure_format( $format ) { + if ( ! in_array( $format, array( 'json', 'xml' ), true ) ) { + return 'json'; + } + + return $format; +} + +/** + * Creates an XML string from a given array. + * + * @since 4.4.0 + * @access private + * + * @param array $data The original oEmbed response data. + * @param SimpleXMLElement $node Optional. XML node to append the result to recursively. + * @return string|false XML string on success, false on error. + */ +function _oembed_create_xml( $data, $node = null ) { + if ( ! is_array( $data ) || empty( $data ) ) { + return false; + } + + if ( null === $node ) { + $node = new SimpleXMLElement( '' ); + } + + foreach ( $data as $key => $value ) { + if ( is_numeric( $key ) ) { + $key = 'oembed'; + } + + if ( is_array( $value ) ) { + $item = $node->addChild( $key ); + _oembed_create_xml( $value, $item ); + } else { + $node->addChild( $key, esc_html( $value ) ); + } + } + + return $node->asXML(); +} + +/** + * Filters the returned oEmbed HTML. + * + * If the $url isn't on the trusted providers list, + * we need to filter the HTML heavily for security. + * + * Only filters 'rich' and 'html' response types. + * + * @since 4.4.0 + * + * @param string $return The returned oEmbed HTML. + * @param object $data A data object result from an oEmbed provider. + * @param string $url The URL of the content to be embedded. + * @return string The filtered and sanitized oEmbed result. + */ +function wp_filter_oembed_result( $return, $data, $url ) { + if ( false === $return || ! in_array( $data->type, array( 'rich', 'video' ) ) ) { + return $return; + } + + require_once( ABSPATH . WPINC . '/class-oembed.php' ); + $wp_oembed = _wp_oembed_get_object(); + + // Don't modify the HTML for trusted providers. + if ( false !== $wp_oembed->get_provider( $url, array( 'discover' => false ) ) ) { + return $return; + } + + $allowed_html = array( + 'iframe' => array( + 'src' => true, + 'width' => true, + 'height' => true, + 'frameborder' => true, + 'marginwidth' => true, + 'marginheight' => true, + 'scrolling' => true, + 'title' => true, + 'class' => true, + ), + ); + + $html = wp_kses( $return, $allowed_html ); + preg_match( '|^.*().*$|m', $html, $iframes ); + + if ( empty( $iframes ) ) { + return false; + } + + $html = str_replace( '%s', + 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() { + ?> + + + + + +> + + <?php wp_title( '-', true, 'right' ); ?> + + tag. + * + * @since 4.4.0 + */ + do_action( 'oembed_head' ); + ?> + +> + $data ) { + if ( $data['width'] / $data['height'] > $aspect_ratio ) { + $aspect_ratio = $data['width'] / $data['height']; + $measurements = array( $data['width'], $data['height'] ); + $image_size = $size; + } + } + } + + /** + * Filter the thumbnail image size for use in the embed template. + * + * @param string $image_size Thumbnail image size. + */ + $image_size = apply_filters( 'oembed_thumbnail_image_size', $image_size ); + + $shape = $measurements[0] / $measurements[1] >= 1.75 ? 'rectangular' : 'square'; + + /** + * Filter the thumbnail shape for use in the embed template. + * + * Rectangular images are shown above the title + * while square images are shown next to the content. + * + * @since 4.4.0 + * + * @param string $shape Thumbnail image shape. Either 'rectangular' or 'square'. + */ + $shape = apply_filters( 'oembed_thumbnail_image_shape', $shape ); + } + ?> +
> + + + + +

+ + + +

+ + + + + +
+ + + + + +
+ +
+

+ +
+

+
+ + +
+ + + diff --git a/wp-includes/js/tinymce/plugins/wpoembed/plugin.js b/wp-includes/js/tinymce/plugins/wpoembed/plugin.js new file mode 100644 index 0000000000..3572426fff --- /dev/null +++ b/wp-includes/js/tinymce/plugins/wpoembed/plugin.js @@ -0,0 +1,17 @@ +(function ( tinymce ) { + 'use strict'; + + tinymce.PluginManager.add( 'wpoembed', function ( editor, url ) { + editor.on( 'init', function () { + var scriptId = editor.dom.uniqueId(); + + var scriptElm = editor.dom.create( 'script', { + id: scriptId, + type: 'text/javascript', + src: url + '/../../../wp-oembed.js' + } ); + + editor.getDoc().getElementsByTagName( 'head' )[ 0 ].appendChild( scriptElm ); + } ); + } ); +})( window.tinymce ); diff --git a/wp-includes/js/tinymce/plugins/wpoembed/plugin.min.js b/wp-includes/js/tinymce/plugins/wpoembed/plugin.min.js new file mode 100644 index 0000000000..70cac50b69 --- /dev/null +++ b/wp-includes/js/tinymce/plugins/wpoembed/plugin.min.js @@ -0,0 +1 @@ +!function(a){"use strict";a.PluginManager.add("wpoembed",function(a,b){a.on("init",function(){var c=a.dom.uniqueId(),d=a.dom.create("script",{id:c,type:"text/javascript",src:b+"/../../../wp-oembed.js"});a.getDoc().getElementsByTagName("head")[0].appendChild(d)})})}(window.tinymce); \ No newline at end of file diff --git a/wp-includes/js/tinymce/wp-tinymce.js.gz b/wp-includes/js/tinymce/wp-tinymce.js.gz index 8f9915570e6b9cfd9bec5aac2624d98ee9225365..98fdbef5f2986004154b87370ac30e6ec19636a8 100644 GIT binary patch delta 15407 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

}F%jDB|^XYKsqC?1mN&boyWrdH>Rg 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 UWFDTuaSQza1EvdLS%t+00OR=>0RR91 diff --git a/wp-includes/js/wp-oembed-embed.js b/wp-includes/js/wp-oembed-embed.js new file mode 100644 index 0000000000..847ebcfd95 --- /dev/null +++ b/wp-includes/js/wp-oembed-embed.js @@ -0,0 +1,162 @@ +(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 ); diff --git a/wp-includes/js/wp-oembed-embed.min.js b/wp-includes/js/wp-oembed-embed.min.js new file mode 100644 index 0000000000..6ef2a22627 --- /dev/null +++ b/wp-includes/js/wp-oembed-embed.min.js @@ -0,0 +1 @@ +!function(a,b){"use strict";function c(b,c){a.parent.postMessage({message:b,value:c,secret:g},"*")}function d(){function d(){j.className=j.className.replace("hidden",""),m[0].select()}function e(){j.className+=" hidden",b.querySelector(".wp-embed-share-dialog-open").focus()}function f(a){var c=b.querySelector('.wp-embed-share-tab-button [aria-selected="true"]');c.setAttribute("aria-selected","false"),b.querySelector("#"+c.getAttribute("aria-controls")).setAttribute("aria-hidden","true"),a.target.setAttribute("aria-selected","true"),b.querySelector("#"+a.target.getAttribute("aria-controls")).setAttribute("aria-hidden","false")}function g(a){var c,d,e=a.target,f=e.parentElement.previousElementSibling,g=e.parentElement.nextElementSibling;if(37===a.keyCode)c=f;else{if(39!==a.keyCode)return!1;c=g}"rtl"===b.documentElement.getAttribute("dir")&&(c=c===f?g:f),c&&(d=c.firstElementChild,e.setAttribute("tabindex","-1"),e.setAttribute("aria-selected",!1),b.querySelector("#"+e.getAttribute("aria-controls")).setAttribute("aria-hidden","true"),d.setAttribute("tabindex","0"),d.setAttribute("aria-selected","true"),d.focus(),b.querySelector("#"+d.getAttribute("aria-controls")).setAttribute("aria-hidden","false"))}function h(a){var b,d=a.target;b=d.hasAttribute("href")?d.getAttribute("href"):d.parentElement.getAttribute("href"),c("link",b),a.preventDefault()}var i,j=b.querySelector(".wp-embed-share-dialog"),k=b.querySelector(".wp-embed-share-dialog-open"),l=b.querySelector(".wp-embed-share-dialog-close"),m=b.querySelectorAll(".wp-embed-share-input"),n=b.querySelectorAll(".wp-embed-share-tab-button button"),o=b.getElementsByTagName("a");if(m)for(i=0;i 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 ); diff --git a/wp-includes/js/wp-oembed.min.js b/wp-includes/js/wp-oembed.min.js new file mode 100644 index 0000000000..71775415f4 --- /dev/null +++ b/wp-includes/js/wp-oembed.min.js @@ -0,0 +1 @@ +!function(a,b){"use strict";function c(){var a=-1!==navigator.appVersion.indexOf("MSIE 10"),c=!!navigator.userAgent.match(/Trident.*rv\:11\./);if(a||c)for(var d,e=b.querySelectorAll(".wp-embedded-content[security]"),f=0;f1e3?h=1e3:200>h&&(h=200),g.height=h+"px"}if("link"===d.message){var i=b.createElement("a"),j=b.createElement("a");i.href=g.getAttribute("src"),j.href=d.value,j.host===i.host&&b.activeElement===g&&(a.top.location.href=d.value)}}},a.addEventListener("message",a.wp.receiveEmbedMessage,!1),b.addEventListener("DOMContentLoaded",c,!1))}(window,document); \ No newline at end of file diff --git a/wp-includes/query.php b/wp-includes/query.php index 69310345d5..94e48391d9 100644 --- a/wp-includes/query.php +++ b/wp-includes/query.php @@ -718,6 +718,26 @@ function is_404() { return $wp_query->is_404(); } +/** + * 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(); +} + /** * Is the query the main query? * @@ -1200,6 +1220,15 @@ class WP_Query { */ public $is_404 = false; + /** + * Set if query is embed. + * + * @since 4.4.0 + * @access public + * @var bool + */ + public $is_embed = false; + /** * Set if query is within comments popup window. * @@ -1845,6 +1874,8 @@ class WP_Query { if ( '404' == $qv['error'] ) $this->set_404(); + $this->is_embed = isset( $qv['embed'] ) && ( $this->is_singular || $this->is_404 ); + $this->query_vars_hash = md5( serialize( $this->query_vars ) ); $this->query_vars_changed = false; @@ -4634,6 +4665,17 @@ class WP_Query { return (bool) $this->is_404; } + /** + * Is the query for an embedded post? + * + * @since 3.1.0 + * + * @return bool + */ + public function is_embed() { + return (bool) $this->is_embed; + } + /** * Is the query the main query? * @@ -4935,6 +4977,8 @@ function wp_old_slug_redirect() { $link = user_trailingslashit( trailingslashit( $link ) . 'feed' ); } elseif ( isset( $GLOBALS['wp_query']->query_vars['paged'] ) && $GLOBALS['wp_query']->query_vars['paged'] > 1 ) { $link = user_trailingslashit( trailingslashit( $link ) . 'page/' . $GLOBALS['wp_query']->query_vars['paged'] ); + } elseif( is_embed() ) { + $link = user_trailingslashit( trailingslashit( $link ) . 'embed' ); } elseif ( is_404() ) { // Add rewrite endpoints if necessary. foreach ( $wp_rewrite->endpoints as $endpoint ) { diff --git a/wp-includes/script-loader.php b/wp-includes/script-loader.php index 4c802f36ee..4035525fc8 100644 --- a/wp-includes/script-loader.php +++ b/wp-includes/script-loader.php @@ -466,6 +466,8 @@ function wp_default_scripts( &$scripts ) { ), ) ); + $scripts->add( 'wp-oembed', "/wp-includes/js/wp-oembed$suffix.js" ); + // To enqueue media-views or media-editor, call wp_enqueue_media(). // Both rely on numerous settings, styles, and templates to operate correctly. $scripts->add( 'media-views', "/wp-includes/js/media-views$suffix.js", array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement' ), false, 1 ); diff --git a/wp-includes/template-loader.php b/wp-includes/template-loader.php index 95216fe5e0..d3eebe93ed 100644 --- a/wp-includes/template-loader.php +++ b/wp-includes/template-loader.php @@ -39,6 +39,20 @@ elseif ( is_feed() ) : elseif ( is_trackback() ) : include( ABSPATH . 'wp-trackback.php' ); return; +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; endif; if ( defined('WP_USE_THEMES') && WP_USE_THEMES ) : diff --git a/wp-includes/version.php b/wp-includes/version.php index 95d7f7dbdb..b705caab0d 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.4-alpha-34902'; +$wp_version = '4.4-alpha-34903'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. diff --git a/wp-settings.php b/wp-settings.php index d2c8b0173a..26ef9885c2 100644 --- a/wp-settings.php +++ b/wp-settings.php @@ -147,6 +147,7 @@ require( ABSPATH . WPINC . '/canonical.php' ); require( ABSPATH . WPINC . '/shortcodes.php' ); require( ABSPATH . WPINC . '/class-wp-embed.php' ); require( ABSPATH . WPINC . '/embed-functions.php' ); +require( ABSPATH . WPINC . '/class-wp-oembed-controller.php' ); require( ABSPATH . WPINC . '/media.php' ); require( ABSPATH . WPINC . '/http.php' ); require( ABSPATH . WPINC . '/widgets.php' );