Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 4
CRAP
n/a
0 / 0
jetpack_responsive_videos_init
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
jetpack_responsive_videos_embed_html
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
42
jetpack_responsive_videos_maybe_wrap_oembed
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
90
jetpack_responsive_videos_remove_wrap_oembed
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/**
3 * Theme Tools: Responsive videos enhancements.
4 *
5 * @package automattic/jetpack
6 */
7
8use Automattic\Jetpack\Assets;
9
10/**
11 * Load the Responsive videos plugin
12 */
13function jetpack_responsive_videos_init() {
14
15    /* If the doesn't theme support 'jetpack-responsive-videos', don't continue */
16    if ( ! current_theme_supports( 'jetpack-responsive-videos' ) ) {
17        return;
18    }
19
20    /* If the theme does support 'jetpack-responsive-videos', wrap the videos */
21    add_filter( 'wp_video_shortcode', 'jetpack_responsive_videos_embed_html' );
22    add_filter( 'video_embed_html', 'jetpack_responsive_videos_embed_html' );
23
24    /* Only wrap oEmbeds if video */
25    add_filter( 'embed_oembed_html', 'jetpack_responsive_videos_maybe_wrap_oembed', 10, 2 );
26    add_filter( 'embed_handler_html', 'jetpack_responsive_videos_maybe_wrap_oembed', 10, 2 );
27
28    /* Wrap videos in Buddypress */
29    add_filter( 'bp_embed_oembed_html', 'jetpack_responsive_videos_embed_html' );
30
31    /* Wrap Slideshare shortcodes */
32    add_filter( 'jetpack_slideshare_shortcode', 'jetpack_responsive_videos_embed_html' );
33
34    // Remove the Jetpack Responsive video wrapper in embed blocks on sites that support core Responsive embeds.
35    if ( current_theme_supports( 'responsive-embeds' ) ) {
36        add_filter( 'render_block', 'jetpack_responsive_videos_remove_wrap_oembed', 10, 2 );
37    }
38}
39add_action( 'after_setup_theme', 'jetpack_responsive_videos_init', 99 );
40
41/**
42 * Adds a wrapper to videos and enqueue script
43 *
44 * @param string $html The video embed HTML.
45 * @return string
46 */
47function jetpack_responsive_videos_embed_html( $html ) {
48    if ( empty( $html ) || ! is_string( $html ) ) {
49        return $html;
50    }
51
52    // Short-circuit for AMP responses, since custom scripts are not allowed in AMP and videos are naturally responsive.
53    // @phan-suppress-next-line PhanUndeclaredClassMethod
54    if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
55        return $html;
56    }
57
58    // The customizer video widget wraps videos with a class of wp-video
59    // mejs as of 4.9 apparently resizes videos too which causes issues
60    // skip the video if it is wrapped in wp-video.
61    $video_widget_wrapper = 'class="wp-video"';
62
63    $mejs_wrapped = strpos( $html, $video_widget_wrapper );
64
65    // If this is a video widget wrapped by mejs, return the html.
66    if ( false !== $mejs_wrapped ) {
67        return $html;
68    }
69
70    Assets::register_script(
71        'jetpack-responsive-videos',
72        '../dist/responsive-videos/responsive-videos.js',
73        __FILE__,
74        array(
75            'in_footer'  => true,
76            'enqueue'    => true,
77            'textdomain' => 'jetpack-classic-theme-helper',
78            'css_path'   => '../dist/responsive-videos/responsive-videos.css',
79        )
80    );
81
82    return '<div class="jetpack-video-wrapper">' . $html . '</div>';
83}
84
85/**
86 * Check if oEmbed is a `$video_patterns` provider video before wrapping.
87 *
88 * @param mixed  $html The cached HTML result, stored in post meta.
89 * @param string $url  he attempted embed URL.
90 *
91 * @return string
92 */
93function jetpack_responsive_videos_maybe_wrap_oembed( $html, $url = null ) {
94    if ( empty( $html ) || ! is_string( $html ) || ! $url ) {
95        return $html;
96    }
97
98    // Short-circuit for AMP responses, since custom scripts are not allowed in AMP and videos are naturally responsive.
99    // @phan-suppress-next-line PhanUndeclaredClassMethod
100    if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
101        return $html;
102    }
103
104    $jetpack_video_wrapper = '<div class="jetpack-video-wrapper">';
105
106    $already_wrapped = strpos( $html, $jetpack_video_wrapper );
107
108    // If the oEmbed has already been wrapped, return the html.
109    if ( false !== $already_wrapped ) {
110        return $html;
111    }
112
113    /**
114     * The oEmbed video providers.
115     *
116     * An allowed list of oEmbed video provider Regex patterns to check against before wrapping the output.
117     *
118     * @module theme-tools
119     *
120     * @since 3.8.0
121     *
122     * @param array $video_patterns oEmbed video provider Regex patterns.
123     */
124    $video_patterns = apply_filters(
125        'jetpack_responsive_videos_oembed_videos',
126        array(
127            'https?://((m|www)\.)?youtube\.com/watch',
128            'https?://((m|www)\.)?youtube\.com/playlist',
129            'https?://youtu\.be/',
130            'https?://(.+\.)?vimeo\.com/',
131            'https?://(www\.)?dailymotion\.com/',
132            'https?://dai.ly/',
133            'https?://(www\.)?hulu\.com/watch/',
134            'https?://wordpress.tv/',
135            'https?://(www\.)?funnyordie\.com/videos/',
136            'https?://vine.co/v/',
137            'https?://(www\.)?collegehumor\.com/video/',
138            'https?://(www\.|embed\.)?ted\.com/talks/',
139        )
140    );
141
142    // Merge patterns to run in a single preg_match call.
143    $video_patterns = '(' . implode( '|', $video_patterns ) . ')';
144
145    $is_video = preg_match( $video_patterns, $url );
146
147    // If the oEmbed is a video, wrap it in the responsive wrapper.
148    if ( false === $already_wrapped && 1 === $is_video ) {
149        return jetpack_responsive_videos_embed_html( $html );
150    }
151
152    return $html;
153}
154
155/**
156 * Remove the Jetpack Responsive video wrapper in embed blocks.
157 *
158 * @since 7.0.0
159 *
160 * @param string $block_content The block content about to be appended.
161 * @param array  $block         The full block, including name and attributes.
162 *
163 * @return string $block_content String of rendered HTML.
164 */
165function jetpack_responsive_videos_remove_wrap_oembed( $block_content, $block ) {
166    if (
167        isset( $block['blockName'] )
168        && (
169            str_contains( $block['blockName'], 'core-embed' ) // pre-WP 5.6 embeds (multiple embed blocks starting with 'core-embed').
170            || 'core/embed' === $block['blockName'] // WP 5.6 embed block format (single embed block w/ block variations).
171        )
172    ) {
173        $block_content = preg_replace( '#<div class="jetpack-video-wrapper">(.*?)</div>#', '${1}', $block_content );
174    }
175
176    return $block_content;
177}