diff options
Diffstat (limited to 'plugins/jetpack/modules/shortcodes')
40 files changed, 2259 insertions, 1487 deletions
diff --git a/plugins/jetpack/modules/shortcodes/archiveorg-book.php b/plugins/jetpack/modules/shortcodes/archiveorg-book.php index 88ac328c..013e7924 100644 --- a/plugins/jetpack/modules/shortcodes/archiveorg-book.php +++ b/plugins/jetpack/modules/shortcodes/archiveorg-book.php @@ -4,7 +4,7 @@ * * Usage: * [archiveorg-book goodytwoshoes00newyiala] - * [archiveorg-book http://www.archive.org/stream/goodytwoshoes00newyiala] + * [archiveorg-book https://www.archive.org/stream/goodytwoshoes00newyiala] * [archiveorg id=goodytwoshoes00newyiala width=480 height=430] * <iframe src='https://www.archive.org/stream/goodytwoshoes00newyiala?ui=embed#mode/1up' width='480px' height='430px' frameborder='0' ></iframe> @@ -76,9 +76,11 @@ function jetpack_archiveorg_book_shortcode( $atts ) { $height = intval( $atts['height'] ); } - $url = esc_url( set_url_scheme( "http://archive.org/stream/{$id}?ui=embed#mode/1up" ) ); + $url = esc_url( "https://archive.org/stream/{$id}?ui=embed#mode/1up" ); - $html = "<div class='embed-archiveorg-book' style='text-align:center;'><iframe src='$url' width='$width' height='$height' style='border:0;' webkitallowfullscreen='true' mozallowfullscreen='true' allowfullscreen></iframe></div>"; + $title = esc_html__( 'Archive.org Book', 'jetpack' ); + + $html = "<div class='embed-archiveorg-book' style='text-align:center;'><iframe title='$title' src='$url' width='$width' height='$height' style='border:0;' webkitallowfullscreen='true' mozallowfullscreen='true' allowfullscreen></iframe></div>"; return $html; } diff --git a/plugins/jetpack/modules/shortcodes/archiveorg.php b/plugins/jetpack/modules/shortcodes/archiveorg.php index 4a335b32..f3e0e2af 100644 --- a/plugins/jetpack/modules/shortcodes/archiveorg.php +++ b/plugins/jetpack/modules/shortcodes/archiveorg.php @@ -90,9 +90,11 @@ function jetpack_archiveorg_shortcode( $atts ) { $poster = ''; } - $url = esc_url( set_url_scheme( "https://archive.org/embed/{$id}{$autoplay}{$poster}" ) ); + $url = esc_url( "https://archive.org/embed/{$id}{$autoplay}{$poster}" ); - $html = "<div class='embed-archiveorg' style='text-align:center;'><iframe src='$url' width='$width' height='$height' style='border:0;' webkitallowfullscreen='true' mozallowfullscreen='true' allowfullscreen></iframe></div>"; + $title = esc_html__( 'Archive.org', 'jetpack' ); + + $html = "<div class='embed-archiveorg' style='text-align:center;'><iframe title='$title' src='$url' width='$width' height='$height' style='border:0;' webkitallowfullscreen='true' mozallowfullscreen='true' allowfullscreen></iframe></div>"; return $html; } diff --git a/plugins/jetpack/modules/shortcodes/brightcove.php b/plugins/jetpack/modules/shortcodes/brightcove.php index 5eca5293..4a08b9a8 100644 --- a/plugins/jetpack/modules/shortcodes/brightcove.php +++ b/plugins/jetpack/modules/shortcodes/brightcove.php @@ -1,5 +1,7 @@ <?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName +use Automattic\Jetpack\Assets; + /** * Brightcove shortcode. * @@ -51,7 +53,7 @@ class Jetpack_Brightcove_Shortcode { * The latest: [shortcode a=1 b=2] and the legacy: [shortcode a=1&b=2] * For an old shortcode: [shortcode a=1&b=2&c=3], it would be parsed into array( 'a' => 1&b=2&c=3' ), which is useless. * However, since we want to determine whether to call convert_to_legacy_studio() or convert_to_new_studio() via passed parameters, we still need to parse the two properly. - * See http://jetpack.wp-a2z.org/oik_api/shortcode_new_to_old_params/ + * See https://jetpack.wp-a2z.org/oik_api/shortcode_new_to_old_params/ * * @since 4.5.0 * @@ -251,7 +253,7 @@ class Jetpack_Brightcove_Shortcode { if ( $html5 ) { wp_enqueue_script( 'brightcove-loader', - Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/brightcove.min.js', 'modules/shortcodes/js/brightcove.js' ), + Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/brightcove.min.js', 'modules/shortcodes/js/brightcove.js' ), array( 'jquery' ), 20121127, false diff --git a/plugins/jetpack/modules/shortcodes/class.filter-embedded-html-objects.php b/plugins/jetpack/modules/shortcodes/class.filter-embedded-html-objects.php index 43e6ca18..5c9d2364 100644 --- a/plugins/jetpack/modules/shortcodes/class.filter-embedded-html-objects.php +++ b/plugins/jetpack/modules/shortcodes/class.filter-embedded-html-objects.php @@ -222,17 +222,22 @@ class Filter_Embedded_HTML_Objects { * @param array $matches Array of matches. */ private static function dispatch_entities( $matches ) { - $matches[0] = html_entity_decode( $matches[0] ); + $orig_html = $matches[0]; + $decoded_matches = array( html_entity_decode( $matches[0] ) ); - return self::dispatch( $matches ); + return self::dispatch( $decoded_matches, $orig_html ); } /** * Filter and replace HTML element. * - * @param array $matches Array of matches. + * @param array $matches Array of matches. + * @param string $orig_html Original html. Returned if no results are found via $matches processing. */ - private static function dispatch( $matches ) { + private static function dispatch( $matches, $orig_html = null ) { + if ( null === $orig_html ) { + $orig_html = $matches[0]; + } $html = preg_replace( '%�*58;//%', '://', $matches[0] ); $attrs = self::get_attrs( $html ); if ( isset( $attrs['src'] ) ) { @@ -253,7 +258,7 @@ class Filter_Embedded_HTML_Objects { } } - return $matches[0]; + return $orig_html; } $src = trim( $src ); @@ -299,11 +304,11 @@ class Filter_Embedded_HTML_Objects { // Keep the failed match so we can later replace it with a link, // but return the original content to give others a chance too. self::$failed_embeds[] = array( - 'match' => $matches[0], + 'match' => $orig_html, 'src' => esc_url( $src ), ); - return $matches[0]; + return $orig_html; } /** diff --git a/plugins/jetpack/modules/shortcodes/crowdsignal.php b/plugins/jetpack/modules/shortcodes/crowdsignal.php index e2078a68..04177919 100644 --- a/plugins/jetpack/modules/shortcodes/crowdsignal.php +++ b/plugins/jetpack/modules/shortcodes/crowdsignal.php @@ -1,610 +1,766 @@ -<?php - -// Keep compatibility with polldaddy-plugin -if ( ! class_exists( 'CrowdsignalShortcode' ) && ! class_exists( 'PolldaddyShortcode' ) ) { - +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName /** -* Class wrapper for Crowdsignal shortcodes -*/ + * Crowdsignal (PollDaddy) shortcode. + * + * Formats: + * [polldaddy type="iframe" survey="EB151947E5950FCF" height="auto" domain="jeherve" id="a-survey-with-branches"] + * [crowdsignal type="iframe" survey="EB151947E5950FCF" height="auto" domain="jeherve" id="a-survey-with-branches"] + * https://polldaddy.com/poll/7910844/ + * https://jeherve.survey.fm/a-survey + * https://jeherve.survey.fm/a-survey-with-branches + * [crowdsignal type="iframe" survey="7676FB1FF2B56CE9" height="auto" domain="jeherve" id="a-survey"] + * [crowdsignal survey="7676FB1FF2B56CE9"] + * [polldaddy survey="7676FB1FF2B56CE9"] + * [crowdsignal poll=9541291] + * [crowdsignal poll=9541291 type=slider] + * [crowdsignal rating=8755352] + * + * @package Jetpack + */ + +use Automattic\Jetpack\Assets; +use Automattic\Jetpack\Constants; + +// Keep compatibility with the PollDaddy plugin. +if ( + ! class_exists( 'CrowdsignalShortcode' ) + && ! class_exists( 'PolldaddyShortcode' ) +) { + /** + * Class wrapper for Crowdsignal shortcodes + */ + class CrowdsignalShortcode { -class CrowdsignalShortcode { + /** + * Should the Crowdsignal JavaScript be added to the page? + * + * @var bool + */ + private static $add_script = false; - static $add_script = false; - static $scripts = false; + /** + * Array of Polls / Surveys present on the page, and that need to be added. + * + * @var bool|array + */ + private static $scripts = false; + + /** + * Add all the actions & register the shortcode. + */ + public function __construct() { + add_action( 'init', array( $this, 'register_scripts' ) ); - /** - * Add all the actions & resgister the shortcode - */ - function __construct() { - if ( defined( 'GLOBAL_TAGS' ) == false ) { add_shortcode( 'crowdsignal', array( $this, 'crowdsignal_shortcode' ) ); - add_shortcode( 'polldaddy', array( $this, 'crowdsignal_shortcode' ) ); + add_shortcode( 'polldaddy', array( $this, 'polldaddy_shortcode' ) ); add_filter( 'pre_kses', array( $this, 'crowdsignal_embed_to_shortcode' ) ); + add_action( 'wp_enqueue_scripts', array( $this, 'check_infinite' ) ); + add_action( 'infinite_scroll_render', array( $this, 'crowdsignal_shortcode_infinite' ), 11 ); } - add_action( 'wp_enqueue_scripts', array( $this, 'check_infinite' ) ); - add_action( 'infinite_scroll_render', array( $this, 'crowdsignal_shortcode_infinite' ), 11 ); - } - private function get_async_code( array $settings, $survey_link ) { - $include = <<<CONTAINER -( function( d, c, j ) { - if ( !d.getElementById( j ) ) { - var pd = d.createElement( c ), s; - pd.id = j; - pd.src = 'https://polldaddy.com/survey.js'; - s = d.getElementsByTagName( c )[0]; - s.parentNode.insertBefore( pd, s ); - } -}( document, 'script', 'pd-embed' ) ); -CONTAINER; - - // Compress it a bit - $include = $this->compress_it( $include ); - - $placeholder = - '<div class="cs-embed pd-embed" data-settings="' - . esc_attr( json_encode( $settings ) ) - . '"></div>'; - if ( 'button' === $settings['type'] ) { - $placeholder = - '<a class="cs-embed pd-embed" href="' - . esc_attr( $survey_link ) - . '" data-settings="' - . esc_attr( json_encode( $settings ) ) - . '">' - . esc_html( $settings['title'] ) - . '</a>'; + /** + * Register scripts that may be enqueued later on by the shortcode. + */ + public static function register_scripts() { + wp_register_script( + 'crowdsignal-shortcode', + Assets::get_file_url_for_environment( '_inc/build/crowdsignal-shortcode.min.js', '_inc/crowdsignal-shortcode.js' ), + array( 'jquery' ), + JETPACK__VERSION, + true + ); + wp_register_script( + 'crowdsignal-survey', + Assets::get_file_url_for_environment( '_inc/build/crowdsignal-survey.min.js', '_inc/crowdsignal-survey.js' ), + array(), + JETPACK__VERSION, + true + ); + wp_register_script( + 'crowdsignal-rating', + 'https://polldaddy.com/js/rating/rating.js', + array(), + JETPACK__VERSION, + true + ); } - $js_include = $placeholder . "\n"; - $js_include .= '<script type="text/javascript"><!--//--><![CDATA[//><!--' . "\n"; - $js_include .= $include . "\n"; - $js_include .= "//--><!]]></script>\n"; + /** + * JavaScript code for a specific survey / poll. + * + * @param array $settings Array of information about a survey / poll. + * @param string $survey_link HTML link tag for a specific survey or poll. + * @param string $survey_url Link to the survey or poll. + */ + private function get_async_code( array $settings, $survey_link, $survey_url ) { + wp_enqueue_script( 'crowdsignal-survey' ); + + if ( 'button' === $settings['type'] ) { + $placeholder = sprintf( + '<a class="cs-embed pd-embed" href="%1$s" data-settings="%2$s">%3$s</a>', + esc_url( $survey_url ), + esc_attr( wp_json_encode( $settings ) ), + esc_html( $settings['title'] ) + ); + } else { + $placeholder = sprintf( + '<div class="cs-embed pd-embed" data-settings="%1$s"></div><noscript>%2$s</noscript>', + esc_attr( wp_json_encode( $settings ) ), + $survey_link + ); + } - if ( 'button' !== $settings['type'] ) { - $js_include .= '<noscript>' . $survey_link . "</noscript>\n"; + return $placeholder; } - return $js_include; - } - - private function compress_it( $js ) { - $js = str_replace( array( "\n", "\t", "\r" ), '', $js ); - $js = preg_replace( '/\s*([,:\?\{;\-=\(\)])\s*/', '$1', $js ); - return $js; - } - - /* - * Crowdsignal Poll Embed script - transforms code that looks like that: - * <script type="text/javascript" charset="utf-8" async src="http://static.polldaddy.com/p/123456.js"></script> - * <noscript><a href="http://polldaddy.com/poll/123456/">What is your favourite color?</a></noscript> - * into the [crowdsignal poll=...] shortcode format - */ - function crowdsignal_embed_to_shortcode( $content ) { - - if ( ! is_string( $content ) || false === strpos( $content, 'polldaddy.com/p/' ) ) { - return $content; - } + /** + * Crowdsignal Poll Embed script - transforms code that looks like that: + * <script type="text/javascript" charset="utf-8" async src="http://static.polldaddy.com/p/123456.js"></script> + * <noscript><a href="http://polldaddy.com/poll/123456/">What is your favourite color?</a></noscript> + * into the [crowdsignal poll=...] shortcode format + * + * @param string $content Post content. + */ + public function crowdsignal_embed_to_shortcode( $content ) { - $regexes = array(); + if ( ! is_string( $content ) || false === strpos( $content, 'polldaddy.com/p/' ) ) { + return $content; + } - $regexes[] = '#<script[^>]+?src="https?://(secure|static)\.polldaddy\.com/p/([0-9]+)\.js"[^>]*+>\s*?</script>\r?\n?(<noscript>.*?</noscript>)?#i'; + $regexes = array(); - $regexes[] = '#<script(?:[^&]|&(?!gt;))+?src="https?://(secure|static)\.polldaddy\.com/p/([0-9]+)\.js"(?:[^&]|&(?!gt;))*+>\s*?</script>\r?\n?(<noscript>.*?</noscript>)?#i'; + $regexes[] = '#<script[^>]+?src="https?://(secure|static)\.polldaddy\.com/p/([0-9]+)\.js"[^>]*+>\s*?</script>\r?\n?(<noscript>.*?</noscript>)?#i'; - foreach ( $regexes as $regex ) { - if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) { - continue; - } + $regexes[] = '#<script(?:[^&]|&(?!gt;))+?src="https?://(secure|static)\.polldaddy\.com/p/([0-9]+)\.js"(?:[^&]|&(?!gt;))*+>\s*?</script>\r?\n?(<noscript>.*?</noscript>)?#i'; - foreach ( $matches as $match ) { - if ( ! isset( $match[2] ) ) { + foreach ( $regexes as $regex ) { + if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) { continue; } - $id = (int) $match[2]; + foreach ( $matches as $match ) { + if ( ! isset( $match[2] ) ) { + continue; + } + + $id = (int) $match[2]; - if ( $id > 0 ) { - $content = str_replace( $match[0], " [crowdsignal poll=$id]", $content ); - /** This action is documented in modules/shortcodes/youtube.php */ - do_action( 'jetpack_embed_to_shortcode', 'crowdsignal', $id ); + if ( $id > 0 ) { + $content = str_replace( $match[0], " [crowdsignal poll=$id]", $content ); + /** This action is documented in modules/shortcodes/youtube.php */ + do_action( 'jetpack_embed_to_shortcode', 'crowdsignal', $id ); + } } } - } - return $content; - } - - /** - * Shortcode for polldadddy - * [crowdsignal poll|survey|rating="123456"] - */ - function crowdsignal_shortcode( $atts ) { - global $post; - global $content_width; + return $content; + } /** - * Variables extracted from $atts. + * Support for legacy Polldaddy shortcode. * - * @var string $survey - * @var string $link_text - * @var string $poll - * @var string $rating - * @var string $unique_id - * @var string $item_id - * @var string $title - * @var string $permalink - * @var int $cb - * @var string $type - * @var string $body - * @var string $button - * @var string $text_color - * @var string $back_color - * @var string $align - * @var string $style - * @var int $width - * @var int $height - * @var int $delay - * @var string $visit - * @var string $domain - * @var string $id + * @param array $atts Shortcode attributes. */ - extract( shortcode_atts( array( - 'survey' => null, - 'link_text' => 'Take Our Survey', - 'poll' => 'empty', - 'rating' => 'empty', - 'unique_id' => null, - 'item_id' => null, - 'title' => null, - 'permalink' => null, - 'cb' => 0, - 'type' => 'button', - 'body' => '', - 'button' => '', - 'text_color' => '000000', - 'back_color' => 'FFFFFF', - 'align' => '', - 'style' => '', - 'width' => $content_width, - 'height' => floor( $content_width * 3 / 4 ), - 'delay' => 100, - 'visit' => 'single', - 'domain' => '', - 'id' => '', - ), $atts, 'crowdsignal' ) ); - - if ( ! is_array( $atts ) ) { - return '<!-- Crowdsignal shortcode passed invalid attributes -->'; - } - - $inline = ! in_the_loop(); - $no_script = false; - $infinite_scroll = false; - - if ( is_home() && current_theme_supports( 'infinite-scroll' ) ) { - $infinite_scroll = true; - } - - if ( defined( 'PADPRESS_LOADED' ) ) { - $inline = true; - } - - if ( function_exists( 'get_option' ) && get_option( 'polldaddy_load_poll_inline' ) ) { - $inline = true; - } + public function polldaddy_shortcode( $atts ) { + if ( ! is_array( $atts ) ) { + return '<!-- Polldaddy shortcode passed invalid attributes -->'; + } - if ( is_feed() || ( defined( 'DOING_AJAX' ) && ! $infinite_scroll ) ) { - $no_script = false; + $atts['site'] = 'polldaddy.com'; + return $this->crowdsignal_shortcode( $atts ); } - self::$add_script = $infinite_scroll; - - if ( intval( $rating ) > 0 && ! $no_script ) { //rating embed + /** + * Shortcode for Crowdsignal + * [crowdsignal poll|survey|rating="123456"] + * + * @param array $atts Shortcode attributes. + */ + public function crowdsignal_shortcode( $atts ) { + global $post; + global $content_width; - if ( empty( $unique_id ) ) { - $unique_id = is_page() ? 'wp-page-' . $post->ID : 'wp-post-' . $post->ID; + if ( ! is_array( $atts ) ) { + return '<!-- Crowdsignal shortcode passed invalid attributes -->'; } - if ( empty( $item_id ) ) { - $item_id = is_page() ? '_page_' . $post->ID : '_post_' . $post->ID; + $attributes = shortcode_atts( + array( + 'survey' => null, + 'link_text' => esc_html__( 'Take Our Survey', 'jetpack' ), + 'poll' => 'empty', + 'rating' => 'empty', + 'unique_id' => null, + 'item_id' => null, + 'title' => null, + 'permalink' => null, + 'cb' => 0, // cache buster. Helps with testing. + 'type' => 'button', + 'body' => '', + 'button' => '', + 'text_color' => '000000', + 'back_color' => 'FFFFFF', + 'align' => '', + 'style' => '', + 'width' => $content_width, + 'height' => floor( $content_width * 3 / 4 ), + 'delay' => 100, + 'visit' => 'single', + 'domain' => '', + 'id' => '', + 'site' => 'crowdsignal.com', + ), + $atts, + 'crowdsignal' + ); + + $inline = ! in_the_loop() + && ! Constants::is_defined( 'TESTING_IN_JETPACK' ); + + $no_script = false; + $infinite_scroll = false; + + if ( is_home() && current_theme_supports( 'infinite-scroll' ) ) { + $infinite_scroll = true; } - if ( empty( $title ) ) { - /** This filter is documented in core/src/wp-includes/general-template.php */ - $title = apply_filters( 'wp_title', $post->post_title, '', '' ); + if ( function_exists( 'get_option' ) && get_option( 'polldaddy_load_poll_inline' ) ) { + $inline = true; } - if ( empty( $permalink ) ) { - $permalink = get_permalink( $post->ID ); + if ( is_feed() || ( defined( 'DOING_AJAX' ) && ! $infinite_scroll ) ) { + $no_script = false; } - $rating = intval( $rating ); - $unique_id = preg_replace( '/[^\-_a-z0-9]/i', '', wp_strip_all_tags( $unique_id ) ); - $item_id = wp_strip_all_tags( $item_id ); - $item_id = preg_replace( '/[^_a-z0-9]/i', '', $item_id ); - - $settings = json_encode( array( - 'id' => $rating, - 'unique_id' => $unique_id, - 'title' => rawurlencode( trim( $title ) ), - 'permalink' => esc_url( $permalink ), - 'item_id' => $item_id, - ) ); - - $item_id = esc_js( $item_id ); - - if ( Jetpack_AMP_Support::is_amp_request() ) { - return sprintf( '<a href="%s" target="_blank">%s</a>', esc_url( $permalink ), esc_html( trim( $title ) ) ); - } elseif ( $inline ) { - return <<<SCRIPT -<div class="cs-rating pd-rating" id="pd_rating_holder_{$rating}{$item_id}"></div> -<script type="text/javascript" charset="UTF-8"><!--//--><![CDATA[//><!-- -PDRTJS_settings_{$rating}{$item_id}={$settings}; -//--><!]]></script> -<script type="text/javascript" charset="UTF-8" async src="https://polldaddy.com/js/rating/rating.js"></script> -SCRIPT; - } else { - if ( false === self::$scripts ) { - self::$scripts = array(); - } - - $data = array( 'id' => $rating, 'item_id' => $item_id, 'settings' => $settings ); - - self::$scripts['rating'][] = $data; + self::$add_script = $infinite_scroll; - add_action( 'wp_footer', array( $this, 'generate_scripts' ) ); + /* + * Rating embed. + */ + if ( intval( $attributes['rating'] ) > 0 && ! $no_script ) { - $data = esc_attr( json_encode( $data ) ); - - if ( $infinite_scroll ) { - return <<<CONTAINER -<div class="cs-rating pd-rating" id="pd_rating_holder_{$rating}{$item_id}" data-settings="{$data}"></div> -CONTAINER; - } else { - return <<<CONTAINER -<div class="cs-rating pd-rating" id="pd_rating_holder_{$rating}{$item_id}"></div> -CONTAINER; + if ( empty( $attributes['unique_id'] ) ) { + $attributes['unique_id'] = is_page() ? 'wp-page-' . $post->ID : 'wp-post-' . $post->ID; } - } - } elseif ( intval( $poll ) > 0 ) { //poll embed - - if ( empty( $title ) ) { - $title = __( 'Take Our Poll', 'jetpack' ); - } - $poll = intval( $poll ); - $poll_url = sprintf( 'https://poll.fm/%d', $poll ); - $poll_js = sprintf( 'https://secure.polldaddy.com/p/%d.js', $poll ); - $poll_link = sprintf( '<a href="%s" target="_blank">%s</a>', esc_url( $poll_url ), esc_html( $title ) ); + if ( empty( $attributes['item_id'] ) ) { + $attributes['item_id'] = is_page() ? '_page_' . $post->ID : '_post_' . $post->ID; + } - if ( $no_script || Jetpack_AMP_Support::is_amp_request() ) { - return $poll_link; - } else { - if ( $type == 'slider' && !$inline ) { + if ( empty( $attributes['title'] ) ) { + /** This filter is documented in core/src/wp-includes/general-template.php */ + $attributes['title'] = apply_filters( 'wp_title', $post->post_title, '', '' ); + } - if ( ! in_array( $visit, array( 'single', 'multiple' ) ) ) { - $visit = 'single'; - } + if ( empty( $attributes['permalink'] ) ) { + $attributes['permalink'] = get_permalink( $post->ID ); + } - $settings = array( - 'type' => 'slider', - 'embed' => 'poll', - 'delay' => intval( $delay ), - 'visit' => $visit, - 'id' => intval( $poll ) + $rating = intval( $attributes['rating'] ); + $unique_id = preg_replace( '/[^\-_a-z0-9]/i', '', wp_strip_all_tags( $attributes['unique_id'] ) ); + $item_id = wp_strip_all_tags( $attributes['item_id'] ); + $item_id = preg_replace( '/[^_a-z0-9]/i', '', $item_id ); + + $settings = wp_json_encode( + array( + 'id' => $rating, + 'unique_id' => $unique_id, + 'title' => rawurlencode( trim( $attributes['title'] ) ), + 'permalink' => esc_url( $attributes['permalink'] ), + 'item_id' => $item_id, + ) + ); + + $item_id = esc_js( $item_id ); + + if ( + class_exists( 'Jetpack_AMP_Support' ) + && Jetpack_AMP_Support::is_amp_request() + ) { + return sprintf( + '<a href="%s" target="_blank">%s</a>', + esc_url( $attributes['permalink'] ), + esc_html( trim( $attributes['title'] ) ) + ); + } elseif ( $inline ) { + $rating_js = "<!--//--><![CDATA[//><!--\n"; + $rating_js .= "PDRTJS_settings_{$rating}{$item_id}={$settings};"; + $rating_js .= "\n//--><!]]>"; + + wp_enqueue_script( 'crowdsignal-rating' ); + wp_add_inline_script( + 'crowdsignal-rating', + $rating_js, + 'before' ); - return $this->get_async_code( $settings, $poll_link ); + return sprintf( + '<div class="cs-rating pd-rating" id="pd_rating_holder_%1$d%2$s"></div>', + absint( $rating ), + esc_attr( $item_id ) + ); } else { - $cb = ( $cb == 1 ? '?cb='.mktime() : false ); - $margins = ''; - $float = ''; - - if ( in_array( $align, array( 'right', 'left' ) ) ) { - $float = sprintf( 'float: %s;', $align ); - - if ( $align == 'left') - $margins = 'margin: 0px 10px 0px 0px;'; - elseif ( $align == 'right' ) - $margins = 'margin: 0px 0px 0px 10px'; - } - - // Force the normal style embed on single posts/pages otherwise it's not rendered on infinite scroll themed blogs ('infinite_scroll_render' isn't fired) - if ( is_singular() ) { - $inline = true; + if ( false === self::$scripts ) { + self::$scripts = array(); } - if ( false === $cb && ! $inline ) { - if ( false === self::$scripts ) { - self::$scripts = array(); - } - - $data = array( 'url' => $poll_js ); - - self::$scripts['poll'][intval( $poll )] = $data; - - add_action( 'wp_footer', array( $this, 'generate_scripts' ) ); - - $data = esc_attr( json_encode( $data ) ); - - $script_url = esc_url_raw( plugins_url( 'js/polldaddy-shortcode.js', __FILE__ ) ); - $str = <<<CONTAINER -<a name="pd_a_{$poll}"></a> -<div class="CSS_Poll PDS_Poll" id="PDI_container{$poll}" data-settings="{$data}" style="display:inline-block;{$float}{$margins}"></div> -<div id="PD_superContainer"></div> -<noscript>{$poll_link}</noscript> -CONTAINER; + $data = array( + 'id' => $rating, + 'item_id' => $item_id, + 'settings' => $settings, + ); -$loader = <<<SCRIPT -( function( d, c, j ) { - if ( ! d.getElementById( j ) ) { - var pd = d.createElement( c ), s; - pd.id = j; - pd.src = '{$script_url}'; - s = d.getElementsByTagName( c )[0]; - s.parentNode.insertBefore( pd, s ); - } else if ( typeof jQuery !== 'undefined' ) { - jQuery( d.body ).trigger( 'pd-script-load' ); - } -} ( document, 'script', 'pd-polldaddy-loader' ) ); -SCRIPT; + self::$scripts['rating'][] = $data; - $loader = $this->compress_it( $loader ); - $loader = "<script type='text/javascript'>\n" . $loader . "\n</script>"; + add_action( 'wp_footer', array( $this, 'generate_scripts' ) ); - return $str . $loader; + if ( $infinite_scroll ) { + return sprintf( + '<div class="cs-rating pd-rating" id="pd_rating_holder_%1$d%2$s" data-settings="%3$s"></div>', + absint( $rating ), + esc_attr( $item_id ), + esc_attr( wp_json_encode( $data ) ) + ); } else { - if ( $inline ) { - $cb = ''; - } - - return <<<CONTAINER -<a id="pd_a_{$poll}"></a> -<div class="CSS_Poll PDS_Poll" id="PDI_container{$poll}" style="display:inline-block;{$float}{$margins}"></div> -<div id="PD_superContainer"></div> -<script type="text/javascript" charset="UTF-8" async src="{$poll_js}{$cb}"></script> -<noscript>{$poll_link}</noscript> -CONTAINER; + return sprintf( + '<div class="cs-rating pd-rating" id="pd_rating_holder_%1$d%2$s"></div>', + absint( $rating ), + esc_attr( $item_id ) + ); } } - } - } elseif ( ! empty( $survey ) ) { //survey embed - - if ( in_array( $type, array( 'iframe', 'button', 'banner', 'slider' ) ) ) { + } elseif ( intval( $attributes['poll'] ) > 0 ) { + /* + * Poll embed. + */ - if ( empty( $title ) ) { - $title = __( 'Take Our Survey', 'jetpack' ); - if( ! empty( $link_text ) ) { - $title = $link_text; - } + if ( empty( $attributes['title'] ) ) { + $attributes['title'] = esc_html__( 'Take Our Poll', 'jetpack' ); } - if ( $type == 'banner' || $type == 'slider' ) - $inline = false; - - $survey = preg_replace( '/[^a-f0-9]/i', '', $survey ); - $survey_url = esc_url( "https://survey.fm/{$survey}" ); - $survey_link = sprintf( '<a href="%s" target="_blank">%s</a>', $survey_url, esc_html( $title ) ); - - $settings = array(); + $poll = intval( $attributes['poll'] ); - // Do we want a full embed code or a link? - if ( $no_script || $inline || $infinite_scroll || Jetpack_AMP_Support::is_amp_request() ) { - return $survey_link; + if ( 'crowdsignal.com' === $attributes['site'] ) { + $poll_url = sprintf( 'https://poll.fm/%d', $poll ); + } else { + $poll_url = sprintf( 'https://polldaddy.com/p/%d', $poll ); } - if ( $type == 'iframe' ) { - if ( $height != 'auto' ) { - if ( isset( $content_width ) && is_numeric( $width ) && $width > $content_width ) { - $width = $content_width; - } + $poll_js = sprintf( 'https://secure.polldaddy.com/p/%d.js', $poll ); + $poll_link = sprintf( + '<a href="%s" target="_blank">%s</a>', + esc_url( $poll_url ), + esc_html( $attributes['title'] ) + ); + + if ( + $no_script + || ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) + ) { + return $poll_link; + } else { + /* + * Slider poll. + */ + if ( + 'slider' === $attributes['type'] + && ! $inline + ) { - if ( ! $width ) { - $width = '100%'; - } else { - $width = (int) $width; + if ( ! in_array( + $attributes['visit'], + array( 'single', 'multiple' ), + true + ) ) { + $attributes['visit'] = 'single'; } - if ( ! $height ) { - $height = '600'; + $settings = array( + 'type' => 'slider', + 'embed' => 'poll', + 'delay' => intval( $attributes['delay'] ), + 'visit' => $attributes['visit'], + 'id' => intval( $poll ), + 'site' => $attributes['site'], + ); + + return $this->get_async_code( $settings, $poll_link, $poll_url ); + } else { + if ( 1 === $attributes['cb'] ) { + $attributes['cb'] = '?cb=' . mktime(); } else { - $height = (int) $height; + $attributes['cb'] = false; + } + $margins = ''; + $float = ''; + + if ( in_array( + $attributes['align'], + array( 'right', 'left' ), + true + ) ) { + $float = sprintf( 'float: %s;', $attributes['align'] ); + + if ( 'left' === $attributes['align'] ) { + $margins = 'margin: 0px 10px 0px 0px;'; + } elseif ( 'right' === $attributes['align'] ) { + $margins = 'margin: 0px 0px 0px 10px'; + } } - return <<<CONTAINER -<iframe src="{$survey_url}?iframe=1" frameborder="0" width="{$width}" height="{$height}" scrolling="auto" allowtransparency="true" marginheight="0" marginwidth="0">{$survey_link}</iframe> -CONTAINER; - } elseif ( ! empty( $domain ) && ! empty( $id ) ) { - - $domain = preg_replace( '/[^a-z0-9\-]/i', '', $domain ); - $id = preg_replace( '/[\/\?&\{\}]/', '', $id ); - - $auto_src = esc_url( "https://{$domain}.survey.fm/{$id}" ); - $auto_src = parse_url( $auto_src ); - - if ( ! is_array( $auto_src ) || count( $auto_src ) == 0 ) { - return '<!-- no crowdsignal output -->'; + /* + * Force the normal style embed on single posts/pages + * otherwise it's not rendered on infinite scroll themed blogs + * ('infinite_scroll_render' isn't fired) + */ + if ( is_singular() ) { + $inline = true; } - if ( ! isset( $auto_src['host'] ) || ! isset( $auto_src['path'] ) ) { - return '<!-- no crowdsignal output -->'; + if ( false === $attributes['cb'] && ! $inline ) { + if ( false === self::$scripts ) { + self::$scripts = array(); + } + + $data = array( 'url' => $poll_js ); + + self::$scripts['poll'][ intval( $poll ) ] = $data; + + add_action( 'wp_footer', array( $this, 'generate_scripts' ) ); + + wp_enqueue_script( 'crowdsignal-shortcode' ); + wp_localize_script( + 'crowdsignal-shortcode', + 'crowdsignal_shortcode_options', + array( + 'script_url' => esc_url_raw( + Assets::get_file_url_for_environment( + '_inc/build/polldaddy-shortcode.min.js', + '_inc/polldaddy-shortcode.js' + ) + ), + ) + ); + + return sprintf( + '<a name="pd_a_%1$d"></a><div class="CSS_Poll PDS_Poll" id="PDI_container%1$d" data-settings="%2$s" style="display:inline-block;%3$s%4$s"></div><div id="PD_superContainer"></div><noscript>%5$s</noscript>', + absint( $poll ), + esc_attr( wp_json_encode( $data ) ), + $float, + $margins, + $poll_link + ); + } else { + if ( $inline ) { + $attributes['cb'] = ''; + } + + wp_enqueue_script( + 'crowdsignal-' . absint( $poll ), + esc_url( $poll_js . $attributes['cb'] ), + array(), + JETPACK__VERSION, + true + ); + + return sprintf( + '<a id="pd_a_%1$s"></a><div class="CSS_Poll PDS_Poll" id="PDI_container%1$s" style="display:inline-block;%2$s%3$s"></div><div id="PD_superContainer"></div><noscript>%4$s</noscript>', + absint( $poll ), + $float, + $margins, + $poll_link + ); } + } + } + } elseif ( ! empty( $attributes['survey'] ) ) { + /* + * Survey embed. + */ + + if ( in_array( + $attributes['type'], + array( 'iframe', 'button', 'banner', 'slider' ), + true + ) ) { + + if ( empty( $attributes['title'] ) ) { + $attributes['title'] = esc_html__( 'Take Our Survey', 'jetpack' ); + if ( ! empty( $attributes['link_text'] ) ) { + $attributes['title'] = $attributes['link_text']; + } + } - $domain = $auto_src['host'] . '/'; - $id = ltrim( $auto_src['path'], '/' ); + if ( + 'banner' === $attributes['type'] + || 'slider' === $attributes['type'] + ) { + $inline = false; + } - $settings = array( - 'type' => $type, - 'auto' => true, - 'domain' => $domain, - 'id' => $id - ); + $survey = preg_replace( '/[^a-f0-9]/i', '', $attributes['survey'] ); + + if ( 'crowdsignal.com' === $attributes['site'] ) { + $survey_url = 'https://survey.fm/' . $survey; + } else { + $survey_url = 'https://polldaddy.com/s/' . $survey; } - } else { - $text_color = preg_replace( '/[^a-f0-9]/i', '', $text_color ); - $back_color = preg_replace( '/[^a-f0-9]/i', '', $back_color ); + $survey_link = sprintf( + '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', + esc_url( $survey_url ), + esc_html( $attributes['title'] ) + ); + + $settings = array(); + + // Do we want a full embed code or a link? if ( - ! in_array( - $align, - array( - 'right', - 'left', - 'top-left', - 'top-right', - 'middle-left', - 'middle-right', - 'bottom-left', - 'bottom-right' - ) - ) + $no_script + || $inline + || $infinite_scroll + || ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) ) { - $align = ''; + return $survey_link; } - if ( - ! in_array( - $style, + if ( 'iframe' === $attributes['type'] ) { + if ( 'auto' !== $attributes['height'] ) { + if ( + isset( $content_width ) + && is_numeric( $attributes['width'] ) + && $attributes['width'] > $content_width + ) { + $attributes['width'] = $content_width; + } + + if ( ! $attributes['width'] ) { + $attributes['width'] = '100%'; + } else { + $attributes['width'] = (int) $attributes['width']; + } + + if ( ! $attributes['height'] ) { + $attributes['height'] = '600'; + } else { + $attributes['height'] = (int) $attributes['height']; + } + + return sprintf( + '<iframe src="%1$s?iframe=1" frameborder="0" width="%2$d" height="%3$d" scrolling="auto" allowtransparency="true" marginheight="0" marginwidth="0">%4$s</iframe>', + esc_url( $survey_url ), + absint( $attributes['width'] ), + absint( $attributes['height'] ), + $survey_link + ); + } elseif ( + ! empty( $attributes['domain'] ) + && ! empty( $attributes['id'] ) + ) { + $domain = preg_replace( '/[^a-z0-9\-]/i', '', $attributes['domain'] ); + $id = preg_replace( '/[\/\?&\{\}]/', '', $attributes['id'] ); + + $auto_src = esc_url( "https://{$domain}.survey.fm/{$id}" ); + $auto_src = wp_parse_url( $auto_src ); + + if ( ! is_array( $auto_src ) || 0 === count( $auto_src ) ) { + return '<!-- no crowdsignal output -->'; + } + + if ( ! isset( $auto_src['host'] ) || ! isset( $auto_src['path'] ) ) { + return '<!-- no crowdsignal output -->'; + } + + $domain = $auto_src['host'] . '/'; + $id = ltrim( $auto_src['path'], '/' ); + + $settings = array( + 'type' => $attributes['type'], + 'auto' => true, + 'domain' => $domain, + 'id' => $id, + 'site' => $attributes['site'], + ); + } + } else { + $text_color = preg_replace( '/[^a-f0-9]/i', '', $attributes['text_color'] ); + $back_color = preg_replace( '/[^a-f0-9]/i', '', $attributes['back_color'] ); + + if ( + ! in_array( + $attributes['align'], + array( + 'right', + 'left', + 'top-left', + 'top-right', + 'middle-left', + 'middle-right', + 'bottom-left', + 'bottom-right', + ), + true + ) + ) { + $attributes['align'] = ''; + } + + if ( + ! in_array( + $attributes['style'], + array( + 'inline', + 'side', + 'corner', + 'rounded', + 'square', + ), + true + ) + ) { + $attributes['style'] = ''; + } + + $settings = array_filter( array( - 'inline', - 'side', - 'corner', - 'rounded', - 'square' + 'title' => wp_strip_all_tags( $attributes['title'] ), + 'type' => $attributes['type'], + 'body' => wp_strip_all_tags( $attributes['body'] ), + 'button' => wp_strip_all_tags( $attributes['button'] ), + 'text_color' => $text_color, + 'back_color' => $back_color, + 'align' => $attributes['align'], + 'style' => $attributes['style'], + 'id' => $survey, + 'site' => $attributes['site'], ) - ) - ) { - $style = ''; + ); } - $title = wp_strip_all_tags( $title ); - $body = wp_strip_all_tags( $body ); - $button = wp_strip_all_tags( $button ); - - $settings = array_filter( array( - 'title' => $title, - 'type' => $type, - 'body' => $body, - 'button' => $button, - 'text_color' => $text_color, - 'back_color' => $back_color, - 'align' => $align, - 'style' => $style, - 'id' => $survey, - ) ); - } + if ( empty( $settings ) ) { + return '<!-- no crowdsignal output -->'; + } - if ( empty( $settings ) ) { - return '<!-- no crowdsignal output -->'; + return $this->get_async_code( $settings, $survey_link, $survey_url ); } - - return $this->get_async_code( $settings, $survey_link ); + } else { + return '<!-- no crowdsignal output -->'; } - } else { - return '<!-- no crowdsignal output -->'; } - } - function generate_scripts() { - $script = ''; + /** + * Enqueue JavaScript containing all ratings / polls on the page. + * Hooked into wp_footer + */ + public function generate_scripts() { + if ( is_array( self::$scripts ) ) { + if ( isset( self::$scripts['rating'] ) ) { + $script = "<!--//--><![CDATA[//><!--\n"; + foreach ( self::$scripts['rating'] as $rating ) { + $script .= "PDRTJS_settings_{$rating['id']}{$rating['item_id']}={$rating['settings']}; if ( typeof PDRTJS_RATING !== 'undefined' ){if ( typeof PDRTJS_{$rating['id']}{$rating['item_id']} == 'undefined' ){PDRTJS_{$rating['id']}{$rating['item_id']} = new PDRTJS_RATING( PDRTJS_settings_{$rating['id']}{$rating['item_id']} );}}"; + } + $script .= "\n//--><!]]>"; - if ( is_array( self::$scripts ) ) { - if ( isset( self::$scripts['rating'] ) ) { - $script = "<script type='text/javascript' charset='UTF-8' id='polldaddyRatings'><!--//--><![CDATA[//><!--\n"; - foreach( self::$scripts['rating'] as $rating ) { - $script .= "PDRTJS_settings_{$rating['id']}{$rating['item_id']}={$rating['settings']}; if ( typeof PDRTJS_RATING !== 'undefined' ){if ( typeof PDRTJS_{$rating['id']}{$rating['item_id']} == 'undefined' ){PDRTJS_{$rating['id']}{$rating['item_id']} = new PDRTJS_RATING( PDRTJS_settings_{$rating['id']}{$rating['item_id']} );}}"; + wp_enqueue_script( 'crowdsignal-rating' ); + wp_add_inline_script( + 'crowdsignal-rating', + $script, + 'before' + ); } - $script .= "\n//--><!]]></script><script type='text/javascript' charset='UTF-8' async src='https://polldaddy.com/js/rating/rating.js'></script>"; - - } - if ( isset( self::$scripts['poll'] ) ) { - foreach( self::$scripts['poll'] as $poll ) { - $script .= "<script type='text/javascript' charset='UTF-8' async src='{$poll['url']}'></script>"; + if ( isset( self::$scripts['poll'] ) ) { + foreach ( self::$scripts['poll'] as $poll_id => $poll ) { + wp_enqueue_script( + 'crowdsignal-' . absint( $poll_id ), + esc_url( $poll['url'] ), + array(), + JETPACK__VERSION, + true + ); + } } } + self::$scripts = false; } - self::$scripts = false; - echo $script; - } - - /** - * If the theme uses infinite scroll, include jquery at the start - */ - function check_infinite() { - if ( - current_theme_supports( 'infinite-scroll' ) - && class_exists( 'The_Neverending_Home_Page' ) - && The_Neverending_Home_Page::archive_supports_infinity() - ) { - wp_enqueue_script( 'jquery' ); + /** + * If the theme uses infinite scroll, include jquery at the start + */ + public function check_infinite() { + if ( + current_theme_supports( 'infinite-scroll' ) + && class_exists( 'The_Neverending_Home_Page' ) + && The_Neverending_Home_Page::archive_supports_infinity() + ) { + wp_enqueue_script( 'jquery' ); + } } - } - - /** - * Dynamically load the .js, if needed - * - * This hooks in late (priority 11) to infinite_scroll_render to determine - * a posteriori if a shortcode has been called. - */ - function crowdsignal_shortcode_infinite() { - // only try to load if a shortcode has been called and theme supports infinite scroll - if( self::$add_script ) { - $script_url = esc_url_raw( plugins_url( 'js/polldaddy-shortcode.js', __FILE__ ) ); - - // if the script hasn't been loaded, load it - // if the script loads successfully, fire an 'pd-script-load' event - echo <<<SCRIPT - <script type='text/javascript'> - //<![CDATA[ - ( function( d, c, j ) { - if ( !d.getElementById( j ) ) { - var pd = d.createElement( c ), s; - pd.id = j; - pd.async = true; - pd.src = '{$script_url}'; - s = d.getElementsByTagName( c )[0]; - s.parentNode.insertBefore( pd, s ); - } else if ( typeof jQuery !== 'undefined' ) { - jQuery( d.body ).trigger( 'pd-script-load' ); - } - } ( document, 'script', 'pd-polldaddy-loader' ) ); - //]]> - </script> -SCRIPT; + /** + * Dynamically load the .js, if needed + * + * This hooks in late (priority 11) to infinite_scroll_render to determine + * a posteriori if a shortcode has been called. + */ + public function crowdsignal_shortcode_infinite() { + // only try to load if a shortcode has been called and theme supports infinite scroll. + if ( self::$add_script ) { + wp_enqueue_script( 'crowdsignal-shortcode' ); + wp_localize_script( + 'crowdsignal-shortcode', + 'crowdsignal_shortcode_options', + array( + 'script_url' => esc_url_raw( + Assets::get_file_url_for_environment( + '_inc/build/polldaddy-shortcode.min.js', + '_inc/polldaddy-shortcode.js' + ) + ), + ) + ); + } } } -} -// kick it all off -new CrowdsignalShortcode(); + // Kick it all off. + new CrowdsignalShortcode(); -if ( ! function_exists( 'crowdsignal_link' ) ) { - // http://polldaddy.com/poll/1562975/?view=results&msg=voted - function crowdsignal_link( $content ) { - if ( Jetpack_AMP_Support::is_amp_request() ) { - return $content; + if ( ! function_exists( 'crowdsignal_link' ) ) { + /** + * Replace link by embed. + * Example: http://polldaddy.com/poll/1562975/?view=results&msg=voted + * + * @param string $content Post content. + */ + function crowdsignal_link( $content ) { + if ( + class_exists( 'Jetpack_AMP_Support' ) + && Jetpack_AMP_Support::is_amp_request() + ) { + return $content; + } + + return jetpack_preg_replace_outside_tags( + '!(?:\n|\A)https?://(polldaddy\.com/poll|poll\.fm)/([0-9]+?)(/.*)?(?:\n|\Z)!i', + "\n<script type='text/javascript' charset='utf-8' src='//static.polldaddy.com/p/$2.js'></script><noscript> <a href='https://poll.fm/$2'>View Poll</a></noscript>\n", // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + $content, + 'polldaddy.com/poll' + ); } - return preg_replace( '!(?:\n|\A)https?://(polldaddy\.com/poll|poll\.fm)/([0-9]+?)(/.*)?(?:\n|\Z)!i', "\n<script type='text/javascript' charset='utf-8' src='//static.polldaddy.com/p/$2.js'></script><noscript> <a href='https://poll.fm/$2'>View Poll</a></noscript>\n", $content ); + // higher priority because we need it before auto-link and autop get to it. + add_filter( 'the_content', 'crowdsignal_link', 1 ); + add_filter( 'the_content_rss', 'crowdsignal_link', 1 ); } - // higher priority because we need it before auto-link and autop get to it - add_filter( 'the_content', 'crowdsignal_link', 1 ); - add_filter( 'the_content_rss', 'crowdsignal_link', 1 ); -} - /** * Note that Core has the oembed of '#https?://survey\.fm/.*#i' as of 5.1. * This should be removed after Core has the current regex is in our minimum version. * * @see https://core.trac.wordpress.org/ticket/46467 - * @todo Confirm patch landed and remove once 5.2 is the minimum version. + * @todo Remove once 5.2 is the minimum version. */ -wp_oembed_add_provider( '#https?://.+\.survey\.fm/.*#i', 'https://api.crowdsignal.com/oembed', true ); - + wp_oembed_add_provider( '#https?://.+\.survey\.fm/.*#i', 'https://api.crowdsignal.com/oembed', true ); } diff --git a/plugins/jetpack/modules/shortcodes/dailymotion.php b/plugins/jetpack/modules/shortcodes/dailymotion.php index fd2d620f..09984f3b 100644 --- a/plugins/jetpack/modules/shortcodes/dailymotion.php +++ b/plugins/jetpack/modules/shortcodes/dailymotion.php @@ -51,7 +51,7 @@ function dailymotion_embed_to_shortcode( $content ) { } $id = basename( substr( $src, strlen( 'www.dailymotion.com/swf' ) ) ); - $id = preg_replace( '/[^a-z0-9].*$/i', '', $id ); + $id = preg_replace( '/[^a-z0-9].*$/is', '', $id ); $content = str_replace( $match[0], "[dailymotion id=$id]", $content ); /** This action is documented in modules/shortcodes/youtube.php */ @@ -151,6 +151,15 @@ function dailymotion_shortcode( $atts ) { $width = $height / 334 * 425; } + if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) { + return sprintf( + '<amp-dailymotion data-videoid="%1$s" layout="responsive" width="%2$d" height="%3$d"></amp-dailymotion>', + esc_attr( $id ), + absint( $width ), + absint( $height ) + ); + } + /** * Let's add parameters if needed. * @@ -208,7 +217,7 @@ function dailymotion_shortcode( $atts ) { && array_key_exists( 'title', $atts ) && $title ) { - $output .= '<br /><strong><a href="' . esc_url( 'http://www.dailymotion.com/video/' . $video ) . '" target="_blank">' . esc_html( $title ) . '</a></strong>'; + $output .= '<br /><strong><a href="' . esc_url( 'https://www.dailymotion.com/video/' . $video ) . '" target="_blank">' . esc_html( $title ) . '</a></strong>'; } $user = preg_replace( '/[^-a-z0-9_]/i', '', $atts['user'] ); @@ -218,7 +227,7 @@ function dailymotion_shortcode( $atts ) { sprintf( /* Translators: placeholder is a Dailymotion username, linking to a Dailymotion profile page. */ __( 'Uploaded by %s', 'jetpack' ), - '<a href="' . esc_url( 'http://www.dailymotion.com/' . $user ) . '" target="_blank">' . esc_html( $user ) . '</a>' + '<a href="' . esc_url( 'https://www.dailymotion.com/' . $user ) . '" target="_blank">' . esc_html( $user ) . '</a>' ), array( 'a' => array( diff --git a/plugins/jetpack/modules/shortcodes/facebook.php b/plugins/jetpack/modules/shortcodes/facebook.php index e2b11e3f..71d625c8 100644 --- a/plugins/jetpack/modules/shortcodes/facebook.php +++ b/plugins/jetpack/modules/shortcodes/facebook.php @@ -9,7 +9,7 @@ define( 'JETPACK_FACEBOOK_EMBED_REGEX', '#^https?://(www.)?facebook\.com/([^/]+) define( 'JETPACK_FACEBOOK_ALTERNATE_EMBED_REGEX', '#^https?://(www.)?facebook\.com/permalink.php\?([^\s]+)#' ); define( 'JETPACK_FACEBOOK_PHOTO_EMBED_REGEX', '#^https?://(www.)?facebook\.com/photo.php\?([^\s]+)#' ); define( 'JETPACK_FACEBOOK_PHOTO_ALTERNATE_EMBED_REGEX', '#^https?://(www.)?facebook\.com/([^/]+)/photos/([^/]+)?#' ); -define( 'JETPACK_FACEBOOK_VIDEO_EMBED_REGEX', '#^https?://(www.)?facebook\.com/video.php\?([^\s]+)#' ); +define( 'JETPACK_FACEBOOK_VIDEO_EMBED_REGEX', '#^https?://(www.)?facebook\.com/(?:video.php|watch\/?)\?([^\s]+)#' ); define( 'JETPACK_FACEBOOK_VIDEO_ALTERNATE_EMBED_REGEX', '#^https?://(www.)?facebook\.com/([^/]+)/videos/([^/]+)?#' ); @@ -34,7 +34,11 @@ wp_embed_register_handler( 'facebook-photo', JETPACK_FACEBOOK_PHOTO_EMBED_REGEX, wp_embed_register_handler( 'facebook-alternate-photo', JETPACK_FACEBOOK_PHOTO_ALTERNATE_EMBED_REGEX, 'jetpack_facebook_embed_handler' ); /* - * Videos e.g. https://www.facebook.com/video.php?v=772471122790796 + * Videos + * + * Formats: + * https://www.facebook.com/video.php?v=2836814009877992 + * https://www.facebook.com/watch/?v=2836814009877992 */ wp_embed_register_handler( 'facebook-video', JETPACK_FACEBOOK_VIDEO_EMBED_REGEX, 'jetpack_facebook_embed_handler' ); @@ -51,7 +55,11 @@ wp_embed_register_handler( 'facebook-alternate-video', JETPACK_FACEBOOK_VIDEO_AL * @param array $url Requested URL to be embedded. */ function jetpack_facebook_embed_handler( $matches, $attr, $url ) { - if ( false !== strpos( $url, 'video.php' ) || false !== strpos( $url, '/videos/' ) ) { + if ( + false !== strpos( $url, 'video.php' ) + || false !== strpos( $url, '/videos/' ) + || false !== strpos( $url, '/watch' ) + ) { $embed = sprintf( '<div class="fb-video" data-allowfullscreen="true" data-href="%s"></div>', esc_url( $url ) ); } else { $width = 552; // As of 01/2017, the default width of Facebook embeds when no width attribute provided. diff --git a/plugins/jetpack/modules/shortcodes/flickr.php b/plugins/jetpack/modules/shortcodes/flickr.php index 73db1172..6ee80200 100644 --- a/plugins/jetpack/modules/shortcodes/flickr.php +++ b/plugins/jetpack/modules/shortcodes/flickr.php @@ -69,7 +69,13 @@ function flickr_embed_to_shortcode( $content ) { continue; } - $code_atts = array( 'video' => $flashvars['photo_id'] ); + $photo_id = preg_replace( '#[^A-Za-z0-9_./@+-]+#', '', $flashvars['photo_id'] ); + + if ( ! strlen( $photo_id ) ) { + continue; + } + + $code_atts = array( 'video' => $photo_id ); if ( isset( $flashvars['flickr_show_info_box'] ) @@ -79,7 +85,10 @@ function flickr_embed_to_shortcode( $content ) { } if ( ! empty( $flashvars['photo_secret'] ) ) { - $code_atts['secret'] = $flashvars['photo_secret']; + $photo_secret = preg_replace( '#[^A-Za-z0-9_./@+-]+#', '', $flashvars['photo_secret'] ); + if ( strlen( $photo_secret ) ) { + $code_atts['secret'] = $photo_secret; + } } if ( ! empty( $params['width']['value'] ) ) { @@ -135,9 +144,7 @@ function flickr_shortcode_handler( $atts ) { return ''; } - if ( is_ssl() ) { - $src = str_replace( 'http://', 'https://', $src ); - } + $src = str_replace( 'http://', 'https://', $src ); if ( 'video' === $showing ) { @@ -186,7 +193,6 @@ function flickr_shortcode_handler( $atts ) { */ function flickr_shortcode_video_markup( $atts ) { $atts = array_map( 'esc_attr', $atts ); - $http = ( is_ssl() ) ? 'https://' : 'http://'; $photo_vars = "photo_id=$atts[photo_id]"; if ( isset( $atts['secret'] ) ) { @@ -194,7 +200,7 @@ function flickr_shortcode_video_markup( $atts ) { } return <<<EOD -<object type="application/x-shockwave-flash" width="$atts[w]" height="$atts[h]" data="{$http}www.flickr.com/apps/video/stewart.swf?v=1.161" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"> <param name="flashvars" value="$photo_vars&flickr_show_info_box=$atts[show_info]"></param><param name="movie" value="{$http}www.flickr.com/apps/video/stewart.swf?v=1.161"></param><param name="bgcolor" value="#000000"></param><param name="allowFullScreen" value="true"></param><param name="wmode" value="opaque"></param><embed type="application/x-shockwave-flash" src="{$http}www.flickr.com/apps/video/stewart.swf?v=1.161" bgcolor="#000000" allowfullscreen="true" flashvars="$photo_vars&flickr_show_info_box=$atts[show_info]" wmode="opaque" height="$atts[h]" width="$atts[w]"></embed></object> +<object type="application/x-shockwave-flash" width="$atts[w]" height="$atts[h]" data="https://www.flickr.com/apps/video/stewart.swf?v=1.161" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"> <param name="flashvars" value="$photo_vars&flickr_show_info_box=$atts[show_info]"></param><param name="movie" value="https://www.flickr.com/apps/video/stewart.swf?v=1.161"></param><param name="bgcolor" value="#000000"></param><param name="allowFullScreen" value="true"></param><param name="wmode" value="opaque"></param><embed type="application/x-shockwave-flash" src="https://www.flickr.com/apps/video/stewart.swf?v=1.161" bgcolor="#000000" allowfullscreen="true" flashvars="$photo_vars&flickr_show_info_box=$atts[show_info]" wmode="opaque" height="$atts[h]" width="$atts[w]"></embed></object> EOD; } diff --git a/plugins/jetpack/modules/shortcodes/getty.php b/plugins/jetpack/modules/shortcodes/getty.php index d473e726..71e64060 100644 --- a/plugins/jetpack/modules/shortcodes/getty.php +++ b/plugins/jetpack/modules/shortcodes/getty.php @@ -152,6 +152,7 @@ function wpcom_shortcodereverse_getty( $content ) { if ( ! empty( $height ) ) { $shortcode .= ' height="' . esc_attr( $height ) . '"'; } + /* * While it does not appear to have any practical impact, Getty has * requested that we include TLD in the embed request diff --git a/plugins/jetpack/modules/shortcodes/gist.php b/plugins/jetpack/modules/shortcodes/gist.php index eba0a1a3..7c558c46 100644 --- a/plugins/jetpack/modules/shortcodes/gist.php +++ b/plugins/jetpack/modules/shortcodes/gist.php @@ -18,6 +18,8 @@ * @package Jetpack */ +use Automattic\Jetpack\Assets; + wp_embed_register_handler( 'github-gist', '#https?://gist\.github\.com/([a-zA-Z0-9/]+)(\#file\-[a-zA-Z0-9\_\-]+)?#', 'github_gist_embed_handler' ); add_shortcode( 'gist', 'github_gist_shortcode' ); @@ -56,6 +58,7 @@ function jetpack_gist_get_shortcode_id( $gist = '' ) { $gist_info = array( 'id' => '', 'file' => '', + 'ts' => 8, ); // Simple shortcode, with just an ID. if ( ctype_alnum( $gist ) ) { @@ -74,6 +77,7 @@ function jetpack_gist_get_shortcode_id( $gist = '' ) { return array( 'id' => '', 'file' => '', + 'ts' => 8, ); } @@ -84,10 +88,19 @@ function jetpack_gist_get_shortcode_id( $gist = '' ) { // Keep the unique identifier without any leading or trailing slashes. if ( ! empty( $parsed_url['path'] ) ) { - $gist_info['id'] = preg_replace( '/^\/([^\.]+)\./', '$1', $parsed_url['path'] ); + $gist_info['id'] = trim( $parsed_url['path'], '/' ); // Overwrite $gist with our identifier to clean it up below. $gist = $gist_info['id']; } + + // Parse the query args to obtain the tab spacing. + if ( ! empty( $parsed_url['query'] ) ) { + $query_args = array(); + wp_parse_str( $parsed_url['query'], $query_args ); + if ( ! empty( $query_args['ts'] ) ) { + $gist_info['ts'] = absint( $query_args['ts'] ); + } + } } // Not a URL nor an ID? Look for "username/id", "/username/id", or "id", and only keep the ID. @@ -154,6 +167,12 @@ function github_gist_shortcode( $atts, $content = '' ) { $file = rawurlencode( $file ); } + // Set the tab size, allowing attributes to override the query string. + $tab_size = $gist_info['ts']; + if ( ! empty( $atts['ts'] ) ) { + $tab_size = absint( $atts['ts'] ); + } + if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() @@ -186,14 +205,18 @@ function github_gist_shortcode( $atts, $content = '' ) { wp_enqueue_script( 'jetpack-gist-embed', - Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/gist.min.js', 'modules/shortcodes/js/gist.js' ), + Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/gist.min.js', 'modules/shortcodes/js/gist.js' ), array( 'jquery' ), JETPACK__VERSION, true ); // inline style to prevent the bottom margin to the embed that themes like TwentyTen, et al., add to tables. - $return = '<style>.gist table { margin-bottom: 0; }</style><div class="gist-oembed" data-gist="' . esc_attr( $id ) . '"></div>'; + $return = sprintf( + '<style>.gist table { margin-bottom: 0; }</style><div class="gist-oembed" data-gist="%1$s" data-ts="%2$d"></div>', + esc_attr( $id ), + absint( $tab_size ) + ); if ( // No need to check for a nonce here, that's already handled by Core further up. @@ -204,7 +227,7 @@ function github_gist_shortcode( $atts, $content = '' ) { && 'parse-embed' === $_POST['action'] // phpcs:enable WordPress.Security.NonceVerification.Missing ) { - return github_gist_simple_embed( $id ); + return github_gist_simple_embed( $id, $tab_size ); } return $return; @@ -216,9 +239,11 @@ function github_gist_shortcode( $atts, $content = '' ) { * * @since 3.9.0 * - * @param string $id The ID of the gist. + * @param string $id The ID of the gist. + * @param int $tab_size The tab size of the gist. + * @return string The script tag of the gist. */ -function github_gist_simple_embed( $id ) { +function github_gist_simple_embed( $id, $tab_size = 8 ) { $id = str_replace( 'json', 'js', $id ); - return '<script src="' . esc_url( "https://gist.github.com/$id" ) . '"></script>'; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + return '<script src="' . esc_url( "https://gist.github.com/$id?ts=$tab_size" ) . '"></script>'; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript } diff --git a/plugins/jetpack/modules/shortcodes/googlemaps.php b/plugins/jetpack/modules/shortcodes/googlemaps.php index 435e8da0..1871aff3 100644 --- a/plugins/jetpack/modules/shortcodes/googlemaps.php +++ b/plugins/jetpack/modules/shortcodes/googlemaps.php @@ -108,9 +108,7 @@ function jetpack_googlemaps_shortcode( $atts ) { } $url = substr( $url, 0, -5 ); - if ( is_ssl() ) { - $url = str_replace( 'http://', 'https://', $url ); - } + $url = str_replace( 'http://', 'https://', $url ); $css_class = 'googlemaps'; diff --git a/plugins/jetpack/modules/shortcodes/gravatar.php b/plugins/jetpack/modules/shortcodes/gravatar.php index cb709af9..f84f1c24 100644 --- a/plugins/jetpack/modules/shortcodes/gravatar.php +++ b/plugins/jetpack/modules/shortcodes/gravatar.php @@ -94,7 +94,7 @@ function jetpack_gravatar_profile_shortcode( $atts ) { } // Render the shortcode. - $gravatar_url = set_url_scheme( 'http://gravatar.com/' . $user->user_login ); + $gravatar_url = 'https://gravatar.com/' . $user->user_login; if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { $avatar_url = wpcom_get_avatar_url( $user->ID, 96 ); diff --git a/plugins/jetpack/modules/shortcodes/instagram.php b/plugins/jetpack/modules/shortcodes/instagram.php index 85c675b4..30d96ed8 100644 --- a/plugins/jetpack/modules/shortcodes/instagram.php +++ b/plugins/jetpack/modules/shortcodes/instagram.php @@ -13,6 +13,8 @@ * @package Jetpack */ +use Automattic\Jetpack\Assets; + /** * Embed Reversal for Instagram * @@ -107,7 +109,7 @@ function jetpack_instagram_handler( $matches, $atts, $url ) { if ( is_feed() ) { // Instagram offers direct links to images, but not to videos. if ( 'p' === $matches[1] ) { - $media_url = sprintf( 'http://instagr.am/p/%1$s/media/?size=l', $matches[2] ); + $media_url = sprintf( 'https://instagr.am/p/%1$s/media/?size=l', $matches[2] ); return sprintf( '<a href="%1$s" title="%2$s" target="_blank"><img src="%3$s" alt="%4$s" /></a>', esc_url( $url ), @@ -207,7 +209,7 @@ function jetpack_instagram_handler( $matches, $atts, $url ) { if ( ! empty( $response_body->html ) ) { wp_enqueue_script( 'jetpack-instagram-embed', - Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/instagram.min.js', 'modules/shortcodes/js/instagram.js' ), + Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/instagram.min.js', 'modules/shortcodes/js/instagram.js' ), array( 'jquery' ), JETPACK__VERSION, true @@ -260,6 +262,27 @@ function jetpack_shortcode_instagram( $atts ) { return ''; } + if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) { + $url_pattern = '#http(s?)://(www\.)?instagr(\.am|am\.com)/p/([^/?]+)#i'; + preg_match( $url_pattern, $atts['url'], $matches ); + if ( ! $matches ) { + return sprintf( + '<a href="%1$s" class="amp-wp-embed-fallback">%1$s</a>', + esc_url( $atts['url'] ) + ); + } + + $shortcode_id = end( $matches ); + $width = ! empty( $atts['width'] ) ? $atts['width'] : 600; + $height = ! empty( $atts['height'] ) ? $atts['height'] : 600; + return sprintf( + '<amp-instagram data-shortcode="%1$s" layout="responsive" width="%2$d" height="%3$d" data-captioned></amp-instagram>', + esc_attr( $shortcode_id ), + absint( $width ), + absint( $height ) + ); + } + return $wp_embed->shortcode( $atts, $atts['url'] ); } add_shortcode( 'instagram', 'jetpack_shortcode_instagram' ); diff --git a/plugins/jetpack/modules/shortcodes/js/gist.js b/plugins/jetpack/modules/shortcodes/js/gist.js index a97d7f91..d2d704dc 100644 --- a/plugins/jetpack/modules/shortcodes/js/gist.js +++ b/plugins/jetpack/modules/shortcodes/js/gist.js @@ -2,13 +2,18 @@ var gistStylesheetLoaded = false, gistEmbed = function() { $( '.gist-oembed' ).each( function( i, el ) { - var url = 'https://gist.github.com/' + $( el ).data( 'gist' ); + var url = 'https://gist.github.com/' + $( el ).data( 'gist' ), + ts = Number.parseInt( $( el ).data( 'ts' ), 10 ); $.ajax( { url: url, dataType: 'jsonp', } ).done( function( response ) { - $( el ).replaceWith( response.div ); + if ( ts && 8 !== ts ) { + $( el ).replaceWith( $( response.div ).css( 'tab-size', ts.toString() ) ); + } else { + $( el ).replaceWith( response.div ); + } if ( ! gistStylesheetLoaded ) { var stylesheet = diff --git a/plugins/jetpack/modules/shortcodes/js/jmpress.js b/plugins/jetpack/modules/shortcodes/js/jmpress.js index c6519cd9..907499bf 100644 --- a/plugins/jetpack/modules/shortcodes/js/jmpress.js +++ b/plugins/jetpack/modules/shortcodes/js/jmpress.js @@ -1307,7 +1307,7 @@ if ( item.length === 0 || item.closest( jmpress ).length === 0 ) { item = $( jmpress ) .find( stepSelector ) - [ prev ? 'last' : 'first' ](); + [ prev ? 'last' : 'first' ](); // eslint-disable-line no-unexpected-multiline } if ( ! item.length ) { return false; diff --git a/plugins/jetpack/modules/shortcodes/js/recipes-printthis.js b/plugins/jetpack/modules/shortcodes/js/recipes-printthis.js index e31fb24c..f2a1937c 100644 --- a/plugins/jetpack/modules/shortcodes/js/recipes-printthis.js +++ b/plugins/jetpack/modules/shortcodes/js/recipes-printthis.js @@ -1,4 +1,3 @@ -// jshint ignore: start /* * printThis v1.9.0 * @desc Printing plug-in for jQuery @@ -36,7 +35,6 @@ * Notes: * - the loadCSS will load additional css (with or without @media print) into the iframe, adjusting layout * - * jshint onevar: false, smarttabs: true, devel: true */ ( function( $ ) { var opt; diff --git a/plugins/jetpack/modules/shortcodes/js/slideshow-shortcode.js b/plugins/jetpack/modules/shortcodes/js/slideshow-shortcode.js index 44a2bd6f..e266465a 100644 --- a/plugins/jetpack/modules/shortcodes/js/slideshow-shortcode.js +++ b/plugins/jetpack/modules/shortcodes/js/slideshow-shortcode.js @@ -1,4 +1,3 @@ -/* jshint onevar:false, loopfunc:true */ /* global jetpackSlideshowSettings, escape */ function JetpackSlideshow( element, transition, autostart ) { diff --git a/plugins/jetpack/modules/shortcodes/medium.php b/plugins/jetpack/modules/shortcodes/medium.php index 02d02aaf..6285759e 100644 --- a/plugins/jetpack/modules/shortcodes/medium.php +++ b/plugins/jetpack/modules/shortcodes/medium.php @@ -1,16 +1,26 @@ <?php - -// Embed support for Medium https://medium.com/p/3eaed64aed8a - /** - * Faux-oembed support for Medium permalinks + * Embed support for Medium + * + * Supported formats: + * - Profiles: https://medium.com/@jeherve + * - Stories: https://medium.com/@jeherve/this-is-a-story-19f582daaf5b + * - And all the above in shortcode formats: + * [medium url="https://medium.com/@jeherve/this-is-a-story-19f582daaf5b" width="100%" border="false" collapsed="true"] * - * e.g. - * https://medium.com/help-center - * https://medium.com/@richroll + * @package Jetpack */ + +// Faux-oembed support for Medium permalinks. wp_embed_register_handler( 'medium', '#^https?://medium.com/([a-zA-z0-9-_@]+)#', 'jetpack_embed_medium_oembed' ); +/** + * Callback to modify output of embedded Medium posts. + * + * @param array $matches Regex partial matches against the URL passed. + * @param array $attr Attributes received in embed response. + * @param array $url Requested URL to be embedded. + */ function jetpack_embed_medium_oembed( $matches, $attr, $url ) { $attr = jetpack_embed_medium_args( $attr ); $attr['url'] = $url; @@ -18,6 +28,11 @@ function jetpack_embed_medium_oembed( $matches, $attr, $url ) { return jetpack_embed_medium_embed_html( $attr ); } +/** + * Return custom markup to display a Medium profile, collection, or story. + * + * @param array $args Attributes received in embed response. + */ function jetpack_embed_medium_embed_html( $args ) { $args = jetpack_embed_medium_args( $args ); @@ -27,36 +42,75 @@ function jetpack_embed_medium_embed_html( $args ) { $args['type'] = jetpack_embed_medium_get_embed_type( $args['url'] ); - return sprintf( '<script async src="https://static.medium.com/embed.js"></script><a class="m-%1$s" href="%2$s" target="_blank" data-width="%3$s" data-border="%4$s" data-collapsed="%5$s">View %1$s at Medium.com</a>', esc_attr( $args['type'] ), esc_url( $args['url'] ), esc_attr( $args['width'] ), esc_attr( $args['border'] ), esc_attr( $args['collapsed'] ) ); + if ( 'collection' === $args['type'] ) { + return sprintf( + '<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>', + esc_url( $args['url'] ), + esc_html__( 'View this collection on Medium.com', 'jetpack' ) + ); + } + + wp_enqueue_script( + 'medium-embed', + 'https://static.medium.com/embed.js', + array(), + JETPACK__VERSION, + true + ); + + return sprintf( + '<a class="m-%1$s" href="%2$s" target="_blank" data-width="%3$s" data-border="%4$s" data-collapsed="%5$s">%6$s</a>', + esc_attr( $args['type'] ), + esc_url( $args['url'] ), + esc_attr( $args['width'] ), + esc_attr( $args['border'] ), + esc_attr( $args['collapsed'] ), + esc_html__( 'View at Medium.com', 'jetpack' ) + ); } /** * Shortcode support that allows passing in URL * - * [medium url="https://medium.com/help-center" width="100%" border="false" collapsed="true"] + * @param array $atts Shortcode attributes. */ -add_shortcode( 'medium', 'jetpack_embed_medium_shortcode' ); - function jetpack_embed_medium_shortcode( $atts ) { $atts = jetpack_embed_medium_args( $atts ); if ( ! empty( $atts['url'] ) ) { global $wp_embed; return $wp_embed->shortcode( $atts, $atts['url'] ); + } else { + if ( current_user_can( 'edit_posts' ) ) { + return esc_html__( 'You did not provide a valid Medium URL.', 'jetpack' ); + } else { + return '<!-- Missing Medium URL -->'; + } } } +add_shortcode( 'medium', 'jetpack_embed_medium_shortcode' ); +/** + * Get embed type (profile, collection, or story) based on Medium URL. + * + * @param string $url Medium URL. + */ function jetpack_embed_medium_get_embed_type( $url ) { - $url_path = parse_url( $url, PHP_URL_PATH ); + $url_path = wp_parse_url( $url, PHP_URL_PATH ); if ( preg_match( '/^\/@[\.\w]+$/', $url_path ) ) { return 'profile'; - } elseif ( preg_match( '/^\/[\da-zA-Z-]+$/', $url_path ) ) { + } elseif ( preg_match( '/^\/(?:s)\/(.+)$/', $url_path ) ) { return 'collection'; } return 'story'; } +/** + * Process Medium shortcode attributes. + * + * @param array $atts Shortcode attributes. + */ function jetpack_embed_medium_args( $atts ) { return shortcode_atts( array( diff --git a/plugins/jetpack/modules/shortcodes/mixcloud.php b/plugins/jetpack/modules/shortcodes/mixcloud.php index 3580a924..4a016d5f 100644 --- a/plugins/jetpack/modules/shortcodes/mixcloud.php +++ b/plugins/jetpack/modules/shortcodes/mixcloud.php @@ -1,8 +1,8 @@ <?php -/* +/** * Mixcloud embeds * - * examples: + * Examples: * [mixcloud MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ /] * [mixcloud MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ width=640 height=480 /] * [mixcloud http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ /] @@ -10,21 +10,29 @@ * [mixcloud]http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/[/mixcloud] * [mixcloud]MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/[/mixcloud] * [mixcloud http://www.mixcloud.com/mat/playlists/classics/ width=660 height=208 hide_cover=1 hide_tracklist=1] -*/ + * + * @package Jetpack + */ -// Register oEmbed provider -// Example URL: http://www.mixcloud.com/oembed/?url=http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ +/* + * Register oEmbed provider + * Example URL: http://www.mixcloud.com/oembed/?url=http://www.mixcloud.com/MalibuRum/play-6-kissy-sellouts-winter-sun-house-party-mix/ + */ wp_oembed_add_provider( '#https?://(?:www\.)?mixcloud\.com/\S*#i', 'https://www.mixcloud.com/oembed', true ); -// Register mixcloud shortcode -add_shortcode( 'mixcloud', 'mixcloud_shortcode' ); +/** + * Register mixcloud shortcode. + * + * @param array $atts Shortcode atttributes. + * @param string $content Post content. + */ function mixcloud_shortcode( $atts, $content = null ) { if ( empty( $atts[0] ) && empty( $content ) ) { return '<!-- mixcloud error: invalid mixcloud resource -->'; } - $regular_expression = '/((?<=mixcloud\\.com\\/)[\\w-\\/]+$)|(^[\\w-\\/]+$)/i'; + $regular_expression = '/((?<=mixcloud\.com\/)[\w\-\/]+$)|(^[\w\-\/]+$)/i'; preg_match( $regular_expression, $content, $match ); if ( ! empty( $match ) ) { $resource_id = trim( $match[0] ); @@ -57,7 +65,7 @@ function mixcloud_shortcode( $atts, $content = null ) { $atts ); - // remove falsey values + // remove falsey values. $atts = array_filter( $atts ); $query_args = array( 'url' => $mixcloud_url ); @@ -73,3 +81,4 @@ function mixcloud_shortcode( $atts, $content = null ) { return $response_body->html; } +add_shortcode( 'mixcloud', 'mixcloud_shortcode' ); diff --git a/plugins/jetpack/modules/shortcodes/pinterest.php b/plugins/jetpack/modules/shortcodes/pinterest.php index caecc619..11e467f0 100644 --- a/plugins/jetpack/modules/shortcodes/pinterest.php +++ b/plugins/jetpack/modules/shortcodes/pinterest.php @@ -3,10 +3,13 @@ * Pinterest embeds * * Based on "Board Widget" example here: http://business.pinterest.com/widget-builder/#code + * + * Example URL: https://pinterest.com/pin/129056345550241149/ + * Second Example URL: https://uk.pinterest.com/annsawesomepins/travel/ + * + * @package Jetpack */ -// Example URL: http://pinterest.com/pinterest/pin-pets/ -// Second Example URL: https://uk.pinterest.com/annsawesomepins/travel/ wp_embed_register_handler( 'pinterest', '#' @@ -20,12 +23,20 @@ wp_embed_register_handler( 'pinterest_embed_handler' ); +/** + * Callback to modify output of embedded Pinterest posts. + * + * @param array $matches Regex partial matches against the URL passed. + * @param array $attr Attributes received in embed response. + * @param array $url Requested URL to be embedded. + */ function pinterest_embed_handler( $matches, $attr, $url ) { - // Pinterest's JS handles making the embed + // Pinterest's JS handles making the embed. $script_src = '//assets.pinterest.com/js/pinit.js'; - wp_enqueue_script( 'pinterest-embed', $script_src, array(), false, true ); - $path = parse_url( $url, PHP_URL_PATH ); + wp_enqueue_script( 'pinterest-embed', $script_src, array(), JETPACK__VERSION, true ); + + $path = wp_parse_url( $url, PHP_URL_PATH ); if ( 0 === strpos( $path, '/pin/' ) ) { $embed_type = 'embedPin'; } elseif ( preg_match( '#^/([^/]+)/?$#', $path ) ) { @@ -41,9 +52,12 @@ function pinterest_embed_handler( $matches, $attr, $url ) { $return = sprintf( '<a data-pin-do="%s" href="%s"></a>', esc_attr( $embed_type ), esc_url( $url ) ); - // If we're generating an embed view for the WordPress Admin via ajax... + // If we're generating an embed view for the WordPress Admin via ajax. if ( doing_action( 'wp_ajax_parse-embed' ) ) { - $return .= sprintf( '<script src="%s"></script>', esc_url( $script_src ) ); + $return .= sprintf( + '<script src="%s"></script>', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + esc_url( $script_src ) + ); } return $return; diff --git a/plugins/jetpack/modules/shortcodes/polldaddy.php b/plugins/jetpack/modules/shortcodes/polldaddy.php deleted file mode 100644 index 10a62d65..00000000 --- a/plugins/jetpack/modules/shortcodes/polldaddy.php +++ /dev/null @@ -1,4 +0,0 @@ -<?php -/** - * Deprecated alias for Crowdsignal. - */ diff --git a/plugins/jetpack/modules/shortcodes/presentations.php b/plugins/jetpack/modules/shortcodes/presentations.php index 77089189..8914b874 100644 --- a/plugins/jetpack/modules/shortcodes/presentations.php +++ b/plugins/jetpack/modules/shortcodes/presentations.php @@ -1,29 +1,48 @@ -<?php -/* -Plugin Name: Presentations -Plugin URI: http://automattic.com/wordpress-plugins/ -Description: Presentations plugin based on the work done by <a href="http://darylkoop.com/">Daryl Koopersmith</a>. Powered by jmpress.js -Version: 0.2 -Author: Automattic -Author URI: http://automattic.com/wordpress-plugins/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ +<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName +use Automattic\Jetpack\Assets; /** + * Presentations + * Presentations plugin based on the work done by <a href="http://darylkoop.com/">Daryl Koopersmith</a>. Powered by jmpress.js + * + * HOW TO: How the plugin settings are organized and which features are supported. + * + * The entire presentation should be wrapped with a [presentation] shortcode, and every + * individual slide should be wrapped with a [slide] shortcode. Any settings supported + * by [slide] can be set into [presentation], which will apply that setting for the entire + * presentation unless overridden by individual slides. + * + * - [presentation] only settings: + * - duration: transition durations, default is one second. + * - height: content height, default is 400px + * - width: content width, default is 550px + * - autoplay: delay between transitions in seconds, default 3s + * when set the presentation will automatically transition between slides + * as long as the presentation remains in focus + * + * - [slide] settings: + * - transition: specifies where the next slide will be placed relative + * to the last one before it. Supported values are "up", "down" + * "left", "right", or "none". Default value is "down". + * + * - scale: scales the content relative to other slides, default value is one + * + * - rotate: rotates the content by the specified degrees, default is zero + * + * - fade: slides will fade in and out during transition. Values of "on" or + * "true" will enable fading, while values of "no" or "false" will + * disable it. Default value is "on" + * + * - bgcolor: specifies a background color for the slides. Any CSS valid value + * is permitted. Default color is transparent. + * + * - bgimg: specifies an image url which will fill the background. Image is + * set to fill the background 100% width and height + * + * - fadebullets: any html <li> tags will start out with an opacity of 0 and any + * subsequent slide transitions will show the bullets one by one + * * Known issues: * * - IE 7/8 are not supported by jmpress and presentations will not work @@ -33,70 +52,53 @@ Author URI: http://automattic.com/wordpress-plugins/ * happens to be on the first loaded page. The permalink page will function * properly, however. * - Exiting fullscreen mode will not properly reset the scroll locations in Safari + * + * @package Jetpack */ - -/* -HOW TO: How the plugin settings are organized and which features are supported. - -The entire presentation should be wrapped with a [presentation] shortcode, and every -individual slide should be wrapped with a [slide] shortcode. Any settings supported -by [slide] can be set into [presentation], which will apply that setting for the entire -presentation unless overridden by individual slides. - -- [presentation] only settings: - - duration: transition durations, default is one second. - - height: content height, default is 400px - - width: content width, default is 550px - - autoplay: delay between transitions in seconds, default 3s - when set the presentation will automatically transition between slides - as long as the presentation remains in focus - -- [slide] settings: - - transition: specifies where the next slide will be placed relative - to the last one before it. Supported values are "up", "down" - "left", "right", or "none". Default value is "down". - - - scale: scales the content relative to other slides, default value is one - - - rotate: rotates the content by the specified degrees, default is zero - - - fade: slides will fade in and out during transition. Values of "on" or - "true" will enable fading, while values of "no" or "false" will - disable it. Default value is "on" - - - bgcolor: specifies a background color for the slides. Any CSS valid value - is permitted. Default color is transparent. - - - bgimg: specifies an image url which will fill the background. Image is - set to fill the background 100% width and height - - - fadebullets: any html <li> tags will start out with an opacity of 0 and any - subsequent slide transitions will show the bullets one by one -*/ - if ( ! class_exists( 'Presentations' ) ) : + /** + * Create a shortcode to display Presentations and slides. + */ class Presentations { + /** + * Presentation settings. + * + * @var array + */ private $presentation_settings; + /** + * Do we have a Presentation shortcode to be displayed. + * + * @var bool + */ private $presentation_initialized; + /** + * Were scripts and styles enqueued already. + * + * @var bool + */ private $scripts_and_style_included; /** * Constructor */ - function __construct() { + public function __construct() { $this->presentation_initialized = false; $this->scripts_and_style_included = false; - // Registers shortcodes + // Registers shortcodes. add_action( 'wp_head', array( &$this, 'add_scripts' ), 1 ); add_shortcode( 'presentation', array( &$this, 'presentation_shortcode' ) ); add_shortcode( 'slide', array( &$this, 'slide_shortcode' ) ); } - function add_scripts() { + /** + * Enqueue all scripts and styles. + */ + public function add_scripts() { $this->scripts_and_style_included = false; if ( empty( $GLOBALS['posts'] ) || ! is_array( $GLOBALS['posts'] ) ) { @@ -115,28 +117,34 @@ if ( ! class_exists( 'Presentations' ) ) : } $plugin = plugin_dir_url( __FILE__ ); - // Add CSS - wp_enqueue_style( 'presentations', $plugin . 'css/style.css' ); - // Add JavaScript + // Add CSS. + wp_enqueue_style( 'presentations', $plugin . 'css/style.css', array(), JETPACK__VERSION ); + // Add JavaScript. wp_enqueue_script( 'jquery' ); wp_enqueue_script( 'jmpress', - Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/jmpress.min.js', 'modules/shortcodes/js/jmpress.js' ), + Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/jmpress.min.js', 'modules/shortcodes/js/jmpress.js' ), array( 'jquery' ), - '0.4.5', + JETPACK__VERSION, true ); wp_enqueue_script( 'presentations', - Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/main.min.js', 'modules/shortcodes/js/main.js' ), + Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/main.min.js', 'modules/shortcodes/js/main.js' ), array( 'jquery', 'jmpress' ), - false, + JETPACK__VERSION, true ); } - function presentation_shortcode( $atts, $content = '' ) { - // Mark that we've found a valid [presentation] shortcode + /** + * Main Presentation shortcode. + * + * @param array $atts Shortcode attributes. + * @param string $content Post content. + */ + public function presentation_shortcode( $atts, $content = '' ) { + // Mark that we've found a valid [presentation] shortcode. $this->presentation_initialized = true; $atts = shortcode_atts( @@ -148,7 +156,7 @@ if ( ! class_exists( 'Presentations' ) ) : 'bgimg' => '', 'autoplay' => '', - // Settings + // Settings. 'transition' => '', 'scale' => '', 'rotate' => '', @@ -173,73 +181,75 @@ if ( ! class_exists( 'Presentations' ) ) : ), ); - // Set the presentation-wide settings - if ( '' != trim( $atts['transition'] ) ) { + // Set the presentation-wide settings. + if ( '' !== trim( $atts['transition'] ) ) { $this->presentation_settings['transition'] = $atts['transition']; } - if ( '' != trim( $atts['scale'] ) ) { + if ( '' !== trim( $atts['scale'] ) ) { $this->presentation_settings['scale'] = floatval( $atts['scale'] ); } - if ( '' != trim( $atts['rotate'] ) ) { + if ( '' !== trim( $atts['rotate'] ) ) { $this->presentation_settings['rotate'] = floatval( $atts['rotate'] ); } - if ( '' != trim( $atts['fade'] ) ) { + if ( '' !== trim( $atts['fade'] ) ) { $this->presentation_settings['fade'] = $atts['fade']; } - if ( '' != trim( $atts['fadebullets'] ) ) { + if ( '' !== trim( $atts['fadebullets'] ) ) { $this->presentation_settings['fadebullets'] = $atts['fadebullets']; } - // Set any settings the slides don't care about - if ( '' != trim( $atts['duration'] ) ) { + // Set any settings the slides don't care about. + if ( '' !== trim( $atts['duration'] ) ) { $duration = floatval( $atts['duration'] ) . 's'; } else { $duration = '1s'; } - // Autoplay durations are set in milliseconds - if ( '' != trim( $atts['autoplay'] ) ) { + // Autoplay durations are set in milliseconds. + if ( '' !== trim( $atts['autoplay'] ) ) { $autoplay = floatval( $atts['autoplay'] ) * 1000; } else { $autoplay = 0; } // No autoplay - // Set the presentation size as specified or with some nicely sized dimensions - if ( '' != trim( $atts['width'] ) ) { + // Set the presentation size as specified or with some nicely sized dimensions. + if ( '' !== trim( $atts['width'] ) ) { $this->presentation_settings['width'] = intval( $atts['width'] ); } else { $this->presentation_settings['width'] = 480; } - if ( '' != trim( $atts['height'] ) ) { + if ( '' !== trim( $atts['height'] ) ) { $this->presentation_settings['height'] = intval( $atts['height'] ); } else { $this->presentation_settings['height'] = 370; } - // Hide the content by default in case the scripts fail + // Hide the content by default in case the scripts fail. $style = 'display: none; width: ' . $this->presentation_settings['width'] . 'px; height: ' . $this->presentation_settings['height'] . 'px;'; - // Check for background color XOR background image - // Use a white background if nothing specified + /* + * Check for background color XOR background image + * Use a white background if nothing specified + */ if ( preg_match( '/https?\:\/\/[^\'"\s]*/', $atts['bgimg'], $matches ) ) { $style .= ' background-image: url("' . esc_url( $matches[0] ) . '");'; - } elseif ( '' != trim( $atts['bgcolor'] ) ) { + } elseif ( '' !== trim( $atts['bgcolor'] ) ) { $style .= ' background-color: ' . esc_attr( $atts['bgcolor'] ) . ';'; } else { $style .= ' background-color: #fff;'; } - // Not supported message style is inlined incase the style sheet doesn't get included + // Not supported message style is inlined incase the style sheet doesn't get included. $out = "<section class='presentation-wrapper'>"; $out .= "<p class='not-supported-msg' style='display: inherit; padding: 25%; text-align: center;'>"; $out .= __( 'This slideshow could not be started. Try refreshing the page or viewing it in another browser.', 'jetpack' ) . '</p>'; - // Bail out unless the scripts were added + // Bail out unless the scripts were added. if ( $this->scripts_and_style_included ) { $out .= sprintf( '<div class="presentation" duration="%s" data-autoplay="%s" style="%s">', @@ -267,8 +277,14 @@ if ( ! class_exists( 'Presentations' ) ) : return $out; } - function slide_shortcode( $atts, $content = '' ) { - // Bail out unless wrapped by a [presentation] shortcode + /** + * Slide shortcode. + * + * @param array $atts Shortcode attributes. + * @param string $content Post content. + */ + public function slide_shortcode( $atts, $content = '' ) { + // Bail out unless wrapped by a [presentation] shortcode. if ( ! $this->presentation_initialized ) { return $content; } @@ -287,17 +303,17 @@ if ( ! class_exists( 'Presentations' ) ) : 'slide' ); - // Determine positioning based on transition - if ( '' == trim( $atts['transition'] ) ) { + // Determine positioning based on transition. + if ( '' === trim( $atts['transition'] ) ) { $atts['transition'] = $this->presentation_settings['transition']; } - // Setting the content scale - if ( '' == trim( $atts['scale'] ) ) { + // Setting the content scale. + if ( '' === trim( $atts['scale'] ) ) { $atts['scale'] = $this->presentation_settings['scale']; } - if ( '' == trim( $atts['scale'] ) ) { + if ( '' === trim( $atts['scale'] ) ) { $scale = 1; } else { $scale = floatval( $atts['scale'] ); @@ -307,34 +323,34 @@ if ( ! class_exists( 'Presentations' ) ) : $scale *= -1; } - // Setting the content rotation - if ( '' == trim( $atts['rotate'] ) ) { + // Setting the content rotation. + if ( '' === trim( $atts['rotate'] ) ) { $atts['rotate'] = $this->presentation_settings['rotate']; } - if ( '' == trim( $atts['rotate'] ) ) { + if ( '' === trim( $atts['rotate'] ) ) { $rotate = 0; } else { $rotate = floatval( $atts['rotate'] ); } - // Setting if the content should fade - if ( '' == trim( $atts['fade'] ) ) { + // Setting if the content should fade. + if ( '' === trim( $atts['fade'] ) ) { $atts['fade'] = $this->presentation_settings['fade']; } - if ( 'on' == $atts['fade'] || 'true' == $atts['fade'] ) { + if ( 'on' === $atts['fade'] || 'true' === $atts['fade'] ) { $fade = 'fade'; } else { $fade = ''; } - // Setting if bullets should fade on step changes - if ( '' == trim( $atts['fadebullets'] ) ) { + // Setting if bullets should fade on step changes. + if ( '' === trim( $atts['fadebullets'] ) ) { $atts['fadebullets'] = $this->presentation_settings['fadebullets']; } - if ( 'on' == $atts['fadebullets'] || 'true' == $atts['fadebullets'] ) { + if ( 'on' === $atts['fadebullets'] || 'true' === $atts['fadebullets'] ) { $fadebullets = 'fadebullets'; } else { $fadebullets = ''; @@ -351,11 +367,13 @@ if ( ! class_exists( 'Presentations' ) ) : $x = $coords['x']; $y = $coords['y']; - // Check for background color XOR background image - // Use a white background if nothing specified + /* + * Check for background color XOR background image + * Use a white background if nothing specified + */ if ( preg_match( '/https?\:\/\/[^\'"\s]*/', $atts['bgimg'], $matches ) ) { $style = 'background-image: url("' . esc_url( $matches[0] ) . '");'; - } elseif ( '' != trim( $atts['bgcolor'] ) ) { + } elseif ( '' !== trim( $atts['bgcolor'] ) ) { $style = 'background-color: ' . esc_attr( $atts['bgcolor'] ) . ';'; } else { $style = ''; @@ -383,14 +401,17 @@ if ( ! class_exists( 'Presentations' ) ) : /** * Determines the position of the next slide based on the position and scaling of the previous slide. * - * @param array $args : an array with the following key-value pairs - * string $transition: the transition name, "up", "down", "left", or "right" - * float $scale: the scale of the next slide (used to determine the position of the slide after that) + * @param array $args { + * Array of key-value pairs. + * + * @type string $transition: the transition name, "up", "down", "left", or "right". + * @type float $scale: the scale of the next slide (used to determine the position of the slide after that). + * } * - * @return array with the 'x' and 'y' coordinates of the slide + * @return array with the 'x' and 'y' coordinates of the slide. */ - function get_coords( $args ) { - if ( 0 == $args['scale'] ) { + private function get_coords( $args ) { + if ( 0 === $args['scale'] ) { $args['scale'] = 1; } @@ -407,30 +428,36 @@ if ( ! class_exists( 'Presentations' ) ) : ); // All angles are measured from the vertical axis, so everything is backwards! - $diagAngle = atan2( $width, $height ); - $diagonal = sqrt( pow( $width, 2 ) + pow( $height, 2 ) ); - - // We offset the angles by the angle formed by the diagonal so that - // we can multiply the sines directly against the diagonal length - $theta = deg2rad( $last['rotate'] ) - $diagAngle; - $phi = deg2rad( $next['rotate'] ) - $diagAngle; - - // We start by displacing by the slide dimensions - $totalHorizDisp = $width * $scale; - $totalVertDisp = $height * $scale; - - // If the previous slide was rotated, we add the incremental offset from the rotation - // Namely the difference between the regular dimension (no rotation) and the component - // of the diagonal for that angle - $totalHorizDisp += ( ( ( abs( sin( $theta ) ) * $diagonal ) - $width ) / 2 ) * $scale; - $totalVertDisp += ( ( ( abs( cos( $theta ) ) * $diagonal ) - $height ) / 2 ) * $scale; - - // Similarly, we check if the current slide has been rotated and add whatever additional - // offset has been added. This is so that two rotated corners don't clash with each other. - // Note: we are checking the raw angle relative to the vertical axis, NOT the diagonal angle. + $diag_angle = atan2( $width, $height ); + $diagonal = sqrt( pow( $width, 2 ) + pow( $height, 2 ) ); + + /* + * We offset the angles by the angle formed by the diagonal so that + * we can multiply the sines directly against the diagonal length + */ + $theta = deg2rad( $last['rotate'] ) - $diag_angle; + $phi = deg2rad( $next['rotate'] ) - $diag_angle; + + // We start by displacing by the slide dimensions. + $total_horiz_disp = $width * $scale; + $total_vert_disp = $height * $scale; + + /* + * If the previous slide was rotated, we add the incremental offset from the rotation + * Namely the difference between the regular dimension (no rotation) and the component + * of the diagonal for that angle + */ + $total_horiz_disp += ( ( ( abs( sin( $theta ) ) * $diagonal ) - $width ) / 2 ) * $scale; + $total_vert_disp += ( ( ( abs( cos( $theta ) ) * $diagonal ) - $height ) / 2 ) * $scale; + + /* + * Similarly, we check if the current slide has been rotated and add whatever additional + * offset has been added. This is so that two rotated corners don't clash with each other. + * Note: we are checking the raw angle relative to the vertical axis, NOT the diagonal angle. + */ if ( 0 !== $next['rotate'] % 180 ) { - $totalHorizDisp += ( abs( ( sin( $phi ) * $diagonal ) - $width ) / 2 ) * $next['scale']; - $totalVertDisp += ( abs( ( cos( $phi ) * $diagonal ) - $height ) / 2 ) * $next['scale']; + $total_horiz_disp += ( abs( ( sin( $phi ) * $diagonal ) - $width ) / 2 ) * $next['scale']; + $total_vert_disp += ( abs( ( cos( $phi ) * $diagonal ) - $height ) / 2 ) * $next['scale']; } switch ( trim( $args['transition'] ) ) { @@ -438,20 +465,20 @@ if ( ! class_exists( 'Presentations' ) ) : break; case 'left': - $next['x'] -= $totalHorizDisp; + $next['x'] -= $total_horiz_disp; break; case 'right': - $next['x'] += $totalHorizDisp; + $next['x'] += $total_horiz_disp; break; case 'up': - $next['y'] -= $totalVertDisp; + $next['y'] -= $total_vert_disp; break; case 'down': default: - $next['y'] += $totalVertDisp; + $next['y'] += $total_vert_disp; break; } diff --git a/plugins/jetpack/modules/shortcodes/quiz.php b/plugins/jetpack/modules/shortcodes/quiz.php index fa4ed960..e9275a67 100644 --- a/plugins/jetpack/modules/shortcodes/quiz.php +++ b/plugins/jetpack/modules/shortcodes/quiz.php @@ -1,4 +1,7 @@ <?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileNam + +use Automattic\Jetpack\Assets; + /** * Quiz shortcode. * @@ -81,7 +84,7 @@ class Quiz_Shortcode { wp_enqueue_style( 'quiz', plugins_url( 'css/quiz.css', __FILE__ ), array(), JETPACK__VERSION ); wp_enqueue_script( 'quiz', - Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/quiz.min.js', 'modules/shortcodes/js/quiz.js' ), + Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/quiz.min.js', 'modules/shortcodes/js/quiz.js' ), array( 'jquery' ), JETPACK__VERSION, true diff --git a/plugins/jetpack/modules/shortcodes/recipe.php b/plugins/jetpack/modules/shortcodes/recipe.php index 7846b154..983f01ee 100644 --- a/plugins/jetpack/modules/shortcodes/recipe.php +++ b/plugins/jetpack/modules/shortcodes/recipe.php @@ -1,4 +1,6 @@ -<?php +<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName + +use Automattic\Jetpack\Assets; /** * Embed recipe 'cards' in post, with basic styling and print functionality @@ -8,80 +10,63 @@ * - basic styles/themecolor styles * - validation/sanitization * - print styles + * + * @package Jetpack */ -class Jetpack_Recipes { - - private $scripts_and_style_included = false; - - function __construct() { - add_action( 'init', array( $this, 'action_init' ) ); - add_filter( 'wp_kses_allowed_html', array( $this, 'add_recipes_kses_rules' ), 10, 2 ); - } +/** + * Register and display Recipes in posts. + */ +class Jetpack_Recipes { /** - * Add Schema-specific attributes to our allowed tags in wp_kses, - * so we can have better Schema.org compliance. + * Have scripts and styles been enqueued already. * - * @param array $allowedtags Array of allowed HTML tags in recipes. - * @param array $context Context to judge allowed tags by. + * @var bool */ - function add_recipes_kses_rules( $allowedtags, $context ) { - if ( in_array( $context, array( '', 'post', 'data' ) ) ) : - // Create an array of all the tags we'd like to add the itemprop attribute to. - $tags = array( 'li', 'ol', 'ul', 'img', 'p', 'h3', 'time' ); - foreach ( $tags as $tag ) { - $allowedtags = $this->add_kses_rule( - $allowedtags, - $tag, - array( - 'class' => array(), - 'itemprop' => array(), - 'datetime' => array(), - ) - ); - } - - // Allow itemscope and itemtype for divs. - $allowedtags = $this->add_kses_rule( - $allowedtags, - 'div', - array( - 'class' => array(), - 'itemscope' => array(), - 'itemtype' => array(), - ) - ); - endif; + private $scripts_and_style_included = false; - return $allowedtags; + /** + * Constructor + */ + public function __construct() { + add_action( 'init', array( $this, 'action_init' ) ); } /** - * Function to add a new property rule to our kses array. - * Used by add_recipe_kses_rules() above. + * Returns KSES tags with Schema-specific attributes. * - * @param array $all_tags Array of allowed HTML tags in recipes. - * @param string $tag New HTML tag to add to the array of allowed HTML. - * @param array $rules Array of allowed attributes for that HTML tag. + * @since 8.0.0 + * + * @return array Array to be used by KSES. */ - private function add_kses_rule( $all_tags, $tag, $rules ) { - - // If the tag doesn't already exist, add it. - if ( ! isset( $all_tags[ $tag ] ) ) { - $all_tags[ $tag ] = array(); + private static function kses_tags() { + $allowedtags = wp_kses_allowed_html( 'post' ); + // Create an array of all the tags we'd like to add the itemprop attribute to. + $tags = array( 'li', 'ol', 'ul', 'img', 'p', 'h3', 'time', 'span' ); + foreach ( $tags as $tag ) { + if ( ! isset( $allowedtags[ $tag ] ) ) { + $allowedtags[ $tag ] = array(); + } + $allowedtags[ $tag ]['class'] = array(); + $allowedtags[ $tag ]['itemprop'] = array(); + $allowedtags[ $tag ]['datetime'] = array(); } - // Merge the new tags with existing tags. - $all_tags[ $tag ] = array_merge( $all_tags[ $tag ], $rules ); - - return $all_tags; + // Allow itemscope and itemtype for divs. + if ( ! isset( $allowedtags['div'] ) ) { + $allowedtags['div'] = array(); + } + $allowedtags['div']['class'] = array(); + $allowedtags['div']['itemscope'] = array(); + $allowedtags['div']['itemtype'] = array(); + return $allowedtags; } /** * Register our shortcode and enqueue necessary files. */ - function action_init() { + public function action_init() { // Enqueue styles if [recipe] exists. add_action( 'wp_head', array( $this, 'add_scripts' ), 1 ); @@ -90,12 +75,14 @@ class Jetpack_Recipes { add_shortcode( 'recipe-notes', array( $this, 'recipe_notes_shortcode' ) ); add_shortcode( 'recipe-ingredients', array( $this, 'recipe_ingredients_shortcode' ) ); add_shortcode( 'recipe-directions', array( $this, 'recipe_directions_shortcode' ) ); + add_shortcode( 'recipe-nutrition', array( $this, 'recipe_nutrition_shortcode' ) ); + add_shortcode( 'recipe-image', array( $this, 'recipe_image_shortcode' ) ); } /** * Enqueue scripts and styles */ - function add_scripts() { + public function add_scripts() { if ( empty( $GLOBALS['posts'] ) || ! is_array( $GLOBALS['posts'] ) ) { return; } @@ -116,19 +103,20 @@ class Jetpack_Recipes { // add $themecolors-defined styles. wp_add_inline_style( 'jetpack-recipes-style', self::themecolor_styles() ); - wp_enqueue_script( 'jetpack-recipes-printthis', - Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/recipes-printthis.min.js', 'modules/shortcodes/js/recipes-printthis.js' ), + Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/recipes-printthis.min.js', 'modules/shortcodes/js/recipes-printthis.js' ), array( 'jquery' ), - '20170202' + '20170202', + false ); wp_enqueue_script( 'jetpack-recipes-js', - Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/recipes.min.js', 'modules/shortcodes/js/recipes.js' ), + Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/recipes.min.js', 'modules/shortcodes/js/recipes.js' ), array( 'jquery', 'jetpack-recipes-printthis' ), - '20131230' + '20131230', + false ); $title_var = wp_title( '|', false, 'right' ); @@ -154,18 +142,21 @@ class Jetpack_Recipes { * * @return string HTML for recipe shortcode. */ - static function recipe_shortcode( $atts, $content = '' ) { + public static function recipe_shortcode( $atts, $content = '' ) { $atts = shortcode_atts( array( 'title' => '', // string. 'servings' => '', // intval. - 'time' => '', // string. + 'time' => '', // strtotime-compatible time description. 'difficulty' => '', // string. - 'print' => '', // string. + 'print' => '', // URL for external print version. 'source' => '', // string. - 'sourceurl' => '', // string. - 'image' => '', // string. + 'sourceurl' => '', // URL string. Only used if source set. + 'image' => '', // URL or attachment ID. 'description' => '', // string. + 'cooktime' => '', // strtotime-compatible time description. + 'preptime' => '', // strtotime-compatible time description. + 'rating' => '', // string. ), $atts, 'recipe' @@ -182,43 +173,41 @@ class Jetpack_Recipes { * * @return string HTML output */ - static function recipe_shortcode_html( $atts, $content = '' ) { + private static function recipe_shortcode_html( $atts, $content = '' ) { - $html = '<div class="hrecipe jetpack-recipe" itemscope itemtype="https://schema.org/Recipe">'; + $html = '<div class="hrecipe h-recipe jetpack-recipe" itemscope itemtype="https://schema.org/Recipe">'; // Print the recipe title if exists. if ( '' !== $atts['title'] ) { - $html .= '<h3 class="jetpack-recipe-title" itemprop="name">' . esc_html( $atts['title'] ) . '</h3>'; + $html .= '<h3 class="p-name jetpack-recipe-title fn" itemprop="name">' . esc_html( $atts['title'] ) . '</h3>'; } // Print the recipe meta if exists. - if ( '' !== $atts['servings'] || '' != $atts['time'] || '' != $atts['difficulty'] || '' != $atts['print'] ) { + if ( + '' !== $atts['servings'] + || '' !== $atts['time'] + || '' !== $atts['difficulty'] + || '' !== $atts['print'] + || '' !== $atts['preptime'] + || '' !== $atts['cooktime'] + || '' !== $atts['rating'] + ) { $html .= '<ul class="jetpack-recipe-meta">'; if ( '' !== $atts['servings'] ) { $html .= sprintf( - '<li class="jetpack-recipe-servings" itemprop="recipeYield"><strong>%1$s: </strong>%2$s</li>', + '<li class="jetpack-recipe-servings p-yield yield" itemprop="recipeYield"><strong>%1$s: </strong>%2$s</li>', esc_html_x( 'Servings', 'recipe', 'jetpack' ), esc_html( $atts['servings'] ) ); } - if ( '' !== $atts['time'] ) { - // Get a time that's supported by Schema.org. - $duration = WPCOM_JSON_API_Date::format_duration( $atts['time'] ); - // If no duration can be calculated, let's output what the user provided. - if ( empty( $duration ) ) { - $duration = $atts['time']; + $time_types = array( 'cooktime', 'preptime', 'time' ); + foreach ( $time_types as $time_type ) { + if ( '' === $atts[ $time_type ] ) { + continue; } - - $html .= sprintf( - '<li class="jetpack-recipe-time"> - <time itemprop="totalTime" datetime="%3$s"><strong>%1$s: </strong>%2$s</time> - </li>', - esc_html_x( 'Time', 'recipe', 'jetpack' ), - esc_html( $atts['time'] ), - esc_attr( $duration ) - ); + $html .= self::output_time( $atts[ $time_type ], $time_type ); } if ( '' !== $atts['difficulty'] ) { @@ -229,6 +218,17 @@ class Jetpack_Recipes { ); } + if ( '' !== $atts['rating'] ) { + $html .= sprintf( + '<li class="jetpack-recipe-rating"> + <strong>%1$s: </strong> + <span itemprop="contentRating">%2$s</span> + </li>', + esc_html_x( 'Rating', 'recipe', 'jetpack' ), + esc_html( $atts['rating'] ) + ); + } + if ( '' !== $atts['source'] ) { $html .= sprintf( '<li class="jetpack-recipe-source"><strong>%1$s: </strong>', @@ -261,14 +261,13 @@ class Jetpack_Recipes { } $html .= '</ul>'; - } // End if(). + } - // Output the image, if we have one. + // Output the image if we have one and it's not shown elsewhere. if ( '' !== $atts['image'] ) { - $html .= sprintf( - '<img class="jetpack-recipe-image" itemprop="image" src="%1$s" />', - esc_url( $atts['image'] ) - ); + if ( ! has_shortcode( $content, 'recipe-image' ) ) { + $html .= self::output_image_html( $atts['image'] ); + } } // Output the description, if we have one. @@ -291,13 +290,37 @@ class Jetpack_Recipes { } // Sanitize html. - $html = wp_kses_post( $html ); + $html = wp_kses( $html, self::kses_tags() ); // Return the HTML block. return $html; } /** + * Our [recipe-image] shortcode. + * Controls placement of image in recipe. + * + * @param array $atts Array of shortcode attributes. + * + * @return string HTML for recipe notes shortcode. + */ + public static function recipe_image_shortcode( $atts ) { + $atts = shortcode_atts( + array( + 'image' => '', // string. + 0 => '', // string. + ), + $atts, + 'recipe-image' + ); + $src = $atts['image']; + if ( ! empty( $atts[0] ) ) { + $src = $atts[0]; + } + return self::output_image_html( $src ); + } + + /** * Our [recipe-notes] shortcode. * Outputs ingredients, styled in a div. * @@ -306,7 +329,7 @@ class Jetpack_Recipes { * * @return string HTML for recipe notes shortcode. */ - static function recipe_notes_shortcode( $atts, $content = '' ) { + public static function recipe_notes_shortcode( $atts, $content = '' ) { $atts = shortcode_atts( array( 'title' => '', // string. @@ -330,7 +353,7 @@ class Jetpack_Recipes { $html .= '</div>'; // Sanitize html. - $html = wp_kses_post( $html ); + $html = wp_kses( $html, self::kses_tags() ); // Return the HTML block. return $html; @@ -345,7 +368,7 @@ class Jetpack_Recipes { * * @return string HTML for recipe ingredients shortcode. */ - static function recipe_ingredients_shortcode( $atts, $content = '' ) { + public static function recipe_ingredients_shortcode( $atts, $content = '' ) { $atts = shortcode_atts( array( 'title' => esc_html_x( 'Ingredients', 'recipe', 'jetpack' ), // string. @@ -367,7 +390,44 @@ class Jetpack_Recipes { $html .= '</div>'; // Sanitize html. - $html = wp_kses_post( $html ); + $html = wp_kses( $html, self::kses_tags() ); + + // Return the HTML block. + return $html; + } + + /** + * Our [recipe-nutrition] shortcode. + * Outputs notes, styled in a div. + * + * @param array $atts Array of shortcode attributes. + * @param string $content Post content. + * + * @return string HTML for recipe nutrition shortcode. + */ + public static function recipe_nutrition_shortcode( $atts, $content = '' ) { + $atts = shortcode_atts( + array( + 'title' => esc_html_x( 'Nutrition', 'recipe', 'jetpack' ), // string. + ), + $atts, + 'recipe-nutrition' + ); + + $html = '<div class="jetpack-recipe-nutrition p-nutrition nutrition">'; + + // Print a title unless the user has opted to exclude it. + if ( 'false' !== $atts['title'] ) { + $html .= '<h4 class="jetpack-recipe-nutrition-title">' . esc_html( $atts['title'] ) . '</h4>'; + } + + // Format content using list functionality. + $html .= self::output_list_content( $content, 'nutrition' ); + + $html .= '</div>'; + + // Sanitize html. + $html = wp_kses( $html, self::kses_tags() ); // Return the HTML block. return $html; @@ -387,7 +447,7 @@ class Jetpack_Recipes { * * @return string content formatted as a list item */ - static function output_list_content( $content, $type ) { + private static function output_list_content( $content, $type ) { $html = ''; switch ( $type ) { @@ -397,10 +457,20 @@ class Jetpack_Recipes { $listtype = 'ol'; break; case 'ingredients': - $list_item_replacement = '<li class="jetpack-recipe-ingredient" itemprop="recipeIngredient">${1}</li>'; + $list_item_replacement = '<li class="jetpack-recipe-ingredient p-ingredient ingredient" itemprop="recipeIngredient">${1}</li>'; $itemprop = ''; $listtype = 'ul'; break; + case 'nutrition': + $list_item_replacement = '<li class="jetpack-recipe-nutrition">${1}</li>'; + $itemprop = ' itemprop="nutrition"'; + $listtype = 'ul'; + break; + case 'nutrition': + $list_item_replacement = '<li class="jetpack-recipe-nutrition nutrition">${1}</li>'; + $itemprop = ' itemprop="nutrition"'; + $listtype = 'ul'; + break; default: $list_item_replacement = '<li class="jetpack-recipe-notes">${1}</li>'; $itemprop = ''; @@ -464,7 +534,7 @@ class Jetpack_Recipes { * * @return string HTML for recipe directions shortcode. */ - static function recipe_directions_shortcode( $atts, $content = '' ) { + public static function recipe_directions_shortcode( $atts, $content = '' ) { $atts = shortcode_atts( array( 'title' => esc_html_x( 'Directions', 'recipe', 'jetpack' ), // string. @@ -473,7 +543,7 @@ class Jetpack_Recipes { 'recipe-directions' ); - $html = '<div class="jetpack-recipe-directions">'; + $html = '<div class="jetpack-recipe-directions e-instructions">'; // Print a title unless the user has specified to exclude it. if ( 'false' !== $atts['title'] ) { @@ -486,19 +556,102 @@ class Jetpack_Recipes { $html .= '</div>'; // Sanitize html. - $html = wp_kses_post( $html ); + $html = wp_kses( $html, self::kses_tags() ); // Return the HTML block. return $html; } /** + * Outputs time meta tag. + * + * @param string $time_str Raw time to output. + * @param string $time_type Type of time to show. + * + * @return string HTML for recipe time meta. + */ + private static function output_time( $time_str, $time_type ) { + // Get a time that's supported by Schema.org. + $duration = WPCOM_JSON_API_Date::format_duration( $time_str ); + // If no duration can be calculated, let's output what the user provided. + if ( ! $duration ) { + $duration = $time_str; + } + + switch ( $time_type ) { + case 'cooktime': + $title = _x( 'Cook Time', 'recipe', 'jetpack' ); + $itemprop = 'cookTime'; + break; + case 'preptime': + $title = _x( 'Prep Time', 'recipe', 'jetpack' ); + $itemprop = 'prepTime'; + break; + default: + $title = _x( 'Time', 'recipe', 'jetpack' ); + $itemprop = 'totalTime'; + break; + } + + return sprintf( + '<li class="jetpack-recipe-%3$s"> + <time itemprop="%4$s" datetime="%5$s"><strong>%1$s:</strong> <span class="%3$s">%2$s</span></time> + </li>', + esc_html( $title ), + esc_html( $time_str ), + esc_attr( $time_type ), + esc_attr( $itemprop ), + esc_attr( $duration ) + ); + } + + /** + * Outputs image tag for recipe. + * + * @param string $src The image source. + * + * @return string + */ + private static function output_image_html( $src ) { + // Exit if there is no provided source. + if ( ! $src ) { + return ''; + } + + // If it's numeric, this may be an attachment. + if ( is_numeric( $src ) ) { + return wp_get_attachment_image( + $src, + 'full', + false, + array( + 'class' => 'jetpack-recipe-image u-photo photo', + 'itemprop' => 'image', + ) + ); + } + + // Check if it's an absolute or relative URL, and return if not. + if ( + 0 !== strpos( $src, '/' ) + && false === filter_var( $src, FILTER_VALIDATE_URL ) + ) { + return ''; + } + + return sprintf( + '<img class="jetpack-recipe-image u-photo photo" itemprop="image" src="%1$s" />', + esc_url( $src ) + ); + } + + /** * Use $themecolors array to style the Recipes shortcode * * @print style block * @return string $style */ - function themecolor_styles() { + public function themecolor_styles() { global $themecolors; $style = ''; diff --git a/plugins/jetpack/modules/shortcodes/scribd.php b/plugins/jetpack/modules/shortcodes/scribd.php index 1810c2fa..a0101ad2 100644 --- a/plugins/jetpack/modules/shortcodes/scribd.php +++ b/plugins/jetpack/modules/shortcodes/scribd.php @@ -1,17 +1,22 @@ <?php +/** + * Scribd Shortcode + * + * [scribd id=DOCUMENT_ID key=DOCUMENT_KEY mode=MODE] + * DOCUMENT_ID is an integer (also used as an object_id) + * DOCUMENT_KEY is an alphanumeric hash ('-' character as well) + * MODE can be 'list', 'book', 'slide', 'slideshow', or 'tile' + * + * [scribd id=39027960 key=key-3kaiwcjqhtipf25m8tw mode=list] + * + * @package Jetpack + */ -/* - Scribd Short Code -Author: Nick Momrik - -[scribd id=DOCUMENT_ID key=DOCUMENT_KEY mode=MODE] -DOCUMENT_ID is an integer (also used as an object_id) -DOCUMENT_KEY is an alphanumeric hash ('-' character as well) -MODE can be 'list', 'book', 'slide', 'slideshow', or 'tile' - -[scribd id=39027960 key=key-3kaiwcjqhtipf25m8tw mode=list] -*/ - +/** + * Register Scribd shortcode. + * + * @param array $atts Shortcode attributes. + */ function scribd_shortcode_handler( $atts ) { $atts = shortcode_atts( array( @@ -29,7 +34,7 @@ function scribd_shortcode_handler( $atts ) { if ( preg_match( '/^[A-Za-z0-9-]+$/', $atts['key'], $m ) ) { $atts['key'] = $m[0]; - if ( ! in_array( $atts['mode'], $modes ) ) { + if ( ! in_array( $atts['mode'], $modes, true ) ) { $atts['mode'] = ''; } @@ -39,18 +44,26 @@ function scribd_shortcode_handler( $atts ) { } } +/** + * Display the shortcode. + * + * @param array $atts Shortcode attributes. + */ function scribd_shortcode_markup( $atts ) { $markup = <<<EOD <iframe class="scribd_iframe_embed" src="//www.scribd.com/embeds/$atts[id]/content?start_page=1&view_mode=$atts[mode]&access_key=$atts[key]" data-auto-height="true" scrolling="no" id="scribd_$atts[id]" width="100%" height="500" frameborder="0"></iframe> -<div style="font-size:10px;text-align:center;width:100%"><a href="http://www.scribd.com/doc/$atts[id]" target="_blank">View this document on Scribd</a></div> +<div style="font-size:10px;text-align:center;width:100%"><a href="https://www.scribd.com/doc/$atts[id]" target="_blank">View this document on Scribd</a></div> EOD; return $markup; } - add_shortcode( 'scribd', 'scribd_shortcode_handler' ); -// Scribd supports HTTPS, so use that endpoint to get HTTPS-compatible embeds +/** + * Scribd supports HTTPS, so use that endpoint to get HTTPS-compatible embeds. + * + * @param array $providers Array of oEmbed providers. + */ function scribd_https_oembed( $providers ) { if ( isset( $providers['#https?://(www\.)?scribd\.com/doc/.*#i'] ) ) { $providers['#https?://(www\.)?scribd\.com/doc/.*#i'][0] = 'https://www.scribd.com/services/oembed'; @@ -58,5 +71,4 @@ function scribd_https_oembed( $providers ) { return $providers; } - add_filter( 'oembed_providers', 'scribd_https_oembed' ); diff --git a/plugins/jetpack/modules/shortcodes/slideshare.php b/plugins/jetpack/modules/shortcodes/slideshare.php index 898ae57e..35740287 100644 --- a/plugins/jetpack/modules/shortcodes/slideshare.php +++ b/plugins/jetpack/modules/shortcodes/slideshare.php @@ -1,23 +1,30 @@ <?php /** - * Slideshare shortcode format: + * Slideshare shortcode + * + * Formats: * Old style (still compatible): [slideshare id=5342235&doc=camprock-101002163655-phpapp01&w=300&h=200] * New style: [slideshare id=5342235&w=300&h=200&fb=0&mw=0&mh=0&sc=no] * * Legend: - * id = Document ID provided by Slideshare - * w = Width of iFrame (int) - * h = Height of iFrame (int) - * fb = iFrame frameborder (int) - * mw = iFrame marginwidth (int) - * mh = iFrame marginheight (int) - * sc = iFrame Scrollbar (yes/no) - * pro = Slideshare Pro (yes/no) - * style = Inline CSS (string) - **/ - -add_shortcode( 'slideshare', 'slideshare_shortcode' ); + * id = Document ID provided by Slideshare + * w = Width of iFrame (int) + * h = Height of iFrame (int) + * fb = iFrame frameborder (int) + * mw = iFrame marginwidth (int) + * mh = iFrame marginheight (int) + * sc = iFrame Scrollbar (yes/no) + * pro = Slideshare Pro (yes/no) + * style = Inline CSS (string) + * + * @package Jetpack + */ +/** + * Register and display shortcode. + * + * @param array $atts Shortcode attributes. + */ function slideshare_shortcode( $atts ) { global $content_width; @@ -43,17 +50,19 @@ function slideshare_shortcode( $atts ) { $arguments ); - // check that the Slideshare ID contains letters, numbers and query strings + // check that the Slideshare ID contains letters, numbers and query strings. $pattern = '/[^-_a-zA-Z0-9?=&]/'; if ( empty( $attr['id'] ) || preg_match( $pattern, $attr['id'] ) ) { return '<!-- SlideShare error: id is missing or has illegal characters -->'; } - // check the width/height - $w = $attr['w']; + // check the width/height. + $w = intval( $attr['w'] ); + + // If no width was specified (or uses the wrong format), and if we have a $content_width, use that. if ( empty( $w ) && ! empty( $content_width ) ) { $w = intval( $content_width ); - } elseif ( ! ( $w = intval( $w ) ) || $w < 300 || $w > 1600 ) { + } elseif ( $w < 300 || $w > 1600 ) { // If width was specified, but is too small/large, set default value. $w = 425; } else { $w = intval( $w ); @@ -61,33 +70,33 @@ function slideshare_shortcode( $atts ) { $h = ceil( $w * 348 / 425 ); // Note: user-supplied height is ignored. - if ( isset( $attr['pro'] ) && $attr['pro'] ) { + if ( ! empty( $attr['pro'] ) ) { $source = 'https://www.slideshare.net/slidesharepro/' . $attr['id']; } else { $source = 'https://www.slideshare.net/slideshow/embed_code/' . $attr['id']; } - if ( isset( $rel ) ) { - $source = add_query_arg( 'rel', intval( $rel ), $source ); + if ( isset( $attr['rel'] ) ) { + $source = add_query_arg( 'rel', intval( $attr['rel'] ), $source ); } - if ( isset( $startSlide ) ) { - $source = add_query_arg( 'startSlide', intval( $startSlide ), $source ); + if ( ! empty( $attr['startSlide'] ) ) { + $source = add_query_arg( 'startSlide', intval( $attr['startSlide'] ), $source ); } $player = sprintf( "<iframe src='%s' width='%d' height='%d'", esc_url( $source ), $w, $h ); - // check the frameborder + // check the frameborder. if ( ! empty( $attr['fb'] ) || '0' === $attr['fb'] ) { $player .= " frameborder='" . intval( $attr['fb'] ) . "'"; } - // check the margin width; if not empty, cast as int + // check the margin width; if not empty, cast as int. if ( ! empty( $attr['mw'] ) || '0' === $attr['mw'] ) { $player .= " marginwidth='" . intval( $attr['mw'] ) . "'"; } - // check the margin height, if not empty, cast as int + // check the margin height, if not empty, cast as int. if ( ! empty( $attr['mh'] ) || '0' === $attr['mh'] ) { $player .= " marginheight='" . intval( $attr['mh'] ) . "'"; } @@ -96,11 +105,11 @@ function slideshare_shortcode( $atts ) { $player .= " style='" . esc_attr( $attr['style'] ) . "'"; } - // check the scrollbar; cast as a lowercase string for comparison + // check the scrollbar; cast as a lowercase string for comparison. if ( ! empty( $attr['sc'] ) ) { $sc = strtolower( $attr['sc'] ); - if ( in_array( $sc, array( 'yes', 'no' ) ) ) { + if ( in_array( $sc, array( 'yes', 'no' ), true ) ) { $player .= " scrolling='" . $sc . "'"; } } @@ -119,3 +128,4 @@ function slideshare_shortcode( $atts ) { */ return apply_filters( 'jetpack_slideshare_shortcode', $player, $atts ); } +add_shortcode( 'slideshare', 'slideshare_shortcode' ); diff --git a/plugins/jetpack/modules/shortcodes/slideshow.php b/plugins/jetpack/modules/shortcodes/slideshow.php index 43428dc8..a3b99ac1 100644 --- a/plugins/jetpack/modules/shortcodes/slideshow.php +++ b/plugins/jetpack/modules/shortcodes/slideshow.php @@ -1,12 +1,29 @@ -<?php +<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName + +use Automattic\Jetpack\Assets; + +/** + * Slideshow shortcode. + * Adds a new "slideshow" gallery type when adding a gallery using the classic editor. + * + * @package Jetpack + */ /** * Slideshow shortcode usage: [gallery type="slideshow"] or the older [slideshow] */ class Jetpack_Slideshow_Shortcode { + /** + * Number of slideshows on a page. + * + * @var int + */ public $instance_count = 0; - function __construct() { + /** + * Constructor + */ + public function __construct() { global $shortcode_tags; // Only if the slideshow shortcode has not already been defined. @@ -19,31 +36,24 @@ class Jetpack_Slideshow_Shortcode { add_filter( 'post_gallery', array( $this, 'post_gallery' ), 1002, 2 ); add_filter( 'jetpack_gallery_types', array( $this, 'add_gallery_type' ), 10 ); } - - /** - * For the moment, comment out the setting for v2.8. - * The remainder should work as it always has. - * See: https://github.com/Automattic/jetpack/pull/85/files - */ - // add_action( 'admin_init', array( $this, 'register_settings' ), 5 ); } /** * Responds to the [gallery] shortcode, but not an actual shortcode callback. * - * @param $value string An empty string if nothing has modified the gallery output, the output html otherwise - * @param $attr array The shortcode attributes array + * @param string $value An empty string if nothing has modified the gallery output, the output html otherwise. + * @param array $attr The shortcode attributes array. * * @return string The (un)modified $value */ - function post_gallery( $value, $attr ) { - // Bail if somebody else has done something + public function post_gallery( $value, $attr ) { + // Bail if somebody else has done something. if ( ! empty( $value ) ) { return $value; } - // If [gallery type="slideshow"] have it behave just like [slideshow] - if ( ! empty( $attr['type'] ) && 'slideshow' == $attr['type'] ) { + // If [gallery type="slideshow"] have it behave just like [slideshow]. + if ( ! empty( $attr['type'] ) && 'slideshow' === $attr['type'] ) { return $this->shortcode_callback( $attr ); } @@ -55,58 +65,22 @@ class Jetpack_Slideshow_Shortcode { * * @see Jetpack_Tiled_Gallery::media_ui_print_templates * - * @param $types array An array of types where the key is the value, and the value is the caption. + * @param array $types An array of types where the key is the value, and the value is the caption. * * @return array */ - function add_gallery_type( $types = array() ) { + public function add_gallery_type( $types = array() ) { $types['slideshow'] = esc_html__( 'Slideshow', 'jetpack' ); return $types; } - function register_settings() { - add_settings_section( 'slideshow_section', __( 'Image Gallery Slideshow', 'jetpack' ), '__return_empty_string', 'media' ); - - add_settings_field( 'jetpack_slideshow_background_color', __( 'Background color', 'jetpack' ), array( $this, 'slideshow_background_color_callback' ), 'media', 'slideshow_section' ); - - register_setting( 'media', 'jetpack_slideshow_background_color', array( $this, 'slideshow_background_color_sanitize' ) ); - } - - function slideshow_background_color_callback() { - $options = array( - 'black' => __( 'Black', 'jetpack' ), - 'white' => __( 'White', 'jetpack' ), - ); - $this->settings_select( 'jetpack_slideshow_background_color', $options ); - } - - function settings_select( $name, $values, $extra_text = '' ) { - if ( empty( $name ) || empty( $values ) || ! is_array( $values ) ) { - return; - } - $option = get_option( $name ); - ?> - <fieldset> - <select name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $name ); ?>"> - <?php foreach ( $values as $key => $value ) : ?> - <option value="<?php echo esc_attr( $key ); ?>" <?php selected( $key, $option ); ?>> - <?php echo esc_html( $value ); ?> - </option> - <?php endforeach; ?> - </select> - <?php if ( ! empty( $extra_text ) ) : ?> - <p class="description"><?php echo esc_html( $extra_text ); ?></p> - <?php endif; ?> - </fieldset> - <?php - } - - function slideshow_background_color_sanitize( $value ) { - return ( 'white' == $value ) ? 'white' : 'black'; - } - - function shortcode_callback( $attr ) { + /** + * Display shortcode. + * + * @param array $attr Shortcode attributes. + */ + public function shortcode_callback( $attr ) { $post_id = get_the_ID(); $attr = shortcode_atts( @@ -124,7 +98,7 @@ class Jetpack_Slideshow_Shortcode { 'slideshow' ); - if ( 'rand' == strtolower( $attr['order'] ) ) { + if ( 'rand' === strtolower( $attr['order'] ) ) { $attr['orderby'] = 'none'; } @@ -137,7 +111,7 @@ class Jetpack_Slideshow_Shortcode { $attr['size'] = 'full'; } - // Don't restrict to the current post if include + // Don't restrict to the current post if include. $post_parent = ( empty( $attr['include'] ) ) ? intval( $attr['id'] ) : null; $attachments = get_posts( @@ -164,7 +138,7 @@ class Jetpack_Slideshow_Shortcode { $gallery = array(); foreach ( $attachments as $attachment ) { $attachment_image_src = wp_get_attachment_image_src( $attachment->ID, $attr['size'] ); - $attachment_image_src = $attachment_image_src[0]; // [url, width, height] + $attachment_image_src = $attachment_image_src[0]; // [url, width, height]. $attachment_image_title = get_the_title( $attachment->ID ); $attachment_image_alt = get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ); /** @@ -177,7 +151,7 @@ class Jetpack_Slideshow_Shortcode { * @param string wptexturize( strip_tags( $attachment->post_excerpt ) ) Post excerpt. * @param string $attachment ->ID Attachment ID. */ - $caption = apply_filters( 'jetpack_slideshow_slide_caption', wptexturize( strip_tags( $attachment->post_excerpt ) ), $attachment->ID ); + $caption = apply_filters( 'jetpack_slideshow_slide_caption', wptexturize( wp_strip_all_tags( $attachment->post_excerpt ) ), $attachment->ID ); $gallery[] = (object) array( 'src' => (string) esc_url_raw( $attachment_image_src ), @@ -216,52 +190,57 @@ class Jetpack_Slideshow_Shortcode { * * Returns the necessary markup and js to fire a slideshow. * - * @param $attr array Attributes for the slideshow. + * @param array $attr Attributes for the slideshow. * * @uses $this->enqueue_scripts() * * @return string HTML output. */ - function slideshow_js( $attr ) { - // Enqueue scripts + public function slideshow_js( $attr ) { + // Enqueue scripts. $this->enqueue_scripts(); $output = ''; if ( defined( 'JSON_HEX_AMP' ) ) { - // This is nice to have, but not strictly necessary since we use _wp_specialchars() below - $gallery = json_encode( $attr['gallery'], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ); // phpcs:ignore PHPCompatibility + // This is nice to have, but not strictly necessary since we use _wp_specialchars() below. + $gallery = wp_json_encode( $attr['gallery'], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ); // phpcs:ignore PHPCompatibility } else { - $gallery = json_encode( $attr['gallery'] ); + $gallery = wp_json_encode( $attr['gallery'] ); } $output .= '<p class="jetpack-slideshow-noscript robots-nocontent">' . esc_html__( 'This slideshow requires JavaScript.', 'jetpack' ) . '</p>'; + + /* + * The input to json_encode() above can contain '"'. + * + * For calls to json_encode() lacking the JSON_HEX_AMP option, + * that '"' is left unaltered. Running '"' through esc_attr() + * also leaves it unaltered since esc_attr() does not double-encode. + * + * This means we end up with an attribute like + * `data-gallery="{"foo":"""}"`, + * which is interpreted by the browser as `{"foo":"""}`, + * which cannot be JSON decoded. + * + * The preferred workaround is to include the JSON_HEX_AMP (and friends) + * options, but these are not available until 5.3.0. + * Alternatively, we can use _wp_specialchars( , , , true ) instead of + * esc_attr(), which will double-encode. + * + * Since we can't rely on JSON_HEX_AMP, we do both. + * + * @todo Update when minimum is PHP 5.3+ + */ + $gallery_attributes = _wp_specialchars( wp_check_invalid_utf8( $gallery ), ENT_QUOTES, false, true ); + $output .= sprintf( '<div id="%s" class="slideshow-window jetpack-slideshow slideshow-%s" data-trans="%s" data-autostart="%s" data-gallery="%s" itemscope itemtype="https://schema.org/ImageGallery"></div>', esc_attr( $attr['selector'] . '-slideshow' ), esc_attr( $attr['color'] ), esc_attr( $attr['trans'] ), esc_attr( $attr['autostart'] ), - /* - * The input to json_encode() above can contain '"'. - * - * For calls to json_encode() lacking the JSON_HEX_AMP option, - * that '"' is left unaltered. Running '"' through esc_attr() - * also leaves it unaltered since esc_attr() does not double-encode. - * - * This means we end up with an attribute like - * `data-gallery="{"foo":"""}"`, - * which is interpreted by the browser as `{"foo":"""}`, - * which cannot be JSON decoded. - * - * The preferred workaround is to include the JSON_HEX_AMP (and friends) - * options, but these are not available until 5.3.0. - * Alternatively, we can use _wp_specialchars( , , , true ) instead of - * esc_attr(), which will double-encode. - * - * Since we can't rely on JSON_HEX_AMP, we do both. - */ - _wp_specialchars( wp_check_invalid_utf8( $gallery ), ENT_QUOTES, false, true ) + $gallery_attributes ); return $output; @@ -270,17 +249,22 @@ class Jetpack_Slideshow_Shortcode { /** * Actually enqueues the scripts and styles. */ - function enqueue_scripts() { + public function enqueue_scripts() { wp_enqueue_script( 'jquery-cycle', plugins_url( '/js/jquery.cycle.min.js', __FILE__ ), array( 'jquery' ), '20161231', true ); wp_enqueue_script( 'jetpack-slideshow', - Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/slideshow-shortcode.min.js', 'modules/shortcodes/js/slideshow-shortcode.js' ), + Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/slideshow-shortcode.min.js', 'modules/shortcodes/js/slideshow-shortcode.js' ), array( 'jquery-cycle' ), '20160119.1', true ); - wp_enqueue_style( 'jetpack-slideshow', plugins_url( '/css/slideshow-shortcode.css', __FILE__ ) ); + wp_enqueue_style( + 'jetpack-slideshow', + plugins_url( '/css/slideshow-shortcode.css', __FILE__ ), + array(), + JETPACK__VERSION + ); wp_style_add_data( 'jetpack-slideshow', 'rtl', 'replace' ); wp_localize_script( @@ -308,6 +292,9 @@ class Jetpack_Slideshow_Shortcode { ); } + /** + * Instantiate shortcode. + */ public static function init() { new Jetpack_Slideshow_Shortcode(); } diff --git a/plugins/jetpack/modules/shortcodes/soundcloud.php b/plugins/jetpack/modules/shortcodes/soundcloud.php index 71f281c3..59479fc7 100644 --- a/plugins/jetpack/modules/shortcodes/soundcloud.php +++ b/plugins/jetpack/modules/shortcodes/soundcloud.php @@ -1,44 +1,25 @@ <?php -/* -Plugin Name: SoundCloud Shortcode -Plugin URI: https://wordpress.org/extend/plugins/soundcloud-shortcode/ -Description: Converts SoundCloud WordPress shortcodes to a SoundCloud widget. Example: [soundcloud]http://soundcloud.com/forss/flickermood[/soundcloud] -Version: 2.3 -Author: SoundCloud Inc., simplified for Jetpack by Automattic, Inc. -Author URI: http://soundcloud.com -License: GPLv2 - -Original version: Johannes Wagener <johannes@soundcloud.com> -Options support: Tiffany Conroy <tiffany@soundcloud.com> -HTML5 & oEmbed support: Tim Bormans <tim@soundcloud.com> -*/ - -/* -A8C: Taken from http://plugins.svn.wordpress.org/soundcloud-shortcode/trunk/ -at revision 664386. - -Commenting out (instead of removing) and replacing code with custom modifs -so it's eqsy to see what differs from the standard DOTORG version. - -All custom modifs are annoted with "A8C" keyword in comment. -*/ - /** - * Register oEmbed provider + * SoundCloud Shortcode + * Based on this plugin: https://wordpress.org/plugins/soundcloud-shortcode/ + * + * Credits: + * Original version: Johannes Wagener <johannes@soundcloud.com> + * Options support: Tiffany Conroy <tiffany@soundcloud.com> + * HTML5 & oEmbed support: Tim Bormans <tim@soundcloud.com> + * + * Examples: + * [soundcloud]http://soundcloud.com/forss/flickermood[/soundcloud] + * [soundcloud url="https://api.soundcloud.com/tracks/156661852" params="auto_play=false&hide_related=false&visual=false" width="100%" height="450" iframe="true" /] + * [soundcloud url="https://api.soundcloud.com/tracks/156661852" params="auto_play=false&hide_related=false&visual=true" width="100%" height="450" iframe="true" /] + * [soundcloud url="https://soundcloud.com/closetorgan/paul-is-dead" width=400 height=400] + * [soundcloud url="https://soundcloud.com/closetorgan/sets/smells-like-lynx-africa-private"] + * [soundcloud url="https://soundcloud.com/closetorgan/sets/smells-like-lynx-africa-private" color="00cc11"] + * <iframe width="100%" height="450" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/150745932&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true"></iframe> + * + * @package Jetpack */ -/* - A8C: oEmbed is handled now in core; see wp-includes/class-oembed.php -wp_oembed_add_provider( '#https?://(?:api\.)?soundcloud\.com/.*#i', 'http://soundcloud.com/oembed', true ); -*/ - - -/** - * Register SoundCloud shortcode - */ - -add_shortcode( 'soundcloud', 'soundcloud_shortcode' ); - /** * SoundCloud shortcode handler * @@ -49,128 +30,153 @@ add_shortcode( 'soundcloud', 'soundcloud_shortcode' ); * @return string Widget embed code HTML */ function soundcloud_shortcode( $atts, $content = null ) { + global $wp_embed; + + // Custom shortcode options. + $shortcode_options = array_merge( + array( 'url' => trim( $content ) ), + is_array( $atts ) ? $atts : array() + ); - // Custom shortcode options - $shortcode_options = array_merge( array( 'url' => trim( $content ) ), is_array( $atts ) ? $atts : array() ); + // The "url" option is required. + if ( empty( $shortcode_options['url'] ) ) { + if ( current_user_can( 'edit_posts' ) ) { + return esc_html__( 'Please specify a Soundcloud URL.', 'jetpack' ); + } else { + return '<!-- Missing Soundcloud URL -->'; + } + } - // Turn shortcode option "param" (param=value¶m2=value) into array + // Turn shortcode option "param" (param=value¶m2=value) into array of params. $shortcode_params = array(); if ( isset( $shortcode_options['params'] ) ) { parse_str( html_entity_decode( $shortcode_options['params'] ), $shortcode_params ); + $shortcode_options = array_merge( + $shortcode_options, + $shortcode_params + ); + unset( $shortcode_options['params'] ); } - $shortcode_options['params'] = $shortcode_params; - - /* - A8C: The original plugin exposes options we don't. SoundCloud omits "visual" shortcode - option when false, so if logic here remains, impossible to have non-visual shortcode. - $player_type = soundcloud_get_option( 'player_type', 'visual' ); - $isIframe = $player_type !== 'flash'; - $isVisual = ! $player_type || $player_type === 'visual' || $shortcode_options['visual']; - */ - - // User preference options - $plugin_options = array_filter( + + $options = shortcode_atts( + // This list used to include an 'iframe' option. We don't include it anymore as we don't support the Flash player anymore. array( - 'iframe' => true, // A8C: See above comment; flash is not a supported option - 'width' => soundcloud_get_option( 'player_width' ), - 'height' => soundcloud_url_has_tracklist( $shortcode_options['url'] ) ? soundcloud_get_option( 'player_height_multi' ) : soundcloud_get_option( 'player_height' ), - 'params' => array_filter( - array( - 'auto_play' => soundcloud_get_option( 'auto_play' ), - 'show_comments' => soundcloud_get_option( 'show_comments' ), - 'color' => soundcloud_get_option( 'color' ), - 'visual' => 'false', // A8C: Merged with params below at $options assignment - ) - ), - ) + 'url' => '', + 'width' => soundcloud_get_option( 'player_width' ), + 'height' => soundcloud_url_has_tracklist( $shortcode_options['url'] ) ? soundcloud_get_option( 'player_height_multi' ) : soundcloud_get_option( 'player_height' ), + 'auto_play' => soundcloud_get_option( 'auto_play' ), + 'hide_related' => false, + 'visual' => false, + 'show_comments' => soundcloud_get_option( 'show_comments' ), + 'color' => soundcloud_get_option( 'color' ), + 'show_user' => false, + 'show_reposts' => false, + ), + $shortcode_options, + 'soundcloud' ); - // Needs to be an array - if ( ! isset( $plugin_options['params'] ) ) { - $plugin_options['params'] = array(); + // "width" needs to be an integer. + if ( ! empty( $options['width'] ) && ! preg_match( '/^\d+$/', $options['width'] ) ) { + // set to 0 so oEmbed will use the default 100% and WordPress themes will leave it alone. + $options['width'] = 0; } - - // plugin options < shortcode options - $options = array_merge( - $plugin_options, - $shortcode_options - ); - - // plugin params < shortcode params - $options['params'] = array_merge( - $plugin_options['params'], - $shortcode_options['params'] - ); - - // The "url" option is required - if ( ! isset( $options['url'] ) ) { - return ''; + // Set default width if not defined. + $width = ! empty( $options['width'] ) ? absint( $options['width'] ) : '100%'; + + // Set default height if not defined. + if ( + empty( $options['height'] ) + || ( + // "height" needs to be an integer. + ! empty( $options['height'] ) + && ! preg_match( '/^\d+$/', $options['height'] ) + ) + ) { + if ( + soundcloud_url_has_tracklist( $options['url'] ) + || 'true' === $options['visual'] + ) { + $height = 450; + } else { + $height = 166; + } } else { - $options['url'] = trim( $options['url'] ); + $height = absint( $options['height'] ); } - // Both "width" and "height" need to be integers - if ( isset( $options['width'] ) && ! preg_match( '/^\d+$/', $options['width'] ) ) { - // set to 0 so oEmbed will use the default 100% and WordPress themes will leave it alone - $options['width'] = 0; + // Set visual to false when displaying the smallest player. + if ( '20' === $options['height'] ) { + $options['visual'] = false; } - if ( isset( $options['height'] ) && ! preg_match( '/^\d+$/', $options['height'] ) ) { - unset( $options['height'] ); + + if ( + class_exists( 'Jetpack_AMP_Support' ) + && Jetpack_AMP_Support::is_amp_request() + && ! empty( $options['url'] ) + && 'api.soundcloud.com' !== wp_parse_url( $options['url'], PHP_URL_HOST ) + ) { + // Defer to oEmbed if an oEmbeddable URL is provided. + return $wp_embed->shortcode( $options, $options['url'] ); } - // The "iframe" option must be true to load the iframe widget - $iframe = soundcloud_booleanize( $options['iframe'] ); + // Build our list of Soundcloud parameters. + $query_args = array( + 'url' => rawurlencode( $options['url'] ), + ); + + // Add our options, if they are set to true or false. + foreach ( $options as $name => $value ) { + if ( 'true' === $value ) { + $query_args[ $name ] = 'true'; + } - // Remove visual parameter from Flash widget, when it's false because that's the default, or when displaying the smallest player - if ( $options['params']['visual'] && ( ! $iframe || ! soundcloud_booleanize( $options['params']['visual'] ) || ( isset( $options['height'] ) && '20' == $options['height'] ) ) ) { - unset( $options['params']['visual'] ); + if ( 'false' === $value || false === $value ) { + $query_args[ $name ] = 'false'; + } } - // Merge in "url" value - $options['params'] = array_merge( - array( - 'url' => $options['url'], - ), - $options['params'] + // Add the color parameter if it was specified and is a valid color. + if ( ! empty( $options['color'] ) ) { + $color = sanitize_hex_color_no_hash( $options['color'] ); + if ( ! empty( $color ) ) { + $query_args['color'] = $color; + } + } + + // Build final embed URL. + $url = add_query_arg( + $query_args, + 'https://w.soundcloud.com/player/' ); - // Return html embed code - if ( $iframe ) { - return soundcloud_iframe_widget( $options ); - } else { - return soundcloud_flash_widget( $options ); - } + return sprintf( + '<iframe width="%1$s" height="%2$d" scrolling="no" frameborder="no" src="%3$s"></iframe>', + esc_attr( $width ), + esc_attr( $height ), + $url + ); } +add_shortcode( 'soundcloud', 'soundcloud_shortcode' ); /** * Plugin options getter * - * @param string|array $option Option name - * @param mixed $default Default value + * @param string|array $option Option name. + * @param mixed $default Default value. * * @return mixed Option value */ function soundcloud_get_option( $option, $default = false ) { $value = get_option( 'soundcloud_' . $option ); - return $value === '' ? $default : $value; -} - -/** - * Booleanize a value - * - * @param boolean|string $value - * - * @return boolean - */ -function soundcloud_booleanize( $value ) { - return is_bool( $value ) ? $value : $value === 'true' ? true : false; + return '' === $value ? $default : $value; } /** * Decide if a url has a tracklist * - * @param string $url + * @param string $url Soundcloud URL. * * @return boolean */ @@ -179,81 +185,6 @@ function soundcloud_url_has_tracklist( $url ) { } /** - * Parameterize url - * - * @param array $match Matched regex - * - * @return string Parameterized url - */ -function soundcloud_oembed_params_callback( $match ) { - global $soundcloud_oembed_params; - - // Convert URL to array - $url = parse_url( urldecode( $match[1] ) ); - // Convert URL query to array - parse_str( $url['query'], $query_array ); - // Build new query string - $query = http_build_query( array_merge( $query_array, $soundcloud_oembed_params ) ); - - return 'src="' . $url['scheme'] . '://' . $url['host'] . $url['path'] . '?' . $query; -} - -/** - * Iframe widget embed code - * - * @param array $options Parameters - * - * @return string Iframe embed code - */ -function soundcloud_iframe_widget( $options ) { - - // Build URL - $url = set_url_scheme( 'https://w.soundcloud.com/player/?' . http_build_query( $options['params'] ) ); - // Set default width if not defined - $width = isset( $options['width'] ) && $options['width'] !== 0 ? $options['width'] : '100%'; - // Set default height if not defined - $height = isset( $options['height'] ) && $options['height'] !== 0 - ? $options['height'] - : ( soundcloud_url_has_tracklist( $options['url'] ) || ( isset( $options['params']['visual'] ) && soundcloud_booleanize( $options['params']['visual'] ) ) ? '450' : '166' ); - - return sprintf( '<iframe width="%s" height="%s" scrolling="no" frameborder="no" src="%s"></iframe>', $width, $height, $url ); -} - -/** - * Legacy Flash widget embed code - * - * @param array $options Parameters - * - * @return string Flash embed code - */ -function soundcloud_flash_widget( $options ) { - // Build URL - $url = set_url_scheme( 'https://player.soundcloud.com/player.swf?' . http_build_query( $options['params'] ) ); - // Set default width if not defined - $width = isset( $options['width'] ) && $options['width'] !== 0 ? $options['width'] : '100%'; - // Set default height if not defined - $height = isset( $options['height'] ) && $options['height'] !== 0 ? $options['height'] : ( soundcloud_url_has_tracklist( $options['url'] ) ? '255' : '81' ); - - return preg_replace( - '/\s\s+/', - '', - sprintf( - '<object width="%s" height="%s"> - <param name="movie" value="%s" /> - <param name="allowscriptaccess" value="always" /> - <embed width="%s" height="%s" src="%s" allowscriptaccess="always" type="application/x-shockwave-flash"></embed> - </object>', - $width, - $height, - $url, - $width, - $height, - $url - ) - ); -} - -/** * SoundCloud Embed Reversal * * Converts a generic HTML embed code from SoundClound into a @@ -268,12 +199,6 @@ function jetpack_soundcloud_embed_reversal( $content ) { return $content; } - /* - Sample embed code: - - <iframe width="100%" height="450" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/150745932&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true"></iframe> - */ - $regexes = array(); $regexes[] = '#<iframe[^>]+?src="((?:https?:)?//w\.soundcloud\.com/player/[^"\']++)"[^>]*+>\s*?</iframe>#i'; @@ -286,10 +211,10 @@ function jetpack_soundcloud_embed_reversal( $content ) { foreach ( $matches as $match ) { - // if pasted from the visual editor - prevent double encoding + // if pasted from the visual editor - prevent double encoding. $match[1] = str_replace( '&amp;', '&', $match[1] ); - $args = parse_url( html_entity_decode( $match[1] ), PHP_URL_QUERY ); + $args = wp_parse_url( html_entity_decode( $match[1] ), PHP_URL_QUERY ); $args = wp_parse_args( $args ); if ( ! preg_match( '#^(?:https?:)?//api\.soundcloud\.com/.+$#i', $args['url'], $url_matches ) ) { @@ -316,6 +241,7 @@ function jetpack_soundcloud_embed_reversal( $content ) { $replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) ); $content = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $shortcode ), $content ); + /** This action is documented in modules/shortcodes/youtube.php */ do_action( 'jetpack_embed_to_shortcode', 'soundcloud', $url_matches[0] ); } @@ -323,5 +249,4 @@ function jetpack_soundcloud_embed_reversal( $content ) { return $content; } - add_filter( 'pre_kses', 'jetpack_soundcloud_embed_reversal' ); diff --git a/plugins/jetpack/modules/shortcodes/ted.php b/plugins/jetpack/modules/shortcodes/ted.php index f66f77d5..b26ef1da 100644 --- a/plugins/jetpack/modules/shortcodes/ted.php +++ b/plugins/jetpack/modules/shortcodes/ted.php @@ -1,23 +1,36 @@ <?php -/* +/** * TED Player embed code * http://www.ted.com * + * Examples: * http://www.ted.com/talks/view/id/210 * http://www.ted.com/talks/marc_goodman_a_vision_of_crimes_in_the_future.html * [ted id="210" lang="en"] * [ted id="http://www.ted.com/talks/view/id/210" lang="en"] * [ted id=1539 lang=fr width=560 height=315] + * + * @package Jetpack */ -wp_oembed_add_provider( '!https?://(www\.)?ted.com/talks/view/id/.+!i', 'http://www.ted.com/talks/oembed.json', true ); -wp_oembed_add_provider( '!https?://(www\.)?ted.com/talks/[a-zA-Z\-\_]+\.html!i', 'http://www.ted.com/talks/oembed.json', true ); +wp_oembed_add_provider( '!https?://(www\.)?ted.com/talks/view/id/.+!i', 'https://www.ted.com/talks/oembed.json', true ); +wp_oembed_add_provider( '!https?://(www\.)?ted.com/talks/[a-zA-Z\-\_]+\.html!i', 'https://www.ted.com/talks/oembed.json', true ); +/** + * Get the unique ID of a TED video. + * Used in Jetpack_Media_Meta_Extractor. + * + * @param array $atts Shortcode attributes. + */ function jetpack_shortcode_get_ted_id( $atts ) { return ( ! empty( $atts['id'] ) ? $atts['id'] : 0 ); } -add_shortcode( 'ted', 'shortcode_ted' ); +/** + * Handle Ted Shortcode. + * + * @param array $atts Shortcode attributes. + */ function shortcode_ted( $atts ) { global $wp_embed; @@ -35,17 +48,19 @@ function shortcode_ted( $atts ) { $url = ''; if ( preg_match( '#^[\d]+$#', $atts['id'], $matches ) ) { - $url = 'http://ted.com/talks/view/id/' . $matches[0]; + $url = 'https://ted.com/talks/view/id/' . $matches[0]; } elseif ( preg_match( '#^https?://(www\.)?ted\.com/talks/view/id/[0-9]+$#', $atts['id'], $matches ) ) { - $url = $matches[0]; + $url = set_url_scheme( $matches[0], 'https' ); } unset( $atts['id'] ); - $args = array(); + $args = array(); + $embed_size_w = get_option( 'embed_size_w' ); + if ( is_numeric( $atts['width'] ) ) { $args['width'] = $atts['width']; - } elseif ( $embed_size_w = get_option( 'embed_size_w' ) ) { + } elseif ( $embed_size_w ) { $args['width'] = $embed_size_w; } elseif ( ! empty( $GLOBALS['content_width'] ) ) { $args['width'] = (int) $GLOBALS['content_width']; @@ -53,7 +68,7 @@ function shortcode_ted( $atts ) { $args['width'] = 500; } - // Default to a 16x9 aspect ratio if there's no height set + // Default to a 16x9 aspect ratio if there's no height set. if ( is_numeric( $atts['height'] ) ) { $args['height'] = $atts['height']; } else { @@ -69,9 +84,14 @@ function shortcode_ted( $atts ) { return $retval; } +add_shortcode( 'ted', 'shortcode_ted' ); /** * Filter the request URL to also include the $lang parameter + * + * @param string $provider URL of provider that supplies the tweet we're requesting. + * @param string $url URL of tweet to embed. + * @param array $args Parameters supplied to shortcode and passed to wp_oembed_get. */ function ted_filter_oembed_fetch_url( $provider, $url, $args ) { return add_query_arg( 'lang', $args['lang'], $provider ); diff --git a/plugins/jetpack/modules/shortcodes/tweet.php b/plugins/jetpack/modules/shortcodes/tweet.php index 5d6acd29..435195b6 100644 --- a/plugins/jetpack/modules/shortcodes/tweet.php +++ b/plugins/jetpack/modules/shortcodes/tweet.php @@ -204,12 +204,23 @@ class Jetpack_Tweet { remove_filter( 'oembed_fetch_url', array( 'Jetpack_Tweet', 'jetpack_tweet_url_extra_args' ), 10 ); } - // Add Twitter widgets.js script to the footer. - add_action( 'wp_footer', array( 'Jetpack_Tweet', 'jetpack_tweet_shortcode_script' ) ); - /** This action is documented in modules/widgets/social-media-icons.php */ do_action( 'jetpack_bump_stats_extras', 'embeds', 'tweet' ); + if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) { + $width = ! empty( $attr['width'] ) ? $attr['width'] : 600; + $height = 480; + $output = sprintf( + '<amp-twitter data-tweetid="%1$s" layout="responsive" width="%2$d" height="%3$d"></amp-twitter>', + esc_attr( $tweet_id ), + absint( $width ), + absint( $height ) + ); + } else { + // Add Twitter widgets.js script to the footer. + add_action( 'wp_footer', array( 'Jetpack_Tweet', 'jetpack_tweet_shortcode_script' ) ); + } + return $output; } diff --git a/plugins/jetpack/modules/shortcodes/twitchtv.php b/plugins/jetpack/modules/shortcodes/twitchtv.php index a5439d05..935a8b3a 100644 --- a/plugins/jetpack/modules/shortcodes/twitchtv.php +++ b/plugins/jetpack/modules/shortcodes/twitchtv.php @@ -1,20 +1,24 @@ <?php /** - * twitch.tv shortcode - * [twitchtv url='http://www.twitch.tv/paperbat' height='378' width='620' autoplay='false'] - * [twitchtv url='http://www.twitch.tv/paperbat/b/323486192' height='378' width='620' autoplay='false'] - **/ + * Twitch.tv shortcode + * + * Examples: + * [twitchtv url='https://www.twitch.tv/paperbat' height='378' width='620' autoplay='false'] + * [twitchtv url='https://www.twitch.tv/paperbat/b/323486192' height='378' width='620' autoplay='false'] + * + * @package Jetpack + */ /** - * (Live URL) http://www.twitch.tv/paperbat + * (Live URL) https://www.twitch.tv/paperbat * * <iframe src="https://player.twitch.tv/?autoplay=false&muted=false&channel=paperbat" width="620" height="378" frameborder="0" scrolling="no" allowfullscreen></iframe> * - * (Archive URL) http://www.twitch.tv/paperbat/v/323486192 + * (Archive URL) https://www.twitch.tv/paperbat/v/323486192 * * <iframe src="https://player.twitch.tv/?autoplay=false&muted=false&video=v323486192" width="620" height="378" frameborder="0" scrolling="no" allowfullscreen></iframe> * - * @param $atts array User supplied shortcode arguments. + * @param array $atts User supplied shortcode arguments. * * @return string HTML output of the shortcode. */ @@ -35,7 +39,7 @@ function wpcom_twitchtv_shortcode( $atts ) { return '<!-- Invalid twitchtv URL -->'; } - preg_match( '|^http://www.twitch.tv/([^/?]+)(/v/(\d+))?|i', $attr['url'], $match ); + preg_match( '|^https?://www.twitch.tv/([^/?]+)(/v/(\d+))?|i', $attr['url'], $match ); $url_args = array( 'autoplay' => ( false !== $attr['autoplay'] && 'false' !== $attr['autoplay'] ) ? 'true' : 'false', @@ -69,6 +73,5 @@ function wpcom_twitchtv_shortcode( $atts ) { esc_attr( $height ) ); } - add_shortcode( 'twitch', 'wpcom_twitchtv_shortcode' ); add_shortcode( 'twitchtv', 'wpcom_twitchtv_shortcode' ); diff --git a/plugins/jetpack/modules/shortcodes/twitter-timeline.php b/plugins/jetpack/modules/shortcodes/twitter-timeline.php index 38558b49..f282943d 100644 --- a/plugins/jetpack/modules/shortcodes/twitter-timeline.php +++ b/plugins/jetpack/modules/shortcodes/twitter-timeline.php @@ -1,6 +1,18 @@ <?php -add_shortcode( 'twitter-timeline', 'twitter_timeline_shortcode' ); +/** + * Twitter Timeline Shortcode. + * + * Examples: + * [twitter-timeline username=jetpack] + * + * @package Jetpack + */ +/** + * Render the Twitter shortcode. + * + * @param array $atts Shortcode attributes. + */ function twitter_timeline_shortcode( $atts ) { $default_atts = array( 'username' => '', @@ -39,7 +51,11 @@ function twitter_timeline_shortcode( $atts ) { $output .= '>'; - $output .= sprintf( __( 'Tweets by @%s', 'jetpack' ), $atts['username'] ); + $output .= sprintf( + /* Translators: placeholder is a Twitter username. */ + __( 'Tweets by @%s', 'jetpack' ), + $atts['username'] + ); $output .= '</a>'; @@ -47,7 +63,11 @@ function twitter_timeline_shortcode( $atts ) { return $output; } +add_shortcode( 'twitter-timeline', 'twitter_timeline_shortcode' ); +/** + * Enqueue the js used by the Twitter shortcode. + */ function twitter_timeline_js() { if ( is_customize_preview() ) { wp_enqueue_script( 'jetpack-twitter-timeline' ); diff --git a/plugins/jetpack/modules/shortcodes/untappd-menu.php b/plugins/jetpack/modules/shortcodes/untappd-menu.php index f8f62f0b..612df9af 100644 --- a/plugins/jetpack/modules/shortcodes/untappd-menu.php +++ b/plugins/jetpack/modules/shortcodes/untappd-menu.php @@ -1,4 +1,4 @@ -<?php +<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName /** * Untappd Shortcodes * @@ -8,22 +8,36 @@ * @since 4.1.0 * @param location int Location ID for the Untappd venue. Required. * @param theme int Theme ID for the Untappd menu. Required. + * + * @package Jetpack */ +/** + * Display Untappd data in posts and pages. + */ class Jetpack_Untappd { - function __construct() { + /** + * Constructor + */ + public function __construct() { add_action( 'init', array( $this, 'action_init' ) ); } - function action_init() { + /** + * Register our shortcodes. + */ + public function action_init() { add_shortcode( 'untappd-menu', array( $this, 'menu_shortcode' ) ); } /** * [untappd-menu] shortcode. + * + * @param array $atts Shortocde attributes. + * @param string $content Post content. */ - static function menu_shortcode( $atts, $content = '' ) { + public static function menu_shortcode( $atts, $content = '' ) { // Let's bail if we don't have location or theme. if ( ! isset( $atts['location'] ) || ! isset( $atts['theme'] ) ) { if ( current_user_can( 'edit_posts' ) ) { diff --git a/plugins/jetpack/modules/shortcodes/upcoming-events.php b/plugins/jetpack/modules/shortcodes/upcoming-events.php index 02f6dda1..69ef9bda 100644 --- a/plugins/jetpack/modules/shortcodes/upcoming-events.php +++ b/plugins/jetpack/modules/shortcodes/upcoming-events.php @@ -1,14 +1,30 @@ -<?php +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName /** - * Most of the heavy lifting done in iCalendarReader class + * Display a list of upcoming events from a calendar. + * + * @package Jetpack + */ + +/** + * Register a upcomingevents shortcode. + * Most of the heavy lifting done in iCalendarReader class, + * where the icalendar_render_events() function controls the display. */ class Upcoming_Events_Shortcode { + /** + * Register things. + */ public static function init() { add_shortcode( 'upcomingevents', array( __CLASS__, 'shortcode' ) ); } + /** + * Register the shortcode. + * + * @param array $atts Shortcode attributes. + */ public static function shortcode( $atts = array() ) { jetpack_require_lib( 'icalendar-reader' ); $atts = shortcode_atts( @@ -32,5 +48,4 @@ class Upcoming_Events_Shortcode { return $events; } } - add_action( 'plugins_loaded', array( 'Upcoming_Events_Shortcode', 'init' ), 101 ); diff --git a/plugins/jetpack/modules/shortcodes/videopress.php b/plugins/jetpack/modules/shortcodes/videopress.php index a4bfd167..0750a25a 100644 --- a/plugins/jetpack/modules/shortcodes/videopress.php +++ b/plugins/jetpack/modules/shortcodes/videopress.php @@ -4,6 +4,8 @@ * * @since 2.4 * @since 3.9.5 Added compatibility with refactored VideoPress module. + * + * @package Jetpack */ if ( ! Jetpack::is_module_active( 'videopress' ) ) { diff --git a/plugins/jetpack/modules/shortcodes/vimeo.php b/plugins/jetpack/modules/shortcodes/vimeo.php index 91492d9c..cc0d3d77 100644 --- a/plugins/jetpack/modules/shortcodes/vimeo.php +++ b/plugins/jetpack/modules/shortcodes/vimeo.php @@ -1,14 +1,23 @@ <?php +/** + * Vimeo Shortcode. + * + * Examples: + * [vimeo 141358] + * [vimeo http://vimeo.com/141358] + * [vimeo 141358 h=500&w=350] + * [vimeo id=141358 width=350 height=500] + * + * <iframe src="http://player.vimeo.com/video/18427511" width="400" height="225" frameborder="0"></iframe><p><a href="http://vimeo.com/18427511">Eskmo 'We Got More' (Official Video)</a> from <a href="http://vimeo.com/ninjatune">Ninja Tune</a> on <a href="http://vimeo.com">Vimeo</a>.</p> + * + * @package Jetpack + */ -/* -[vimeo 141358] -[vimeo http://vimeo.com/141358] -[vimeo 141358 h=500&w=350] -[vimeo id=141358 width=350 height=500] - -<iframe src="http://player.vimeo.com/video/18427511" width="400" height="225" frameborder="0"></iframe><p><a href="http://vimeo.com/18427511">Eskmo 'We Got More' (Official Video)</a> from <a href="http://vimeo.com/ninjatune">Ninja Tune</a> on <a href="http://vimeo.com">Vimeo</a>.</p> -*/ - +/** + * Extract Vimeo ID from shortcode. + * + * @param array $atts Shortcode attributes. + */ function jetpack_shortcode_get_vimeo_id( $atts ) { if ( isset( $atts[0] ) ) { $atts[0] = trim( $atts[0], '=' ); @@ -28,74 +37,70 @@ function jetpack_shortcode_get_vimeo_id( $atts ) { } /** - * Convert a Vimeo shortcode into an embed code. + * Get video dimensions. * - * @param array $atts An array of shortcode attributes. + * @since 8.0.0 * - * @return string The embed code for the Vimeo video. + * @param array $attr The attributes of the shortcode. + * @param array $old_attr Optional array of attributes from the old shortcode format. + * + * @return array Width and height. */ -function vimeo_shortcode( $atts ) { +function jetpack_shortcode_get_vimeo_dimensions( $attr, $old_attr = array() ) { global $content_width; - $attr = array_map( - 'intval', - shortcode_atts( - array( - 'id' => 0, - 'width' => 0, - 'height' => 0, - 'autoplay' => 0, - 'loop' => 0, - ), - $atts - ) - ); - - if ( isset( $atts[0] ) ) { - $attr['id'] = jetpack_shortcode_get_vimeo_id( $atts ); - } - - if ( ! $attr['id'] ) { - return '<!-- vimeo error: not a vimeo video -->'; - } - - // [vimeo 141358 h=500&w=350] - $params = shortcode_new_to_old_params( $atts ); // h=500&w=350 - $params = str_replace( array( '&', '&' ), '&', $params ); - parse_str( $params, $args ); + $default_width = 600; + $default_height = 338; + $aspect_ratio = $default_height / $default_width; + $width = ( ! empty( $attr['width'] ) ? absint( $attr['width'] ) : $default_width ); + $height = ( ! empty( $attr['height'] ) ? absint( $attr['height'] ) : $default_height ); - $width = intval( $attr['width'] ); - $height = intval( $attr['height'] ); - - // Support w and h argument as fallback. - if ( empty( $width ) && isset( $args['w'] ) ) { - $width = intval( $args['w'] ); + /* + * Support w and h argument as fallbacks. + */ + if ( + $default_width === $width + && ! empty( $old_attr['w'] ) + ) { + $width = absint( $old_attr['w'] ); - if ( empty( $height ) && ! isset( $args['h'] ) ) { - // The case where w=300 is specified without h=200, otherwise $height - // will always equal the default of 300, no matter what w was set to. - $height = round( ( $width / 640 ) * 360 ); + if ( + $default_width === $width + && empty( $old_attr['h'] ) + ) { + $height = round( $width * $aspect_ratio ); } } - if ( empty( $height ) && isset( $args['h'] ) ) { - $height = (int) $args['h']; + if ( + $default_height === $height + && ! empty( $old_attr['h'] ) + ) { + $height = absint( $old_attr['h'] ); - if ( ! isset( $args['w'] ) ) { - $width = round( ( $height / 360 ) * 640 ); + if ( empty( $old_attr['w'] ) ) { + $width = round( $height * $aspect_ratio ); } } - if ( ! $width && ! empty( $content_width ) ) { + /* + * If we have a content width defined, let it be the new default. + */ + if ( + $default_width === $width + && ! empty( $content_width ) + ) { $width = absint( $content_width ); } - // If setting the width with content_width has failed, defaulting - if ( ! $width ) { - $width = 640; - } - - if ( ! $height ) { + /* + * If we have a custom width, we need a custom height as well + * to maintain aspect ratio. + */ + if ( + $default_width !== $width + && $default_height === $height + ) { $height = round( ( $width / 640 ) * 360 ); } @@ -121,13 +126,53 @@ function vimeo_shortcode( $atts ) { */ $height = (int) apply_filters( 'vimeo_height', $height ); + return array( $width, $height ); +} + +/** + * Convert a Vimeo shortcode into an embed code. + * + * @param array $atts An array of shortcode attributes. + * + * @return string The embed code for the Vimeo video. + */ +function vimeo_shortcode( $atts ) { + $attr = array_map( + 'intval', + shortcode_atts( + array( + 'id' => 0, + 'width' => 0, + 'height' => 0, + 'autoplay' => 0, + 'loop' => 0, + ), + $atts + ) + ); + + if ( isset( $atts[0] ) ) { + $attr['id'] = jetpack_shortcode_get_vimeo_id( $atts ); + } + + if ( ! $attr['id'] ) { + return '<!-- vimeo error: not a vimeo video -->'; + } + + // Handle old shortcode params such as h=500&w=350. + $params = shortcode_new_to_old_params( $atts ); + $params = str_replace( array( '&', '&' ), '&', $params ); + parse_str( $params, $args ); + + list( $width, $height ) = jetpack_shortcode_get_vimeo_dimensions( $attr, $args ); + $url = esc_url( 'https://player.vimeo.com/video/' . $attr['id'] ); // Handle autoplay and loop arguments. if ( isset( $args['autoplay'] ) && '1' === $args['autoplay'] // Parsed from the embedded URL. || $attr['autoplay'] // Parsed from shortcode arguments. - || in_array( 'autoplay', $atts ) // Catch the argument passed without a value. + || in_array( 'autoplay', $atts, true ) // Catch the argument passed without a value. ) { $url = add_query_arg( 'autoplay', 1, $url ); } @@ -135,17 +180,29 @@ function vimeo_shortcode( $atts ) { if ( isset( $args['loop'] ) && '1' === $args['loop'] // Parsed from the embedded URL. || $attr['loop'] // Parsed from shortcode arguments. - || in_array( 'loop', $atts ) // Catch the argument passed without a value. + || in_array( 'loop', $atts, true ) // Catch the argument passed without a value. ) { $url = add_query_arg( 'loop', 1, $url ); } - $html = sprintf( - '<div class="embed-vimeo" style="text-align: center;"><iframe src="%1$s" width="%2$u" height="%3$u" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>', - esc_url( $url ), - esc_attr( $width ), - esc_attr( $height ) - ); + if ( + class_exists( 'Jetpack_AMP_Support' ) + && Jetpack_AMP_Support::is_amp_request() + ) { + $html = sprintf( + '<amp-vimeo data-videoid="%1$s" layout="responsive" width="%2$d" height="%3$d"></amp-vimeo>', + esc_attr( $attr['id'] ), + absint( $width ), + absint( $height ) + ); + } else { + $html = sprintf( + '<div class="embed-vimeo" style="text-align: center;"><iframe src="%1$s" width="%2$u" height="%3$u" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>', + esc_url( $url ), + esc_attr( $width ), + esc_attr( $height ) + ); + } /** * Filter the Vimeo player HTML. @@ -160,7 +217,6 @@ function vimeo_shortcode( $atts ) { return $html; } - add_shortcode( 'vimeo', 'vimeo_shortcode' ); /** @@ -169,8 +225,8 @@ add_shortcode( 'vimeo', 'vimeo_shortcode' ); * @since 3.9 * * @param array $matches Regex partial matches against the URL passed. - * @param array $attr Attributes received in embed response - * @param array $url Requested URL to be embedded + * @param array $attr Attributes received in embed response. + * @param array $url Requested URL to be embedded. * * @return string Return output of Vimeo shortcode with the proper markup. */ @@ -190,9 +246,19 @@ function wpcom_vimeo_embed_url_init() { wp_embed_register_handler( 'wpcom_vimeo_embed_url', '#https?://(.+\.)?vimeo\.com/#i', 'wpcom_vimeo_embed_url' ); } -// Register handler to modify Vimeo embeds using Jetpack's shortcode output. -add_action( 'init', 'wpcom_vimeo_embed_url_init' ); +/* + * Register handler to modify Vimeo embeds using Jetpack's shortcode output. + * This does not happen on WordPress.com, since embeds are handled by core there. + */ +if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) { + add_action( 'init', 'wpcom_vimeo_embed_url_init' ); +} +/** + * Transform a Vimeo embed iFrame into a Vimeo shortcode. + * + * @param string $content Post content. + */ function vimeo_embed_to_shortcode( $content ) { if ( ! is_string( $content ) || false === stripos( $content, 'player.vimeo.com/video/' ) ) { return $content; @@ -201,8 +267,8 @@ function vimeo_embed_to_shortcode( $content ) { $regexp = '!<iframe\s+src=[\'"](https?:)?//player\.vimeo\.com/video/(\d+)[\w=&;?]*[\'"]((?:\s+\w+=[\'"][^\'"]*[\'"])*)((?:[\s\w]*))></iframe>!i'; $regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) ); - foreach ( array( 'regexp', 'regexp_ent' ) as $reg ) { - if ( ! preg_match_all( $$reg, $content, $matches, PREG_SET_ORDER ) ) { + foreach ( compact( 'regexp', 'regexp_ent' ) as $reg => $regexp ) { + if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) { continue; } @@ -211,7 +277,7 @@ function vimeo_embed_to_shortcode( $content ) { $params = $match[3]; - if ( 'regexp_ent' == $reg ) { + if ( 'regexp_ent' === $reg ) { $params = html_entity_decode( $params ); } @@ -232,7 +298,6 @@ function vimeo_embed_to_shortcode( $content ) { return $content; } - add_filter( 'pre_kses', 'vimeo_embed_to_shortcode' ); /** @@ -244,7 +309,8 @@ add_filter( 'pre_kses', 'vimeo_embed_to_shortcode' ); * @since 3.7.0 * @since 3.9.5 One regular expression matches shortcodes and plain URLs. * - * @param string $content HTML content + * @param string $content HTML content. + * * @return string The content with embeds instead of URLs */ function vimeo_link( $content ) { @@ -255,10 +321,12 @@ function vimeo_link( $content ) { $shortcode = '(?:\[vimeo\s+[^0-9]*)([0-9]+)(?:\])'; /** - * http://vimeo.com/12345 - * https://vimeo.com/12345 - * //vimeo.com/12345 - * vimeo.com/some/descender/12345 + * Regex to look for a Vimeo link. + * + * - http://vimeo.com/12345 + * - https://vimeo.com/12345 + * - //vimeo.com/12345 + * - vimeo.com/some/descender/12345 * * Should not capture inside HTML attributes * [Not] <a href="vimeo.com/12345">Cool Video</a> @@ -293,9 +361,17 @@ function vimeo_link_callback( $matches ) { return $matches[0]; } -/** This filter is documented in modules/shortcodes/youtube.php */ -if ( ! is_admin() && apply_filters( 'jetpack_comments_allow_oembed', true ) ) { - // We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway, so the iframe gets filtered out. - // Higher priority because we need it before auto-link and autop get to it +if ( + ! is_admin() + /** This filter is documented in modules/shortcodes/youtube.php */ + && apply_filters( 'jetpack_comments_allow_oembed', true ) + // No need for this on WordPress.com, this is done for multiple shortcodes at a time there. + && ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) +) { + /* + * We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway, + * so the iframe gets filtered out. + * Higher priority because we need it before auto-link and autop get to it + */ add_filter( 'comment_text', 'vimeo_link', 1 ); } diff --git a/plugins/jetpack/modules/shortcodes/vine.php b/plugins/jetpack/modules/shortcodes/vine.php index 444b9999..e1681622 100644 --- a/plugins/jetpack/modules/shortcodes/vine.php +++ b/plugins/jetpack/modules/shortcodes/vine.php @@ -1,9 +1,9 @@ <?php /** * Vine shortcode - */ - -/** + * The service is now archived, but existing embeds are still accessible. + * + * Examples: * Vine embed code: * <iframe class="vine-embed" src="https://vine.co/v/bjHh0zHdgZT" width="600" height="600" frameborder="0"></iframe> * <script async src="//platform.vine.co/static/scripts/embed.js" charset="utf-8"></script> @@ -15,22 +15,34 @@ * [embed]https://vine.co/v/bjHh0zHdgZT[/embed] * [embed width="300"]https://vine.co/v/bjHh0zHdgZT[/embed] * [embed type="postcard" width="300"]https://vine.co/v/bjHh0zHdgZT[/embed] - **/ + * + * @package Jetpack + */ +/** + * Handle Vine embeds. + * + * @param array $matches Results after parsing the URL using the regex in wp_embed_register_handler(). + * @param array $attr Embed attributes. + * @param string $url The original URL that was matched by the regex. + * @param array $rawattr The original unmodified attributes. + * @return string The embed HTML. + */ function vine_embed_video( $matches, $attr, $url, $rawattr ) { - static $vine_flag_embedded_script; - $max_height = 300; $type = 'simple'; - // Only allow 'postcard' or 'simple' types - if ( isset( $rawattr['type'] ) && $rawattr['type'] === 'postcard' ) { + // Only allow 'postcard' or 'simple' types. + if ( + isset( $rawattr['type'] ) + && 'postcard' === $rawattr['type'] + ) { $type = 'postcard'; } $vine_size = Jetpack::get_content_width(); - // If the user enters a value for width or height, we ignore the Jetpack::get_content_width() + // If the user enters a value for width or height, we ignore the Jetpack::get_content_width(). if ( isset( $rawattr['width'] ) || isset( $rawattr['height'] ) ) { // 300 is the minimum size that Vine provides for embeds. Lower than that, the postcard embeds looks weird. $vine_size = max( $max_height, min( $attr['width'], $attr['height'] ) ); @@ -41,17 +53,30 @@ function vine_embed_video( $matches, $attr, $url, $rawattr ) { } $url = 'https://vine.co/v/' . $matches[1] . '/embed/' . $type; - $vine_html = sprintf( '<span class="embed-vine" style="display: block;"><iframe class="vine-embed" src="%s" width="%s" height="%s" frameborder="0"></iframe></span>', esc_url( $url ), (int) $vine_size, (int) $vine_size ); + $vine_html = sprintf( + '<span class="embed-vine" style="display: block;"><iframe class="vine-embed" src="%1$s" width="%2$d" height="%3$d" frameborder="0"></iframe></span>', + esc_url( $url ), + (int) $vine_size, + (int) $vine_size + ); - if ( $vine_flag_embedded_script !== true ) { - $vine_html .= '<script async src="//platform.vine.co/static/scripts/embed.js" charset="utf-8"></script>'; - $vine_flag_embedded_script = true; - } + wp_enqueue_script( + 'vine-embed', + 'https://platform.vine.co/static/scripts/embed.js', + array(), + JETPACK__VERSION, + true + ); return $vine_html; } wp_embed_register_handler( 'jetpack_vine', '#https?://vine.co/v/([a-z0-9]+).*#i', 'vine_embed_video' ); +/** + * Display the Vine shortcode. + * + * @param array $atts Shortcode attributes. + */ function vine_shortcode( $atts ) { global $wp_embed; diff --git a/plugins/jetpack/modules/shortcodes/wordads.php b/plugins/jetpack/modules/shortcodes/wordads.php index bca6c48a..f1797d88 100644 --- a/plugins/jetpack/modules/shortcodes/wordads.php +++ b/plugins/jetpack/modules/shortcodes/wordads.php @@ -1,20 +1,36 @@ -<?php +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName +/** + * Wordads shortcode. + * + * Examples: + * [wordads] + * + * @package Jetpack + */ /** * Embed WordAds 'ad' in post */ class Jetpack_WordAds_Shortcode { + /** + * Used to determine whether scripts and styles have been enqueued already. + * + * @var bool false Should we enqueue scripts and styles. + */ private $scripts_and_style_included = false; - function __construct() { + /** + * Initialize. + */ + public function __construct() { add_action( 'init', array( $this, 'action_init' ) ); } /** * Register our shortcode and enqueue necessary files. */ - function action_init() { + public function action_init() { global $wordads; if ( empty( $wordads ) ) { @@ -33,7 +49,7 @@ class Jetpack_WordAds_Shortcode { * * @return string HTML for WordAds shortcode. */ - static function wordads_shortcode( $atts, $content = '' ) { + public static function wordads_shortcode( $atts, $content = '' ) { $atts = shortcode_atts( array(), $atts, 'wordads' ); return self::wordads_shortcode_html( $atts, $content ); @@ -47,7 +63,7 @@ class Jetpack_WordAds_Shortcode { * * @return string HTML output */ - static function wordads_shortcode_html( $atts, $content = '' ) { + private static function wordads_shortcode_html( $atts, $content = '' ) { global $wordads; if ( empty( $wordads ) ) { diff --git a/plugins/jetpack/modules/shortcodes/wufoo.php b/plugins/jetpack/modules/shortcodes/wufoo.php index fbe6fe70..023da496 100644 --- a/plugins/jetpack/modules/shortcodes/wufoo.php +++ b/plugins/jetpack/modules/shortcodes/wufoo.php @@ -1,14 +1,19 @@ <?php -/* -Plugin Name: Wufoo Shortcode Plugin -Description: Enables shortcode to embed Wufoo forms. Usage: [wufoo username="chriscoyier" formhash="x7w3w3" autoresize="true" height="458" header="show"] -Author: Chris Coyier / Wufoo, evansolomon - -Based on https://wordpress.org/extend/plugins/wufoo-shortcode/ -https://wufoo.com/docs/code-manager/wordpress-shortcode-plugin/ -*/ - +/** + * Plugin Name: Wufoo Shortcode + * Based on https://wordpress.org/plugins/wufoo-shortcode/ + * + * Examples: + * [wufoo username="jeherve" formhash="z1x13ltw1m8jtrw" autoresize="true" height="338" header="show"] + * + * @package Jetpack + */ +/** + * Display the Wufoo shortcode. + * + * @param array $atts Shortcode attributes. + */ function wufoo_shortcode( $atts ) { $attr = shortcode_atts( array( @@ -22,59 +27,87 @@ function wufoo_shortcode( $atts ) { ); // Check username and formhash to ensure they only have alphanumeric characters or underscores, and aren't empty. - if ( ! preg_match( '/^[a-zA-Z0-9_]+$/', $attr['username'] ) || ! preg_match( '/^[a-zA-Z0-9_]+$/', $attr['formhash'] ) ) { - - /** + if ( + ! preg_match( '/^[a-zA-Z0-9_]+$/', $attr['username'] ) + || ! preg_match( '/^[a-zA-Z0-9_]+$/', $attr['formhash'] ) + ) { + /* * Return an error to the users with instructions if one of these params is invalid * They don't have default values because they are user/form-specific */ - $return_error = sprintf( __( 'Something is wrong with your Wufoo shortcode. If you copy and paste it from the %1$sWufoo Code Manager%2$s, you should be golden.', 'jetpack' ), '<a href="https://wufoo.com/docs/code-manager/" target="_blank">', '</a>' ); - - return ' - <div style="border: 20px solid red; border-radius: 40px; padding: 40px; margin: 50px 0 70px;"> - <h3>Uh oh!</h3> - <p style="margin: 0;">' . $return_error . '</p> - </div>'; + if ( current_user_can( 'edit_posts' ) ) { + return sprintf( + wp_kses( + /* translators: URL to Wufoo support page. */ + __( 'Something is wrong with your Wufoo shortcode. Try following the instructions <a href="%s" target="_blank" rel="noopener noreferrer">here</a> to embed a form on your site.', 'jetpack' ), + array( + 'a' => array( + 'href' => array(), + 'target' => array(), + 'rel' => array(), + ), + ) + ), + 'https://help.wufoo.com/articles/en_US/kb/Embed' + ); + } } /** * Placeholder which will tell Wufoo where to render the form. */ - $js_embed_placeholder = '<div id="wufoo-' . $attr['formhash'] . '"></div>'; + $js_embed_placeholder = sprintf( + '<div id="wufoo-%s"></div>', + esc_attr( $attr['formhash'] ) + ); /** * Required parameters are present. * An error will be returned inside the form if they are invalid. */ - $js_embed = '(function(){try{var wufoo_' . $attr['formhash'] . ' = new WufooForm();'; - $js_embed .= 'wufoo_' . $attr['formhash'] . '.initialize({'; - $js_embed .= "'userName':'" . $attr['username'] . "', "; - $js_embed .= "'formHash':'" . $attr['formhash'] . "', "; - $js_embed .= "'autoResize':" . (bool) ( $attr['autoresize'] ) . ','; - $js_embed .= "'height':'" . (int) $attr['height'] . "',"; - $js_embed .= "'header':'" . esc_js( $attr['header'] ) . "',"; - $js_embed .= "'ssl':true,'async':true});"; - $js_embed .= 'wufoo_' . $attr['formhash'] . '.display();'; - $js_embed .= '}catch(e){}})();'; + $js_embed = sprintf( + '(function(){try{var wufoo_%1$s = new WufooForm();wufoo_%1$s.initialize({"userName":"%2$s","formHash":"%1$s","autoResize":"%3$s","height":"%4$d","header":"%5$s","ssl":true,"async":true});wufoo_%1$s.display();}catch(e){}})();', + esc_attr( $attr['formhash'] ), + esc_attr( $attr['username'] ), + esc_attr( $attr['autoresize'] ), + absint( $attr['height'] ), + esc_js( $attr['header'] ) + ); - /** + // Embed URL. + $embed_url = sprintf( + 'https://%1$s.wufoo.com/embed/%2$s/', + $attr['username'], + $attr['formhash'] + ); + + // Form URL. + $form_url = sprintf( + 'https://%1$s.wufoo.com/forms/%2$s/', + $attr['username'], + $attr['formhash'] + ); + + /* * iframe embed, loaded inside <noscript> tags. */ - $iframe_embed = '<iframe '; - $iframe_embed .= 'height="' . (int) $attr['height'] . '" '; - $iframe_embed .= 'allowTransparency="true" frameborder="0" scrolling="no" style="width:100%;border:none;"'; - $iframe_embed .= 'src="https://' . $attr['username'] . '.wufoo.com/embed/' . $attr['formhash'] . '/">'; - $iframe_embed .= '<a href="https://' . $attr['username'] . '.wufoo.com/forms/' . $attr['formhash'] . '/" '; - $iframe_embed .= 'rel="nofollow" target="_blank">' . __( 'Fill out my Wufoo form!', 'jetpack' ) . '</a></iframe>'; + $iframe_embed = sprintf( + '<iframe height="%1$d" src="%2$s" allowTransparency="true" frameborder="0" scrolling="no" style="width:100%;border:none;"> + <a href="%3$s" target="_blank" rel="noopener noreferrer">%4$s</a> + </iframe>', + absint( $attr['height'] ), + esc_url( $embed_url ), + esc_url( $form_url ), + esc_html__( 'Fill out my Wufoo form!', 'jetpack' ) + ); wp_enqueue_script( 'wufoo-form', 'https://www.wufoo.com/scripts/embed/form.js', array(), - false, + JETPACK__VERSION, true ); - wp_add_inline_script( 'wufoo-form', $js_embed ); /** This action is already documented in modules/widgets/gravatar-profile.php */ @@ -85,5 +118,4 @@ function wufoo_shortcode( $atts ) { */ return "$js_embed_placeholder<noscript>$iframe_embed</noscript>"; } - add_shortcode( 'wufoo', 'wufoo_shortcode' ); diff --git a/plugins/jetpack/modules/shortcodes/youtube.php b/plugins/jetpack/modules/shortcodes/youtube.php index 048eb09b..f3e37faf 100644 --- a/plugins/jetpack/modules/shortcodes/youtube.php +++ b/plugins/jetpack/modules/shortcodes/youtube.php @@ -1,64 +1,73 @@ <?php - /** - * youtube shortcode + * Youtube shortcode + * + * Contains shortcode + some improvements over the Core Embeds syntax (see http://codex.wordpress.org/Embeds ) * - * Contains shortcode + some improvements over the Embeds syntax @ - * http://codex.wordpress.org/Embeds + * Examples: + * [youtube https://www.youtube.com/watch?v=WVbQ-oro7FQ] + * [youtube=http://www.youtube.com/watch?v=wq0rXGLs0YM&fs=1&hl=bg_BG&autohide=1&rel=0] + * http://www.youtube.com/watch?v=H2Ncxw1xfck&w=320&h=240&fmt=1&rel=0&showsearch=1&hd=0 + * http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US + * https://www.youtube.com/playlist?list=PLP7HaNDU4Cifov7C2fQM8Ij6Ew_uPHEXW * - * @example [youtube=http://www.youtube.com/watch?v=wq0rXGLs0YM&fs=1&hl=bg_BG] + * @package Jetpack */ /** * Replaces YouTube embeds with YouTube shortcodes. * + * Covers the following formats: + * 2008-07-15: + * <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/bZBHZT3a-FA&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/bZBHZT3a-FA&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object> + * around 2008-06-06 youtube changed their old embed code to this: + * <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/M1D30gS7Z8U&hl=en"></param><embed src="http://www.youtube.com/v/M1D30gS7Z8U&hl=en" type="application/x-shockwave-flash" width="425" height="344"></embed></object> + * old style was: + * <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/dGY28Qbj76A&rel=0"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/dGY28Qbj76A&rel=0" type="application/x-shockwave-flash" wmode="transparent" width="425" height="344"></embed></object> + * 12-2010: + * <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/3H8bnKdf654?fs=1&hl=en_GB"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/3H8bnKdf654?fs=1&hl=en_GB" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object> + * 01-2011: + * <iframe title="YouTube video player" class="youtube-player" type="text/html" width="640" height="390" src="http://www.youtube.com/embed/Qq9El3ki0_g" frameborder="0" allowFullScreen></iframe> + * <iframe class="youtube-player" type="text/html" width="640" height="385" src="http://www.youtube.com/embed/VIDEO_ID" frameborder="0"></iframe> + * * @param string $content HTML content. * @return string The content with YouTube embeds replaced with YouTube shortcodes. */ -// 2008-07-15: -// <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/bZBHZT3a-FA&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/bZBHZT3a-FA&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object> -// around 2008-06-06 youtube changed their old embed code to this: -// <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/M1D30gS7Z8U&hl=en"></param><embed src="http://www.youtube.com/v/M1D30gS7Z8U&hl=en" type="application/x-shockwave-flash" width="425" height="344"></embed></object> -// old style was: -// <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/dGY28Qbj76A&rel=0"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/dGY28Qbj76A&rel=0" type="application/x-shockwave-flash" wmode="transparent" width="425" height="344"></embed></object> -// 12-2010: -// <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/3H8bnKdf654?fs=1&hl=en_GB"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/3H8bnKdf654?fs=1&hl=en_GB" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object> -// 01-2011: -// <iframe title="YouTube video player" class="youtube-player" type="text/html" width="640" height="390" src="http://www.youtube.com/embed/Qq9El3ki0_g" frameborder="0" allowFullScreen></iframe> -// <iframe class="youtube-player" type="text/html" width="640" height="385" src="http://www.youtube.com/embed/VIDEO_ID" frameborder="0"></iframe> function youtube_embed_to_short_code( $content ) { if ( ! is_string( $content ) || false === strpos( $content, 'youtube.com' ) ) { return $content; } - // older codes + // older codes. $regexp = '!<object(.*?)>.*?<param\s+name=[\'"]movie[\'"]\s+value=[\'"](https?:)?//www\.youtube\.com/v/([^\'"]+)[\'"].*?>.*?</object>!i'; $regexp_ent = htmlspecialchars( $regexp, ENT_NOQUOTES ); $old_regexp = '!<embed(?:\s+\w+="[^"]*")*\s+src="https?(?:\:|�*58;)//www\.youtube\.com/v/([^"]+)"(?:\s+\w+="[^"]*")*\s*(?:/>|>\s*</embed>)!'; $old_regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $old_regexp, ENT_NOQUOTES ) ); - // new code + // new code. $ifr_regexp = '!<iframe((?:\s+\w+="[^"]*")*?)\s+src="(https?:)?//(?:www\.)*youtube.com/embed/([^"]+)".*?</iframe>!i'; $ifr_regexp_ent = str_replace( '&#0*58;', '&#0*58;|�*58;', htmlspecialchars( $ifr_regexp, ENT_NOQUOTES ) ); - foreach ( array( 'regexp', 'regexp_ent', 'old_regexp', 'old_regexp_ent', 'ifr_regexp', 'ifr_regexp_ent' ) as $reg ) { - if ( ! preg_match_all( $$reg, $content, $matches, PREG_SET_ORDER ) ) { + foreach ( compact( 'regexp', 'regexp_ent', 'old_regexp', 'old_regexp_ent', 'ifr_regexp', 'ifr_regexp_ent' ) as $reg => $regexp ) { + if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) { continue; } foreach ( $matches as $match ) { - // Hack, but '?' should only ever appear once, and - // it should be for the 1st field-value pair in query string, - // if it is present - // YouTube changed their embed code. - // Example of how it is now: - // <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/aP9AaD4tgBY?fs=1&hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/aP9AaD4tgBY?fs=1&hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object> - // As shown at the start of function, previous YouTube didn't '?' - // the 1st field-value pair. - if ( in_array( $reg, array( 'ifr_regexp', 'ifr_regexp_ent', 'regexp', 'regexp_ent' ) ) ) { + /* + * Hack, but '?' should only ever appear once, and + * it should be for the 1st field-value pair in query string, + * if it is present + * YouTube changed their embed code. + * Example of how it is now: + * <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/aP9AaD4tgBY?fs=1&hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/aP9AaD4tgBY?fs=1&hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object> + * As shown at the start of function, previous YouTube didn't '?' + * the 1st field-value pair. + */ + if ( in_array( $reg, array( 'ifr_regexp', 'ifr_regexp_ent', 'regexp', 'regexp_ent' ), true ) ) { $params = $match[1]; - if ( in_array( $reg, array( 'ifr_regexp_ent', 'regexp_ent' ) ) ) { + if ( in_array( $reg, array( 'ifr_regexp_ent', 'regexp_ent' ), true ) ) { $params = html_entity_decode( $params ); } @@ -97,13 +106,13 @@ function youtube_embed_to_short_code( $content ) { return $content; } - add_filter( 'pre_kses', 'youtube_embed_to_short_code' ); /** * Replaces plain-text links to YouTube videos with YouTube embeds. * - * @param string $content HTML content + * @param string $content HTML content. + * * @return string The content with embeds instead of URLs */ function youtube_link( $content ) { @@ -113,6 +122,8 @@ function youtube_link( $content ) { /** * Callback function for the regex that replaces YouTube URLs with * YouTube embeds. + * + * @param array $matches An array containing a YouTube URL. */ function youtube_link_callback( $matches ) { return "\n" . youtube_id( $matches[0] ) . "\n"; @@ -125,6 +136,11 @@ function youtube_link_callback( $matches ) { * @return string The normalized URL */ if ( ! function_exists( 'youtube_sanitize_url' ) ) : + /** + * Clean up Youtube URL to match a single format. + * + * @param string $url Youtube URL. + */ function youtube_sanitize_url( $url ) { $url = trim( $url, ' "' ); $url = trim( $url ); @@ -141,8 +157,10 @@ if ( ! function_exists( 'youtube_sanitize_url' ) ) : } endif; -/* - * url can be: +/** + * Converts a YouTube URL into an embedded YouTube video. + * + * URL can be: * http://www.youtube.com/embed/videoseries?list=PL94269DA08231042B&hl=en_US * http://www.youtube.com/watch#!v=H2Ncxw1xfck * http://www.youtube.com/watch?v=H2Ncxw1xfck @@ -150,113 +168,43 @@ endif; * http://www.youtube.com/v/jF-kELmmvgA * http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US * http://youtu.be/Rrohlqeir5E - */ - -/** - * Converts a YouTube URL into an embedded YouTube video. + * + * @param string $url Youtube URL. */ function youtube_id( $url ) { - if ( ! $id = jetpack_get_youtube_id( $url ) ) { - return '<!--YouTube Error: bad URL entered-->'; + $id = jetpack_get_youtube_id( $url ); + + if ( ! $id ) { + return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: bad URL entered', 'jetpack' ) ); } $url = youtube_sanitize_url( $url ); - $url = parse_url( $url ); + $url = wp_parse_url( $url ); - if ( ! isset( $url['query'] ) ) { - return false; + $args = jetpack_shortcode_youtube_args( $url ); + if ( empty( $args ) ) { + return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: empty URL args', 'jetpack' ) ); } - if ( isset( $url['fragment'] ) ) { - wp_parse_str( $url['fragment'], $fargs ); - } else { - $fargs = array(); - } - wp_parse_str( $url['query'], $qargs ); - - $qargs = array_merge( $fargs, $qargs ); - - // calculate the width and height, taking content_width into consideration - global $content_width; - - $input_w = ( isset( $qargs['w'] ) && intval( $qargs['w'] ) ) ? intval( $qargs['w'] ) : 0; - $input_h = ( isset( $qargs['h'] ) && intval( $qargs['h'] ) ) ? intval( $qargs['h'] ) : 0; + list( $w, $h ) = jetpack_shortcode_youtube_dimensions( $args ); + $rel = ( isset( $args['rel'] ) && '0' === $args['rel'] ) ? 0 : 1; + $search = ( isset( $args['showsearch'] ) && '1' === $args['showsearch'] ) ? 1 : 0; + $info = ( isset( $args['showinfo'] ) && '0' === $args['showinfo'] ) ? 0 : 1; + $iv = ( isset( $args['iv_load_policy'] ) && '3' === $args['iv_load_policy'] ) ? 3 : 1; - // If we have $content_width, use it. - if ( ! empty( $content_width ) ) { - $default_width = $content_width; - } else { - // Otherwise get default width from the old, now deprecated embed_size_w option. - $default_width = get_option( 'embed_size_w' ); - } + $fmt = ( isset( $args['fmt'] ) && intval( $args['fmt'] ) ) ? '&fmt=' . (int) $args['fmt'] : ''; - // If we don't know those 2 values use a hardcoded width.h - if ( empty( $default_width ) ) { - $default_width = 640; - } - - if ( $input_w > 0 && $input_h > 0 ) { - $w = $input_w; - $h = $input_h; - } elseif ( 0 == $input_w && 0 == $input_h ) { - if ( isset( $qargs['fmt'] ) && intval( $qargs['fmt'] ) ) { - $w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 ); - } else { - $w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width ); - $h = ceil( ( $w / 16 ) * 9 ); - } - } elseif ( $input_w > 0 ) { - $w = $input_w; - $h = ceil( ( $w / 16 ) * 9 ); - } else { - if ( isset( $qargs['fmt'] ) && intval( $qargs['fmt'] ) ) { - $w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 ); - } else { - $w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width ); - $h = $input_h; - } - } - - /** - * Filter the YouTube player width. - * - * @module shortcodes - * - * @since 1.1.0 - * - * @param int $w Width of the YouTube player in pixels. - */ - $w = (int) apply_filters( 'youtube_width', $w ); - - /** - * Filter the YouTube player height. - * - * @module shortcodes - * - * @since 1.1.0 - * - * @param int $h Height of the YouTube player in pixels. - */ - $h = (int) apply_filters( 'youtube_height', $h ); - - $rel = ( isset( $qargs['rel'] ) && 0 == $qargs['rel'] ) ? 0 : 1; - $search = ( isset( $qargs['showsearch'] ) && 1 == $qargs['showsearch'] ) ? 1 : 0; - $info = ( isset( $qargs['showinfo'] ) && 0 == $qargs['showinfo'] ) ? 0 : 1; - $iv = ( isset( $qargs['iv_load_policy'] ) && 3 == $qargs['iv_load_policy'] ) ? 3 : 1; - - $fmt = ( isset( $qargs['fmt'] ) && intval( $qargs['fmt'] ) ) ? '&fmt=' . (int) $qargs['fmt'] : ''; - - if ( ! isset( $qargs['autohide'] ) || ( $qargs['autohide'] < 0 || 2 < $qargs['autohide'] ) ) { + if ( ! isset( $args['autohide'] ) || ( $args['autohide'] < 0 || 2 < $args['autohide'] ) ) { $autohide = '&autohide=2'; } else { - $autohide = '&autohide=' . absint( $qargs['autohide'] ); + $autohide = '&autohide=' . absint( $args['autohide'] ); } $start = 0; - if ( isset( $qargs['start'] ) ) { - $start = intval( $qargs['start'] ); - } elseif ( isset( $qargs['t'] ) ) { - $time_pieces = preg_split( '/(?<=\D)(?=\d+)/', $qargs['t'] ); + if ( isset( $args['start'] ) ) { + $start = intval( $args['start'] ); + } elseif ( isset( $args['t'] ) ) { + $time_pieces = preg_split( '/(?<=\D)(?=\d+)/', $args['t'] ); foreach ( $time_pieces as $time_piece ) { $int = (int) $time_piece; @@ -275,17 +223,17 @@ function youtube_id( $url ) { } $start = $start ? '&start=' . $start : ''; - $end = ( isset( $qargs['end'] ) && intval( $qargs['end'] ) ) ? '&end=' . (int) $qargs['end'] : ''; - $hd = ( isset( $qargs['hd'] ) && intval( $qargs['hd'] ) ) ? '&hd=' . (int) $qargs['hd'] : ''; + $end = ( isset( $args['end'] ) && intval( $args['end'] ) ) ? '&end=' . (int) $args['end'] : ''; + $hd = ( isset( $args['hd'] ) && intval( $args['hd'] ) ) ? '&hd=' . (int) $args['hd'] : ''; - $vq = ( isset( $qargs['vq'] ) && in_array( $qargs['vq'], array( 'hd720', 'hd1080' ) ) ) ? '&vq=' . $qargs['vq'] : ''; + $vq = ( isset( $args['vq'] ) && in_array( $args['vq'], array( 'hd720', 'hd1080' ), true ) ) ? '&vq=' . $args['vq'] : ''; - $cc = ( isset( $qargs['cc_load_policy'] ) ) ? '&cc_load_policy=1' : ''; - $cc_lang = ( isset( $qargs['cc_lang_pref'] ) ) ? '&cc_lang_pref=' . preg_replace( '/[^_a-z0-9-]/i', '', $qargs['cc_lang_pref'] ) : ''; + $cc = ( isset( $args['cc_load_policy'] ) ) ? '&cc_load_policy=1' : ''; + $cc_lang = ( isset( $args['cc_lang_pref'] ) ) ? '&cc_lang_pref=' . preg_replace( '/[^_a-z0-9-]/i', '', $args['cc_lang_pref'] ) : ''; - $wmode = ( isset( $qargs['wmode'] ) && in_array( strtolower( $qargs['wmode'] ), array( 'opaque', 'window', 'transparent' ) ) ) ? $qargs['wmode'] : 'transparent'; + $wmode = ( isset( $args['wmode'] ) && in_array( strtolower( $args['wmode'] ), array( 'opaque', 'window', 'transparent' ), true ) ) ? $args['wmode'] : 'transparent'; - $theme = ( isset( $qargs['theme'] ) && in_array( strtolower( $qargs['theme'] ), array( 'dark', 'light' ) ) ) ? '&theme=' . $qargs['theme'] : ''; + $theme = ( isset( $args['theme'] ) && in_array( strtolower( $args['theme'] ), array( 'dark', 'light' ), true ) ) ? '&theme=' . $args['theme'] : ''; $autoplay = ''; /** @@ -297,21 +245,24 @@ function youtube_id( $url ) { * * @param bool false Enable autoplay for YouTube videos. */ - if ( apply_filters( 'jetpack_youtube_allow_autoplay', false ) && isset( $qargs['autoplay'] ) ) { - $autoplay = '&autoplay=' . (int) $qargs['autoplay']; + if ( apply_filters( 'jetpack_youtube_allow_autoplay', false ) && isset( $args['autoplay'] ) ) { + $autoplay = '&autoplay=' . (int) $args['autoplay']; } - if ( ( isset( $url['path'] ) && '/videoseries' == $url['path'] ) || isset( $qargs['list'] ) ) { + if ( + ( isset( $url['path'] ) && '/videoseries' === $url['path'] ) + || isset( $args['list'] ) + ) { $html = "<iframe class='youtube-player' type='text/html' width='$w' height='$h' src='" . esc_url( "https://www.youtube.com/embed/videoseries?list=$id&hl=en_US" ) . "' allowfullscreen='true' style='border:0;'></iframe>"; } else { - $html = "<iframe class='youtube-player' type='text/html' width='$w' height='$h' src='" . esc_url( "https://www.youtube.com/embed/$id?version=3&rel=$rel&fs=1$fmt$autohide&showsearch=$search&showinfo=$info&iv_load_policy=$iv$start$end$hd&wmode=$wmode$theme$autoplay{$cc}{$cc_lang}" ) . "' allowfullscreen='true' style='border:0;'></iframe>"; + $html = "<iframe class='youtube-player' type='text/html' width='$w' height='$h' src='" . esc_url( "https://www.youtube.com/embed/$id?version=3&rel=$rel&fs=1$fmt$autohide&showsearch=$search&showinfo=$info&iv_load_policy=$iv$start$end$hd&wmode=$wmode$theme$autoplay$vq{$cc}{$cc_lang}" ) . "' allowfullscreen='true' style='border:0;'></iframe>"; } - // Let's do some alignment wonder in a span, unless we're producing a feed + // Let's do some alignment wonder in a span, unless we're producing a feed. if ( ! is_feed() ) { $alignmentcss = 'text-align:center;'; - if ( isset( $qargs['align'] ) ) { - switch ( $qargs['align'] ) { + if ( isset( $args['align'] ) ) { + switch ( $args['align'] ) { case 'left': $alignmentcss = "float:left; width:{$w}px; height:{$h}px; margin-right:10px; margin-bottom: 10px;"; break; @@ -343,24 +294,177 @@ function youtube_id( $url ) { return $html; } -function youtube_shortcode( $atts ) { - return youtube_id( ( isset( $atts[0] ) ) ? ltrim( $atts[0], '=' ) : shortcode_new_to_old_params( $atts ) ); +/** + * Gets the args present in the YouTube shortcode URL. + * + * @since 8.0.0 + * + * @param string $url The URL of the shortcode. + * + * @return array|false The query args of the URL, or false. + */ +function jetpack_shortcode_youtube_args( $url ) { + $qargs = array(); + if ( ! empty( $url['query'] ) ) { + wp_parse_str( $url['query'], $qargs ); + } else { + return false; + } + + $fargs = array(); + if ( ! empty( $url['fragment'] ) ) { + wp_parse_str( $url['fragment'], $fargs ); + } + + return array_merge( $fargs, $qargs ); } +/** + * Display the Youtube shortcode. + * + * @param array $atts Shortcode attributes. + * + * @return string The rendered shortcode. + */ +function youtube_shortcode( $atts ) { + $url = ( isset( $atts[0] ) ) ? ltrim( $atts[0], '=' ) : shortcode_new_to_old_params( $atts ); + + if ( + class_exists( 'Jetpack_AMP_Support' ) + && Jetpack_AMP_Support::is_amp_request() + ) { + return jetpack_amp_youtube_shortcode( $url ); + } else { + return youtube_id( $url ); + } +} add_shortcode( 'youtube', 'youtube_shortcode' ); /** + * Renders the [youtube] shortcode as an AMP component. + * + * @since 8.0.0 + * + * @param string $url The YouTube URL. + * + * @return string The AMP-compatible rendered shortcode. + */ +function jetpack_amp_youtube_shortcode( $url ) { + $video_id = jetpack_get_youtube_id( $url ); + if ( empty( $video_id ) ) { + return sprintf( + '<a href="%1$s" class="amp-wp-embed-fallback">%1$s</a>', + esc_url( $url ) + ); + } + + $sanitized_url = youtube_sanitize_url( $url ); + $parsed_url = wp_parse_url( $sanitized_url ); + $args = jetpack_shortcode_youtube_args( $parsed_url ); + list( $width, $height ) = jetpack_shortcode_youtube_dimensions( $args ); + return sprintf( + '<amp-youtube data-videoid="%s" layout="responsive" width="%d" height="%d"></amp-youtube>', + esc_attr( $video_id ), + absint( $width ), + absint( $height ) + ); +} + +/** + * Gets the dimensions of the [youtube] shortcode. + * + * Calculates the width and height, taking $content_width into consideration. + * + * @since 8.0.0 + * + * @param array $query_args The query args of the URL. + * + * @return array The width and height of the shortcode. + */ +function jetpack_shortcode_youtube_dimensions( $query_args ) { + global $content_width; + + $input_w = ( isset( $query_args['w'] ) && intval( $query_args['w'] ) ) ? intval( $query_args['w'] ) : 0; + $input_h = ( isset( $query_args['h'] ) && intval( $query_args['h'] ) ) ? intval( $query_args['h'] ) : 0; + + // If we have $content_width, use it. + if ( ! empty( $content_width ) ) { + $default_width = $content_width; + } else { + // Otherwise get default width from the old, now deprecated embed_size_w option. + $default_width = get_option( 'embed_size_w' ); + } + + // If we don't know those 2 values use a hardcoded width. + if ( empty( $default_width ) ) { + $default_width = 640; + } + + if ( $input_w > 0 && $input_h > 0 ) { + $w = $input_w; + $h = $input_h; + } elseif ( 0 === $input_w && 0 === $input_h ) { + if ( isset( $query_args['fmt'] ) && intval( $query_args['fmt'] ) ) { + $w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 ); + } else { + $w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width ); + $h = ceil( ( $w / 16 ) * 9 ); + } + } elseif ( $input_w > 0 ) { + $w = $input_w; + $h = ceil( ( $w / 16 ) * 9 ); + } else { + if ( isset( $query_args['fmt'] ) && intval( $query_args['fmt'] ) ) { + $w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 ); + } else { + $w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width ); + $h = $input_h; + } + } + + /** + * Filter the YouTube player width. + * + * @module shortcodes + * + * @since 1.1.0 + * + * @param int $w Width of the YouTube player in pixels. + */ + $w = (int) apply_filters( 'youtube_width', $w ); + + /** + * Filter the YouTube player height. + * + * @module shortcodes + * + * @since 1.1.0 + * + * @param int $h Height of the YouTube player in pixels. + */ + $h = (int) apply_filters( 'youtube_height', $h ); + + return array( $w, $h ); +} + +/** * For bare URLs on their own line of the form * http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US + * + * @param array $matches Regex partial matches against the URL passed. + * @param array $attr Attributes received in embed response. + * @param array $url Requested URL to be embedded. */ function wpcom_youtube_embed_crazy_url( $matches, $attr, $url ) { return youtube_id( $url ); } +/** + * Add a new handler to automatically transform custom Youtube URLs (like playlists) into embeds. + */ function wpcom_youtube_embed_crazy_url_init() { wp_embed_register_handler( 'wpcom_youtube_embed_crazy_url', '#https?://(?:www\.)?(?:youtube.com/(?:v/|playlist|watch[/\#?])|youtu\.be/).*#i', 'wpcom_youtube_embed_crazy_url' ); } - add_action( 'init', 'wpcom_youtube_embed_crazy_url_init' ); /** @@ -373,8 +477,11 @@ add_action( 'init', 'wpcom_youtube_embed_crazy_url_init' ); * @param int get_option('embed_autourls') Option to automatically embed all plain text URLs. */ if ( ! is_admin() && apply_filters( 'jetpack_comments_allow_oembed', true ) ) { - // We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway, so the iframe gets filtered out. - // Higher priority because we need it before auto-link and autop get to it + /* + * We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway, + * so the iframe gets filtered out. + * Higher priority because we need it before auto-link and autop get to it. + */ add_filter( 'comment_text', 'youtube_link', 1 ); } @@ -385,6 +492,8 @@ if ( ! is_admin() && apply_filters( 'jetpack_comments_allow_oembed', true ) ) { * This removes the "=" from the shortcode so it can be parsed. * * @see https://github.com/Automattic/jetpack/issues/3121 + * + * @param string $content HTML content. */ function jetpack_fix_youtube_shortcode_display_filter( $content ) { if ( strpos( $content, '[youtube=' ) !== false ) { |