PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 7.5.1
Jetpack – WP Security, Backup, Speed, & Growth v7.5.1
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 All 500 releases
jetpack / modules / shortcodes / instagram.php
instagram.php
269 lines 12.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use Automattic\Jetpack\Assets;
4
5 /**
6 * Instagram Embeds.
7 *
8 * Full links: https://www.instagram.com/p/BnMOk_FFsxg/
9 * https://www.instagram.com/tv/BkQjCfsBIzi/
10 * [instagram url=https://www.instagram.com/p/BnMOk_FFsxg/]
11 * [instagram url=https://www.instagram.com/p/BZoonmAHvHf/ width=320]
12 * Embeds can be converted to a shortcode when the author does not have unfiltered_html caps:
13 * <blockquote class="instagram-media" data-instgrm-captioned data-instgrm-version="2" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);"><div style="padding:8px;"><div style=" background:#F8F8F8; line-height:0; margin-top:40px; padding-bottom:55%; padding-top:45%; text-align:center; width:100%;"><div style="position:relative;"><div style=" -webkit-animation:dkaXkpbBxI 1s ease-out infinite; animation:dkaXkpbBxI 1s ease-out infinite; background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAAGFBMVEUiIiI9PT0eHh4gIB4hIBkcHBwcHBwcHBydr+JQAAAACHRSTlMABA4YHyQsM5jtaMwAAADfSURBVDjL7ZVBEgMhCAQBAf//42xcNbpAqakcM0ftUmFAAIBE81IqBJdS3lS6zs3bIpB9WED3YYXFPmHRfT8sgyrCP1x8uEUxLMzNWElFOYCV6mHWWwMzdPEKHlhLw7NWJqkHc4uIZphavDzA2JPzUDsBZziNae2S6owH8xPmX8G7zzgKEOPUoYHvGz1TBCxMkd3kwNVbU0gKHkx+iZILf77IofhrY1nYFnB/lQPb79drWOyJVa/DAvg9B/rLB4cC+Nqgdz/TvBbBnr6GBReqn/nRmDgaQEej7WhonozjF+Y2I/fZou/qAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-44px; width:44px;"></div><span style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:12px; font-style:normal; font-weight:bold; position:relative; top:15px;">Loading</span></div></div><p style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin:8px 0 0 0; padding:0 4px; word-wrap:break-word;"> Balloons</p><p style=" line-height:32px; margin-bottom:0; margin-top:8px; padding:0; text-align:center;"> <a href="https://instagram.com/p/r9vfPrmjeB/" style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; text-decoration:none;" target="_top"> View on Instagram</a></p></div><style>@-webkit-keyframes"dkaXkpbBxI"{ 0%{opacity:0.5;} 50%{opacity:1;} 100%{opacity:0.5;} } @keyframes"dkaXkpbBxI"{ 0%{opacity:0.5;} 50%{opacity:1;} 100%{opacity:0.5;} }</style></blockquote>
14 * <script async defer src="https://platform.instagram.com/en_US/embeds.js"></script>
15 *
16 * @package Jetpack
17 */
18
19 /**
20 * Embed Reversal for Instagram
21 *
22 * Hooked to pre_kses, converts an embed code from Instagram.com to an oEmbeddable URL.
23 *
24 * @param string $content Post content.
25 *
26 * @return string The filtered or the original content.
27 **/
28 function jetpack_instagram_embed_reversal( $content ) {
29 if ( ! is_string( $content ) || false === stripos( $content, 'instagram.com' ) ) {
30 return $content;
31 }
32
33 /*
34 * Sample embed code:
35 * <blockquote class="instagram-media" data-instgrm-captioned data-instgrm-version="2" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);"><div style="padding:8px;"><div style=" background:#F8F8F8; line-height:0; margin-top:40px; padding-bottom:55%; padding-top:45%; text-align:center; width:100%;"><div style="position:relative;"><div style=" -webkit-animation:dkaXkpbBxI 1s ease-out infinite; animation:dkaXkpbBxI 1s ease-out infinite; background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAMAAAApWqozAAAAGFBMVEUiIiI9PT0eHh4gIB4hIBkcHBwcHBwcHBydr+JQAAAACHRSTlMABA4YHyQsM5jtaMwAAADfSURBVDjL7ZVBEgMhCAQBAf//42xcNbpAqakcM0ftUmFAAIBE81IqBJdS3lS6zs3bIpB9WED3YYXFPmHRfT8sgyrCP1x8uEUxLMzNWElFOYCV6mHWWwMzdPEKHlhLw7NWJqkHc4uIZphavDzA2JPzUDsBZziNae2S6owH8xPmX8G7zzgKEOPUoYHvGz1TBCxMkd3kwNVbU0gKHkx+iZILf77IofhrY1nYFnB/lQPb79drWOyJVa/DAvg9B/rLB4cC+Nqgdz/TvBbBnr6GBReqn/nRmDgaQEej7WhonozjF+Y2I/fZou/qAAAAAElFTkSuQmCC); display:block; height:44px; margin:0 auto -44px; position:relative; top:-44px; width:44px;"></div><span style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:12px; font-style:normal; font-weight:bold; position:relative; top:15px;">Loading</span></div></div><p style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin:8px 0 0 0; padding:0 4px; word-wrap:break-word;"> Balloons</p><p style=" line-height:32px; margin-bottom:0; margin-top:8px; padding:0; text-align:center;"> <a href="https://instagram.com/p/r9vfPrmjeB/" style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; text-decoration:none;" target="_top"> View on Instagram</a></p></div><style>@-webkit-keyframes"dkaXkpbBxI"{ 0%{opacity:0.5;} 50%{opacity:1;} 100%{opacity:0.5;} } @keyframes"dkaXkpbBxI"{ 0%{opacity:0.5;} 50%{opacity:1;} 100%{opacity:0.5;} }</style></blockquote>
36 * <script async defer src="https://platform.instagram.com/en_US/embeds.js"></script>
37 */
38
39 $regexes = array();
40
41 // new style js.
42 $regexes[] = '#<blockquote[^>]+?class="instagram-media"[^>].+?>(.+?)</blockquote><script[^>]+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"></script>#ix';
43
44 // Let's play nice with the visual editor too.
45 $regexes[] = '#&lt;blockquote(?:[^&]|&(?!gt;))+?class="instagram-media"(?:[^&]|&(?!gt;)).+?&gt;(.+?)&lt;/blockquote&gt;&lt;script(?:[^&]|&(?!gt;))+?src="(https?:)?//platform\.instagram\.com/(.+?)/embeds\.js"(?:[^&]|&(?!gt;))*+&gt;&lt;/script&gt;#ix';
46
47 // old style iframe.
48 $regexes[] = '#<iframe[^>]+?src="((?:https?:)?//(?:www\.)?instagram\.com/p/([^"\'/]++)[^"\']*?)"[^>]*+>\s*?</iframe>#i';
49
50 // Let's play nice with the visual editor too.
51 $regexes[] = '#&lt;iframe(?:[^&]|&(?!gt;))+?src="((?:https?:)?//(?:www\.)instagram\.com/p/([^"\'/]++)[^"\']*?)"(?:[^&]|&(?!gt;))*+&gt;\s*?&lt;/iframe&gt;#i';
52
53 foreach ( $regexes as $regex ) {
54 if ( ! preg_match_all( $regex, $content, $matches, PREG_SET_ORDER ) ) {
55 continue;
56 }
57
58 foreach ( $matches as $match ) {
59 if ( ! preg_match( '#(https?:)?//(?:www\.)?instagr(\.am|am\.com)/p/([^/]*)#i', $match[1], $url_matches ) ) {
60 continue;
61 }
62
63 // Since we support Instagram via oEmbed, we simply leave a link on a line by itself.
64 $replace_regex = sprintf( '#\s*%s\s*#', preg_quote( $match[0], '#' ) );
65 $url = esc_url( $url_matches[0] );
66
67 $content = preg_replace( $replace_regex, sprintf( "\n\n%s\n\n", $url ), $content );
68 /** This action is documented in modules/shortcodes/youtube.php */
69 do_action( 'jetpack_embed_to_shortcode', 'instagram', $url );
70 }
71 }
72
73 return $content;
74 }
75
76 add_filter( 'pre_kses', 'jetpack_instagram_embed_reversal' );
77
78 /**
79 * Instagram's custom Embed provider.
80 * We first remove 2 different embed providers, both registered by Core.
81 * - The first is the original provider,that only supports images.
82 * - The second is tne new provider that replaced the first one in Core when Core added support for videos. https://core.trac.wordpress.org/changeset/44486
83 *
84 * Once the core embed provider is removed (one or the other, depending on your version of Core), we declare our own.
85 */
86 wp_oembed_remove_provider( '#https?://(www\.)?instagr(\.am|am\.com)/p/.*#i' );
87 wp_oembed_remove_provider( '#https?://(www\.)?instagr(\.am|am\.com)/(p|tv)/.*#i' );
88 wp_embed_register_handler(
89 'jetpack_instagram',
90 '#http(s?)://(www\.)?instagr(\.am|am\.com)/(p|tv)/([^\/]*)#i',
91 'jetpack_instagram_handler'
92 );
93
94 /**
95 * Handle Instagram embeds (build embed from regex).
96 *
97 * @param array $matches Array of matches from the regex.
98 * @param array $atts The original unmodified attributes.
99 * @param string $url The original URL that was matched by the regex.
100 */
101 function jetpack_instagram_handler( $matches, $atts, $url ) {
102 global $content_width;
103
104 // keep a copy of the passed-in URL since it's modified below.
105 $passed_url = $url;
106
107 $max_width = 698;
108 $min_width = 320;
109
110 if ( is_feed() ) {
111 // Instagram offers direct links to images, but not to videos.
112 if ( 'p' === $matches[1] ) {
113 $media_url = sprintf( 'http://instagr.am/p/%1$s/media/?size=l', $matches[2] );
114 return sprintf(
115 '<a href="%1$s" title="%2$s" target="_blank"><img src="%3$s" alt="%4$s" /></a>',
116 esc_url( $url ),
117 esc_attr__( 'View on Instagram', 'jetpack' ),
118 esc_url( $media_url ),
119 esc_html__( 'Instagram Photo', 'jetpack' )
120 );
121 } elseif ( 'tv' === $matches[1] ) {
122 return sprintf(
123 '<a href="%1$s" title="%2$s" target="_blank">%3$s</a>',
124 esc_url( $url ),
125 esc_attr__( 'View on Instagram', 'jetpack' ),
126 esc_html__( 'Instagram Video', 'jetpack' )
127 );
128 }
129 }
130
131 $atts = shortcode_atts(
132 array(
133 'width' => isset( $content_width ) ? $content_width : $max_width,
134 'hidecaption' => false,
135 ),
136 $atts
137 );
138
139 $atts['width'] = absint( $atts['width'] );
140 if ( $atts['width'] > $max_width ) {
141 $atts['width'] = $max_width;
142 } elseif ( $atts['width'] < $min_width ) {
143 $atts['width'] = $min_width;
144 }
145
146 // remove the modal param from the URL.
147 $url = remove_query_arg( 'modal', $url );
148
149 // force .com instead of .am for https support.
150 $url = str_replace( 'instagr.am', 'instagram.com', $url );
151
152 // The oembed endpoint expects HTTP, but HTTP requests 301 to HTTPS.
153 $instagram_http_url = str_replace( 'https://', 'http://', $url );
154
155 $url_args = array(
156 'url' => $instagram_http_url,
157 'maxwidth' => $atts['width'],
158 'omitscript' => 1,
159 );
160
161 if ( $atts['hidecaption'] ) {
162 $url_args['hidecaption'] = 'true';
163 }
164
165 $url = esc_url_raw( add_query_arg( $url_args, 'https://api.instagram.com/oembed/' ) );
166
167 /**
168 * Filter Object Caching for response from Instagram.
169 *
170 * Allow enabling of object caching for the response sent by Instagram when querying for Instagram image HTML.
171 *
172 * @module shortcodes
173 *
174 * @since 3.3.0
175 *
176 * @param bool false Object caching is off by default.
177 * @param array $matches Array of Instagram URLs found in the post.
178 * @param array $atts Instagram Shortcode attributes.
179 * @param string $passed_url Instagram API URL.
180 */
181 $response_body_use_cache = apply_filters( 'instagram_cache_oembed_api_response_body', false, $matches, $atts, $passed_url );
182 $response_body = false;
183 if ( $response_body_use_cache ) {
184 $cache_key = 'oembed_response_body_' . md5( $url );
185 $response_body = wp_cache_get( $cache_key, 'instagram_embeds' );
186 }
187
188 if ( ! $response_body ) {
189 // Not using cache (default case) or cache miss.
190 $instagram_response = wp_remote_get( $url, array( 'redirection' => 0 ) );
191 if (
192 is_wp_error( $instagram_response )
193 || 200 !== $instagram_response['response']['code']
194 || empty( $instagram_response['body'] ) ) {
195 return '<!-- instagram error: invalid instagram resource -->';
196 }
197
198 $response_body = json_decode( $instagram_response['body'] );
199 if ( $response_body_use_cache ) {
200 // if caching it is short-lived since this is a "Cache-Control: no-cache" resource.
201 wp_cache_set(
202 $cache_key,
203 $response_body,
204 'instagram_embeds',
205 HOUR_IN_SECONDS + wp_rand( 0, HOUR_IN_SECONDS )
206 );
207 }
208 }
209
210 if ( ! empty( $response_body->html ) ) {
211 wp_enqueue_script(
212 'jetpack-instagram-embed',
213 Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/instagram.min.js', 'modules/shortcodes/js/instagram.js' ),
214 array( 'jquery' ),
215 JETPACK__VERSION,
216 true
217 );
218 return $response_body->html;
219 }
220
221 return '<!-- instagram error: no embed found -->';
222 }
223
224 /**
225 * Handle an alternate Instagram URL format, where the username is also part of the URL.
226 * We do not actually need that username for the embed.
227 */
228 wp_embed_register_handler(
229 'jetpack_instagram_alternate_format',
230 '#https?://(?:www\.)?instagr(?:\.am|am\.com)/(?:[^/]*)/(p|tv)/([^\/]*)#i',
231 'jetpack_instagram_alternate_format_handler'
232 );
233
234 /**
235 * Handle alternate Instagram embeds (build embed from regex).
236 *
237 * @param array $matches Array of matches from the regex.
238 * @param array $atts The original unmodified attributes.
239 * @param string $url The original URL that was matched by the regex.
240 */
241 function jetpack_instagram_alternate_format_handler( $matches, $atts, $url ) {
242 // Replace URL saved by original Instagram URL (no username).
243 $matches[0] = esc_url_raw(
244 sprintf(
245 'https://www.instagram.com/%1$s/%2$s',
246 $matches[1],
247 $matches[2]
248 )
249 );
250
251 return jetpack_instagram_handler( $matches, $atts, $url );
252 }
253
254 /**
255 * Display the Instagram shortcode.
256 *
257 * @param array $atts Shortcode attributes.
258 */
259 function jetpack_shortcode_instagram( $atts ) {
260 global $wp_embed;
261
262 if ( empty( $atts['url'] ) ) {
263 return '';
264 }
265
266 return $wp_embed->shortcode( $atts, $atts['url'] );
267 }
268 add_shortcode( 'instagram', 'jetpack_shortcode_instagram' );
269