PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 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 All 508 releases
← All changes | jetpack_vendor/automattic/jetpack-videopress/src/class-data.php +252 -70 12.3.2 → 16.3 View file →
@@ -50,8 +50,52 @@
50 50 return boolval( get_option( 'videopress_private_enabled_for_site', false ) );
51 51 }
52 52
53 53 /**
54 + * Gets whether auto-generated subtitles are disabled for the site.
55 + *
56 + * Subtitles are generated by default, so this opt-out option defaults to false.
57 + *
58 + * @return boolean If auto-generated subtitles should be skipped for new videos.
59 + */
60 + public static function get_videopress_auto_subtitles_disabled() {
61 + return boolval( get_option( 'videopress_auto_subtitles_disabled', false ) );
62 + }
63 +
64 + /**
65 + * Gets whether player preloading is turned off for every embed on the site.
66 + *
67 + * Preloading is on by default, so this opt-out option defaults to false.
68 + *
69 + * @return boolean If embeds should wait for playback before fetching video data and player assets.
70 + */
71 + public static function get_videopress_player_preload_disabled() {
72 + return boolval( get_option( 'videopress_player_preload_disabled', false ) );
73 + }
74 +
75 + /**
76 + * Gets whether embeds render an inline player instead of one iframe per video.
77 + *
78 + * Iframes are the default, so this opt-in option defaults to false.
79 + *
80 + * @return boolean If embeds should mount players in the page from one shared player script.
81 + */
82 + public static function get_videopress_inline_player_enabled() {
83 + return boolval( get_option( 'videopress_inline_player_enabled', false ) );
84 + }
85 +
86 + /**
87 + * Gets whether the share menu is turned off for every video on the site.
88 + *
89 + * Sharing follows each video's own setting by default, so this opt-out option defaults to false.
90 + *
91 + * @return boolean If no video may display the share menu, whatever its own setting.
92 + */
93 + public static function get_videopress_share_menu_disabled() {
94 + return boolval( get_option( 'videopress_share_menu_disabled', false ) );
95 + }
96 +
97 + /**
54 98 * Gets the VideoPress Settings.
55 99 *
56 100 * @return array The settings as an associative array.
57 101 */
@@ -68,8 +112,12 @@
68 112 }
69 113
70 114 return array(
71 115 'videopress_videos_private_for_site' => self::get_videopress_videos_private_for_site(),
116 + 'videopress_auto_subtitles_disabled' => self::get_videopress_auto_subtitles_disabled(),
117 + 'videopress_player_preload_disabled' => self::get_videopress_player_preload_disabled(),
118 + 'videopress_inline_player_enabled' => self::get_videopress_inline_player_enabled(),
119 + 'videopress_share_menu_disabled' => self::get_videopress_share_menu_disabled(),
72 120 'site_is_private' => $site_is_private,
73 121 'site_type' => $site_type,
74 122 );
75 123 }
@@ -93,18 +141,18 @@
93 141 ),
94 142 );
95 143
96 144 $args = array(
97 - 'order' => $video_data['query']['order'],
98 - 'orderby' => $video_data['query']['orderBy'],
99 - 'per_page' => $video_data['query']['itemsPerPage'],
100 - 'page' => $video_data['query']['page'],
101 - 'media_type' => 'video',
145 + 'order' => $video_data['query']['order'],
146 + 'orderby' => $video_data['query']['orderBy'],
147 + 'per_page' => $video_data['query']['itemsPerPage'],
148 + 'page' => $video_data['query']['page'],
102 149 );
103 150
104 151 if ( $is_videopress ) {
105 152 $args['mime_type'] = 'video/videopress';
106 153 } else {
154 + $args['media_type'] = 'video';
107 155 $args['no_videopress'] = true;
108 156 }
109 157
110 158 // Do an internal request for the media list
@@ -132,8 +180,128 @@
132 180 return $video_data;
133 181 }
134 182
135 183 /**
184 + * Gets the site's newest VideoPress videos as playlist entries, newest first.
185 + *
186 + * Goes through the media REST endpoint rather than a direct WP_Query so the
187 + * package's rest_attachment_query filter resolves VideoPress membership on
188 + * every host: by mime off WordPress.com Simple, from wpcom's videos table on it.
189 + * The editor's block preview sends the same request.
190 + *
191 + * @param int $count How many videos to fetch.
192 + *
193 + * @return array Entries with guid, durationMs and height keys.
194 + */
195 + public static function get_latest_videopress_playlist_entries( $count ) {
196 + $count = max( 1, (int) $count );
197 + $args = array(
198 + 'per_page' => $count,
199 + 'orderby' => 'date',
200 + 'order' => 'desc',
201 + 'videopress_has_guid' => 1,
202 + );
203 +
204 + // Attachments keep their original mime there, so narrow to videos before the ID-set constraint.
205 + if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
206 + $args['videopress_only_videos'] = 1;
207 + }
208 +
209 + $request = new WP_REST_Request( 'GET', '/wp/v2/media' );
210 + $request->set_query_params( $args );
211 + $response = rest_do_request( $request );
212 +
213 + // WordPress.com Simple registers the wp/v2 routes only for REST requests, so on a
214 + // page render the media endpoint does not exist: query the attachments directly.
215 + if ( $response->is_error() ) {
216 + return self::query_latest_videopress_playlist_entries( $count );
217 + }
218 +
219 + $entries = array();
220 + foreach ( (array) $response->get_data() as $item ) {
221 + $item = (array) $item;
222 + $guid = $item['jetpack_videopress_guid'] ?? '';
223 +
224 + // The REST field is empty on a site without a connection; the attachment meta still knows.
225 + if ( ( ! is_string( $guid ) || '' === $guid ) && ! empty( $item['id'] ) ) {
226 + $guid = get_post_meta( (int) $item['id'], 'videopress_guid', true );
227 + }
228 +
229 + $details = isset( $item['media_details'] ) ? (array) $item['media_details'] : array();
230 + $videopress = isset( $details['videopress'] ) ? (array) $details['videopress'] : array();
231 + $entry = self::playlist_entry( $guid, $videopress['duration'] ?? 0, $details['height'] ?? $videopress['height'] ?? 0 );
232 + if ( $entry ) {
233 + $entries[] = $entry;
234 + }
235 + }
236 +
237 + return $entries;
238 + }
239 +
240 + /**
241 + * The newest VideoPress videos straight from the posts table, for hosts where the
242 + * media endpoint is unavailable. Mirrors what the endpoint does with the package's
243 + * query filter: by mime off WordPress.com Simple, from wpcom's videos table on it.
244 + *
245 + * @param int $count How many videos to fetch.
246 + *
247 + * @return array Entries with guid, durationMs and height keys.
248 + */
249 + private static function query_latest_videopress_playlist_entries( $count ) {
250 + $is_wpcom = defined( 'IS_WPCOM' ) && IS_WPCOM;
251 + $posts = get_posts(
252 + array(
253 + 'post_type' => 'attachment',
254 + 'post_status' => 'inherit',
255 + 'post_mime_type' => $is_wpcom ? 'video' : 'video/videopress',
256 + 'orderby' => 'date',
257 + 'order' => 'DESC',
258 + 'posts_per_page' => $count,
259 + )
260 + );
261 +
262 + $entries = array();
263 + foreach ( $posts as $post ) {
264 + $guid = get_post_meta( $post->ID, 'videopress_guid', true );
265 + if ( ( ! is_string( $guid ) || '' === $guid ) && $is_wpcom && function_exists( 'video_get_info_by_blogpostid' ) ) {
266 + $info = video_get_info_by_blogpostid( get_current_blog_id(), $post->ID );
267 + $guid = is_object( $info ) && ! empty( $info->guid ) ? (string) $info->guid : '';
268 + }
269 +
270 + $meta = wp_get_attachment_metadata( $post->ID );
271 + $meta = is_array( $meta ) ? $meta : array();
272 + $videopress = isset( $meta['videopress'] ) ? (array) $meta['videopress'] : array();
273 + $duration = $videopress['duration'] ?? ( isset( $meta['length'] ) && is_numeric( $meta['length'] ) ? (int) $meta['length'] * 1000 : 0 );
274 + $entry = self::playlist_entry( $guid, $duration, $meta['height'] ?? $videopress['height'] ?? 0 );
275 + if ( $entry ) {
276 + $entries[] = $entry;
277 + }
278 + }
279 +
280 + return $entries;
281 + }
282 +
283 + /**
284 + * One playlist entry, or null when the GUID is unusable.
285 + *
286 + * @param mixed $guid VideoPress GUID.
287 + * @param mixed $duration Duration in ms.
288 + * @param mixed $height Height in px.
289 + *
290 + * @return array|null
291 + */
292 + private static function playlist_entry( $guid, $duration, $height ) {
293 + if ( ! is_string( $guid ) || ! preg_match( '/^[a-zA-Z0-9]{8}$/', $guid ) ) {
294 + return null;
295 + }
296 + return array(
297 + 'guid' => $guid,
298 + 'durationMs' => is_numeric( $duration ) ? max( 0, (int) $duration ) : 0,
299 + 'height' => is_numeric( $height ) ? max( 0, (int) $height ) : 0,
300 + );
301 + }
302 +
303 + /**
136 304 * Gets the user data
137 305 *
138 306 * @return array
139 307 */
@@ -291,11 +459,11 @@
291 459 $title = $jetpack_videopress['title'];
292 460 $description = $jetpack_videopress['description'];
293 461 $caption = $jetpack_videopress['caption'];
294 462
295 - $width = isset( $media_details['width'] ) ? $media_details['width'] : null;
296 - $height = isset( $media_details['height'] ) ? $media_details['height'] : null;
297 - $duration = isset( $media_details['length'] ) ? $media_details['length'] : null;
463 + $width = $media_details['width'] ?? null;
464 + $height = $media_details['height'] ?? null;
465 + $duration = $media_details['length'] ?? null;
298 466
299 467 return array(
300 468 'id' => $id,
301 469 'title' => $title,
@@ -314,70 +482,9 @@
314 482 );
315 483
316 484 // Tweak VideoPress videos data.
317 485 $videos = array_map(
318 - function ( $video ) {
319 - $video = (array) $video;
320 - $id = $video['id'];
321 - $guid = $video['jetpack_videopress_guid'];
322 - $media_details = (array) $video['media_details'];
323 - $jetpack_videopress = (array) $video['jetpack_videopress'];
324 -
325 - $videopress_media_details = $media_details['videopress'];
326 - $width = $media_details['width'];
327 - $height = $media_details['height'];
328 -
329 - $title = $jetpack_videopress['title'];
330 - $description = $jetpack_videopress['description'];
331 - $caption = $jetpack_videopress['caption'];
332 - $rating = $jetpack_videopress['rating'];
333 - $allow_download = $jetpack_videopress['allow_download'];
334 - $display_embed = $jetpack_videopress['display_embed'];
335 - $privacy_setting = $jetpack_videopress['privacy_setting'];
336 - $needs_playback_token = $jetpack_videopress['needs_playback_token'];
337 - $is_private = $jetpack_videopress['is_private'];
338 -
339 - $original = $videopress_media_details['original'];
340 - $poster = ( ! $needs_playback_token ) ? $videopress_media_details['poster'] : null;
341 - $upload_date = $videopress_media_details['upload_date'];
342 - $duration = $videopress_media_details['duration'];
343 - $file_url_base = $videopress_media_details['file_url_base'];
344 - $finished = $videopress_media_details['finished'];
345 - $files = $videopress_media_details['files'];
346 - $filename = basename( $original );
347 -
348 - if ( isset( $files['dvd']['original_img'] ) && $privacy_setting !== 1 ) {
349 - $thumbnail = $file_url_base['https'] . $files['dvd']['original_img'];
350 - } else {
351 - $thumbnail = null;
352 - }
353 -
354 - return array(
355 - 'id' => $id,
356 - 'guid' => $guid,
357 - 'title' => $title,
358 - 'description' => $description,
359 - 'caption' => $caption,
360 - 'url' => $original,
361 - 'uploadDate' => $upload_date,
362 - 'duration' => $duration,
363 - 'isPrivate' => $is_private,
364 - 'posterImage' => $poster,
365 - 'allowDownload' => $allow_download,
366 - 'displayEmbed' => $display_embed,
367 - 'rating' => $rating,
368 - 'privacySetting' => $privacy_setting,
369 - 'needsPlaybackToken' => $needs_playback_token,
370 - 'width' => $width,
371 - 'height' => $height,
372 - 'poster' => array(
373 - 'src' => $poster,
374 - ),
375 - 'thumbnail' => $thumbnail,
376 - 'finished' => $finished,
377 - 'filename' => $filename,
378 - );
379 - },
486 + array( __CLASS__, 'prepare_videopress_video_data' ),
380 487 $videopress_data['videos']
381 488 );
382 489
383 490 $site_settings = self::get_videopress_settings();
@@ -424,6 +531,81 @@
424 531 return array_merge_recursive( $initial_state, self::get_connected_initial_state() );
425 532 }
426 533
427 534 return $initial_state;
535 + }
536 +
537 + /**
538 + * Maps a single VideoPress video, as returned by the media REST endpoint, to
539 + * the shape consumed by the VideoPress dashboard app.
540 + *
541 + * Videos that are still processing (or otherwise have partial metadata) come
542 + * back without `videopress`, `width` or `height` in their media_details, so
543 + * every nested access is coalesced to avoid undefined-key and offset-on-null
544 + * warnings.
545 + *
546 + * @param array|object $video A single video entry from the media REST endpoint.
547 + * @return array The video data formatted for the dashboard app.
548 + */
549 + private static function prepare_videopress_video_data( $video ) {
550 + $video = (array) $video;
551 + $id = $video['id'];
552 + $guid = $video['jetpack_videopress_guid'];
553 + $media_details = (array) $video['media_details'];
554 + $jetpack_videopress = (array) $video['jetpack_videopress'];
555 +
556 + $videopress_media_details = $media_details['videopress'] ?? array();
557 + $width = $media_details['width'] ?? null;
558 + $height = $media_details['height'] ?? null;
559 +
560 + $title = $jetpack_videopress['title'];
561 + $description = $jetpack_videopress['description'];
562 + $caption = $jetpack_videopress['caption'];
563 + $rating = $jetpack_videopress['rating'];
564 + $allow_download = $jetpack_videopress['allow_download'];
565 + $display_embed = $jetpack_videopress['display_embed'];
566 + $privacy_setting = $jetpack_videopress['privacy_setting'];
567 + $needs_playback_token = $jetpack_videopress['needs_playback_token'];
568 + $is_private = $jetpack_videopress['is_private'];
569 +
570 + $original = $videopress_media_details['original'] ?? null;
571 + $poster = ( ! $needs_playback_token ) ? ( $videopress_media_details['poster'] ?? null ) : null;
572 + $upload_date = $videopress_media_details['upload_date'] ?? null;
573 + $duration = $videopress_media_details['duration'] ?? null;
574 + $file_url_base = $videopress_media_details['file_url_base'] ?? null;
575 + $finished = $videopress_media_details['finished'] ?? null;
576 + $files = $videopress_media_details['files'] ?? null;
577 + $filename = $original !== null ? basename( $original ) : null;
578 +
579 + if ( isset( $files['dvd']['original_img'] ) && isset( $file_url_base['https'] ) && $privacy_setting !== 1 ) {
580 + $thumbnail = $file_url_base['https'] . $files['dvd']['original_img'];
581 + } else {
582 + $thumbnail = null;
583 + }
584 +
585 + return array(
586 + 'id' => $id,
587 + 'guid' => $guid,
588 + 'title' => $title,
589 + 'description' => $description,
590 + 'caption' => $caption,
591 + 'url' => $original,
592 + 'uploadDate' => $upload_date,
593 + 'duration' => $duration,
594 + 'isPrivate' => $is_private,
595 + 'posterImage' => $poster,
596 + 'allowDownload' => $allow_download,
597 + 'displayEmbed' => $display_embed,
598 + 'rating' => $rating,
599 + 'privacySetting' => $privacy_setting,
600 + 'needsPlaybackToken' => $needs_playback_token,
601 + 'width' => $width,
602 + 'height' => $height,
603 + 'poster' => array(
604 + 'src' => $poster,
605 + ),
606 + 'thumbnail' => $thumbnail,
607 + 'finished' => $finished,
608 + 'filename' => $filename,
609 + );
428 610 }
429 611 }