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 8f9915570e..98fdbef5f2 100644 Binary files a/wp-includes/js/tinymce/wp-tinymce.js.gz and b/wp-includes/js/tinymce/wp-tinymce.js.gz differ 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' );