Completed
Push — add/e2e-mailchimp-block-test ( e217db...6066d0 )
by Yaroslav
98:30 queued 85:55
created

utility-functions.php ➔ videopress_merge_file_status()   B

Complexity

Conditions 8
Paths 64

Size

Total Lines 32

Duplication

Lines 12
Ratio 37.5 %

Importance

Changes 0
Metric Value
cc 8
nc 64
nop 2
dl 12
loc 32
rs 8.1635
c 0
b 0
f 0
1
<?php
2
3
use Automattic\Jetpack\Connection\Client;
4
5
/**
6
 * We won't have any videos less than sixty pixels wide. That would be silly.
7
 */
8
defined( 'VIDEOPRESS_MIN_WIDTH' ) or define( 'VIDEOPRESS_MIN_WIDTH', 60 );
9
10
/**
11
 * Validate user-supplied guid values against expected inputs
12
 *
13
 * @since 1.1
14
 * @param string $guid video identifier
15
 * @return bool true if passes validation test
16
 */
17
function videopress_is_valid_guid( $guid ) {
18
	if ( ! empty( $guid ) && is_string( $guid ) && strlen( $guid ) === 8 && ctype_alnum( $guid ) ) {
19
		return true;
20
	}
21
	return false;
22
}
23
24
/**
25
 * Get details about a specific video by GUID:
26
 *
27
 * @param $guid string
28
 * @return object
29
 */
30
function videopress_get_video_details( $guid ) {
31
	if ( ! videopress_is_valid_guid( $guid ) ) {
32
		return new WP_Error( 'bad-guid-format', __( 'Invalid Video GUID!', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'bad-guid-format'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
33
	}
34
35
	$version   = '1.1';
36
	$endpoint  = sprintf( '/videos/%1$s', $guid );
37
	$query_url = sprintf(
38
		'https://public-api.wordpress.com/rest/v%1$s%2$s',
39
		$version,
40
		$endpoint
41
	);
42
43
	// Look for data in our transient. If nothing, let's make a new query.
44
	$data_from_cache = get_transient( 'jetpack_videopress_' . $guid );
45
	if ( false === $data_from_cache ) {
46
		$response = wp_remote_get( esc_url_raw( $query_url ) );
47
		$data     = json_decode( wp_remote_retrieve_body( $response ) );
48
49
		// Cache the response for an hour.
50
		set_transient( 'jetpack_videopress_' . $guid, $data, HOUR_IN_SECONDS );
51
	} else {
52
		$data = $data_from_cache;
53
	}
54
55
	/**
56
	 * Allow functions to modify fetched video details.
57
	 *
58
	 * This filter allows third-party code to modify the return data
59
	 * about a given video.  It may involve swapping some data out or
60
	 * adding new parameters.
61
	 *
62
	 * @since 4.0.0
63
	 *
64
	 * @param object $data The data returned by the WPCOM API. See: https://developer.wordpress.com/docs/api/1.1/get/videos/%24guid/
65
	 * @param string $guid The GUID of the VideoPress video in question.
66
	 */
67
	return apply_filters( 'videopress_get_video_details', $data, $guid );
68
}
69
70
71
/**
72
 * Get an attachment ID given a URL.
73
 *
74
 * Modified from http://wpscholar.com/blog/get-attachment-id-from-wp-image-url/
75
 *
76
 * @todo: Add some caching in here.
77
 *
78
 * @param string $url
79
 *
80
 * @return int|bool Attachment ID on success, false on failure
81
 */
82
function videopress_get_attachment_id_by_url( $url ) {
83
	$wp_upload_dir = wp_upload_dir();
84
	// Strip out protocols, so it doesn't fail because searching for http: in https: dir.
85
	$dir = set_url_scheme( trailingslashit( $wp_upload_dir['baseurl'] ), 'relative' );
86
87
	// Is URL in uploads directory?
88
	if ( false !== strpos( $url, $dir ) ) {
89
90
		$file = basename( $url );
91
92
		$query_args = array(
93
			'post_type'   => 'attachment',
94
			'post_status' => 'inherit',
95
			'fields'      => 'ids',
96
			'meta_query'  => array(
97
				array(
98
					'key'     => '_wp_attachment_metadata',
99
					'compare' => 'LIKE',
100
					'value'   => $file,
101
				),
102
			),
103
		);
104
105
		$query = new WP_Query( $query_args );
106
107
		if ( $query->have_posts() ) {
108
			foreach ( $query->posts as $attachment_id ) {
109
				$meta          = wp_get_attachment_metadata( $attachment_id );
110
				$original_file = basename( $meta['file'] );
111
				$cropped_files = wp_list_pluck( $meta['sizes'], 'file' );
112
113
				if ( $original_file === $file || in_array( $file, $cropped_files ) ) {
114
					return (int) $attachment_id;
115
				}
116
			}
117
		}
118
	}
119
120
	return false;
121
}
122
123
/**
124
 * Similar to `media_sideload_image` -- but returns an ID.
125
 *
126
 * @param $url
127
 * @param $attachment_id
128
 *
129
 * @return int|mixed|object|WP_Error
130
 */
131
function videopress_download_poster_image( $url, $attachment_id ) {
132
	// Set variables for storage, fix file filename for query strings.
133
	preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $url, $matches );
134
	if ( ! $matches ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $matches of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
135
		return new WP_Error( 'image_sideload_failed', __( 'Invalid image URL', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'image_sideload_failed'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
136
	}
137
138
	$file_array             = array();
139
	$file_array['name']     = basename( $matches[0] );
140
	$file_array['tmp_name'] = download_url( $url );
141
142
	// If error storing temporarily, return the error.
143
	if ( is_wp_error( $file_array['tmp_name'] ) ) {
144
		return $file_array['tmp_name'];
145
	}
146
147
	// Do the validation and storage stuff.
148
	$thumbnail_id = media_handle_sideload( $file_array, $attachment_id, null );
149
150
	// Flag it as poster image, so we can exclude it from display.
151
	update_post_meta( $thumbnail_id, 'videopress_poster_image', 1 );
152
153
	return $thumbnail_id;
154
}
155
156
/**
157
 * Creates a local media library item of a remote VideoPress video.
158
 *
159
 * @param $guid
160
 * @param int  $parent_id
161
 *
162
 * @return int|object
163
 */
164
function create_local_media_library_for_videopress_guid( $guid, $parent_id = 0 ) {
165
	$vp_data = videopress_get_video_details( $guid );
166
	if ( ! $vp_data || is_wp_error( $vp_data ) ) {
167
		return $vp_data;
168
	}
169
170
	$args = array(
171
		'post_date'      => $vp_data->upload_date,
172
		'post_title'     => wp_kses( $vp_data->title, array() ),
173
		'post_content'   => wp_kses( $vp_data->description, array() ),
174
		'post_mime_type' => 'video/videopress',
175
		'guid'           => sprintf( 'https://videopress.com/v/%s', $guid ),
176
	);
177
178
	$attachment_id = wp_insert_attachment( $args, null, $parent_id );
179
180
	if ( ! is_wp_error( $attachment_id ) ) {
181
		update_post_meta( $attachment_id, 'videopress_guid', $guid );
182
		wp_update_attachment_metadata(
183
			$attachment_id,
184
			array(
185
				'width'  => $vp_data->width,
186
				'height' => $vp_data->height,
187
			)
188
		);
189
190
		$thumbnail_id = videopress_download_poster_image( $vp_data->poster, $attachment_id );
191
		update_post_meta( $attachment_id, '_thumbnail_id', $thumbnail_id );
192
	}
193
194
	return $attachment_id;
195
}
196
197
/**
198
 * Helper that will look for VideoPress media items that are more than 30 minutes old,
199
 * that have not had anything attached to them by a wpcom upload and deletes the ghost
200
 * attachment.
201
 *
202
 * These happen primarily because of failed upload attempts.
203
 *
204
 * @return int The number of items that were cleaned up.
205
 */
206
function videopress_cleanup_media_library() {
207
208
	// Disable this job for now.
209
	return 0;
210
	$query_args = array(
0 ignored issues
show
Unused Code introduced by
$query_args = array('pos...', 'value' => 'new'))); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
211
		'post_type'      => 'attachment',
212
		'post_status'    => 'inherit',
213
		'post_mime_type' => 'video/videopress',
214
		'meta_query'     => array(
215
			array(
216
				'key'   => 'videopress_status',
217
				'value' => 'new',
218
			),
219
		),
220
	);
221
222
	$query = new WP_Query( $query_args );
223
224
	$cleaned = 0;
225
226
	$now = current_time( 'timestamp' );
227
228
	if ( $query->have_posts() ) {
229
		foreach ( $query->posts as $post ) {
230
			$post_time = strtotime( $post->post_date_gmt );
231
232
			// If the post is older than 30 minutes, it is safe to delete it.
233
			if ( $now - $post_time > MINUTE_IN_SECONDS * 30 ) {
234
				// Force delete the attachment, because we don't want it appearing in the trash.
235
				wp_delete_attachment( $post->ID, true );
236
237
				$cleaned++;
238
			}
239
		}
240
	}
241
242
	return $cleaned;
243
}
244
245
/**
246
 * Return an absolute URI for a given filename and guid on the CDN.
247
 * No check is performed to ensure the guid exists or the file is present. Simple centralized string builder.
248
 *
249
 * @param string $guid     VideoPress identifier
250
 * @param string $filename name of file associated with the guid (video file name or thumbnail file name)
251
 *
252
 * @return string Absolute URL of VideoPress file for the given guid.
253
 */
254
function videopress_cdn_file_url( $guid, $filename ) {
255
	return "https://videos.files.wordpress.com/{$guid}/{$filename}";
256
}
257
258
/**
259
 * Get an array of the transcoding status for the given video post.
260
 *
261
 * @since 4.4
262
 * @param int $post_id
263
 * @return array|bool Returns an array of statuses if this is a VideoPress post, otherwise it returns false.
264
 */
265
function videopress_get_transcoding_status( $post_id ) {
266
	$meta = wp_get_attachment_metadata( $post_id );
267
268
	// If this has not been processed by videopress, we can skip the rest.
269
	if ( ! $meta || ! isset( $meta['file_statuses'] ) ) {
270
		return false;
271
	}
272
273
	$info = (object) $meta['file_statuses'];
274
275
	$status = array(
276
		'std_mp4' => isset( $info->mp4 ) ? $info->mp4 : null,
277
		'std_ogg' => isset( $info->ogg ) ? $info->ogg : null,
278
		'dvd_mp4' => isset( $info->dvd ) ? $info->dvd : null,
279
		'hd_mp4'  => isset( $info->hd ) ? $info->hd : null,
280
	);
281
282
	return $status;
283
}
284
285
/**
286
 * Get the direct url to the video.
287
 *
288
 * @since 4.4
289
 * @param string $guid
290
 * @return string
291
 */
292
function videopress_build_url( $guid ) {
293
294
	// No guid, no videopress url.
295
	if ( ! $guid ) {
296
		return '';
297
	}
298
299
	return 'https://videopress.com/v/' . $guid;
300
}
301
302
/**
303
 * Create an empty videopress media item that will be filled out later by an xmlrpc
304
 * callback from the VideoPress servers.
305
 *
306
 * @since 4.4
307
 * @param string $title
308
 * @return int|WP_Error
309
 */
310
function videopress_create_new_media_item( $title, $guid = null ) {
311
	$post = array(
312
		'post_type'      => 'attachment',
313
		'post_mime_type' => 'video/videopress',
314
		'post_title'     => $title,
315
		'post_content'   => '',
316
		'guid'           => videopress_build_url( $guid ),
317
	);
318
319
	$media_id = wp_insert_post( $post );
320
321
	add_post_meta( $media_id, 'videopress_status', 'initiated' );
322
323
	add_post_meta( $media_id, 'videopress_guid', $guid );
324
325
	return $media_id;
326
}
327
328
329
/**
330
 * @param array $current_status
331
 * @param array $new_meta
332
 * @return array
333
 */
334
function videopress_merge_file_status( $current_status, $new_meta ) {
335
	$new_statuses = array();
336
337 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['hd'] ) ) {
338
		$new_statuses['hd'] = $new_meta['videopress']['files_status']['hd'];
339
	}
340
341 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['dvd'] ) ) {
342
		$new_statuses['dvd'] = $new_meta['videopress']['files_status']['dvd'];
343
	}
344
345 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['std']['mp4'] ) ) {
346
		$new_statuses['mp4'] = $new_meta['videopress']['files_status']['std']['mp4'];
347
	}
348
349 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['std']['ogg'] ) ) {
350
		$new_statuses['ogg'] = $new_meta['videopress']['files_status']['std']['ogg'];
351
	}
352
353
	foreach ( $new_statuses as $format => $status ) {
354
		if ( ! isset( $current_status[ $format ] ) ) {
355
			$current_status[ $format ] = $status;
356
			continue;
357
		}
358
359
		if ( $current_status[ $format ] !== 'DONE' ) {
360
			$current_status[ $format ] = $status;
361
		}
362
	}
363
364
	return $current_status;
365
}
366
367
/**
368
 * Check to see if a video has completed processing.
369
 *
370
 * @since 4.4
371
 * @param int $post_id
372
 * @return bool
373
 */
374
function videopress_is_finished_processing( $post_id ) {
375
	$post = get_post( $post_id );
376
377
	if ( is_wp_error( $post ) ) {
378
		return false;
379
	}
380
381
	$meta = wp_get_attachment_metadata( $post->ID );
382
383
	if ( ! isset( $meta['file_statuses'] ) || ! is_array( $meta['file_statuses'] ) ) {
384
		return false;
385
	}
386
387
	$check_statuses = array( 'hd', 'dvd', 'mp4', 'ogg' );
388
389
	foreach ( $check_statuses as $status ) {
390
		if ( ! isset( $meta['file_statuses'][ $status ] ) || $meta['file_statuses'][ $status ] != 'DONE' ) {
391
			return false;
392
		}
393
	}
394
395
	return true;
396
}
397
398
399
/**
400
 * Update the meta information  status for the given video post.
401
 *
402
 * @since 4.4
403
 * @param int $post_id
404
 * @return bool
405
 */
406
function videopress_update_meta_data( $post_id ) {
407
408
	$meta = wp_get_attachment_metadata( $post_id );
409
410
	// If this has not been processed by VideoPress, we can skip the rest.
411
	if ( ! $meta || ! isset( $meta['videopress'] ) ) {
412
		return false;
413
	}
414
415
	$info = (object) $meta['videopress'];
416
417
	$args = array(
418
		// 'sslverify' => false,
419
	);
420
421
	$result = wp_remote_get( videopress_make_video_get_path( $info->guid ), $args );
422
423
	if ( is_wp_error( $result ) ) {
424
		return false;
425
	}
426
427
	$response = json_decode( $result['body'], true );
428
429
	// Update the attachment metadata.
430
	$meta['videopress'] = $response;
431
432
	wp_update_attachment_metadata( $post_id, $meta );
433
434
	return true;
435
}
436
437
/**
438
 * Check to see if this is a VideoPress post that hasn't had a guid set yet.
439
 *
440
 * @param int $post_id
441
 * @return bool
442
 */
443
function videopress_is_attachment_without_guid( $post_id ) {
444
	$post = get_post( $post_id );
445
446
	if ( is_wp_error( $post ) ) {
447
		return false;
448
	}
449
450
	if ( $post->post_mime_type !== 'video/videopress' ) {
451
		return false;
452
	}
453
454
	$videopress_guid = get_post_meta( $post_id, 'videopress_guid', true );
455
456
	if ( $videopress_guid ) {
457
		return false;
458
	}
459
460
	return true;
461
}
462
463
/**
464
 * Check to see if this is a VideoPress attachment.
465
 *
466
 * @param int $post_id
467
 * @return bool
468
 */
469
function is_videopress_attachment( $post_id ) {
470
	$post = get_post( $post_id );
471
472
	if ( is_wp_error( $post ) ) {
473
		return false;
474
	}
475
476
	if ( $post->post_mime_type !== 'video/videopress' ) {
477
		return false;
478
	}
479
480
	return true;
481
}
482
483
/**
484
 * Get the video update path
485
 *
486
 * @since 4.4
487
 * @param string $guid
488
 * @return string
489
 */
490
function videopress_make_video_get_path( $guid ) {
491
	return sprintf(
492
		'%s://%s/rest/v%s/videos/%s',
493
		'https',
494
		JETPACK__WPCOM_JSON_API_HOST,
495
		Client::WPCOM_JSON_API_VERSION,
496
		$guid
497
	);
498
}
499
500
/**
501
 * Get the upload api path.
502
 *
503
 * @since 4.4
504
 * @param int $blog_id The id of the blog we're uploading to.
505
 * @return string
506
 */
507
function videopress_make_media_upload_path( $blog_id ) {
508
	return sprintf(
509
		'https://public-api.wordpress.com/rest/v1.1/sites/%s/media/new',
510
		$blog_id
511
	);
512
}
513
514
/**
515
 * This is a mock of the internal VideoPress method, which is meant to duplicate the functionality
516
 * of the WPCOM API, so that the Jetpack REST API returns the same data with no modifications.
517
 *
518
 * @param int $blog_id Blog ID.
519
 * @param int $post_id Post ID.
520
 * @return bool|stdClass
521
 */
522
function video_get_info_by_blogpostid( $blog_id, $post_id ) {
523
	$post = get_post( $post_id );
524
525
	$video_info                  = new stdClass();
526
	$video_info->post_id         = $post_id;
527
	$video_info->blog_id         = $blog_id;
528
	$video_info->guid            = null;
529
	$video_info->finish_date_gmt = '0000-00-00 00:00:00';
530
531
	if ( is_wp_error( $post ) ) {
532
		return $video_info;
533
	}
534
535
	if ( 'video/videopress' !== $post->post_mime_type ) {
536
		return $video_info;
537
	}
538
539
	// Since this is a VideoPress post, lt's fill out the rest of the object.
540
	$video_info->guid = get_post_meta( $post_id, 'videopress_guid', true );
541
542
	if ( videopress_is_finished_processing( $post_id ) ) {
543
		$video_info->finish_date_gmt = date( 'Y-m-d H:i:s' );
544
	}
545
546
	return $video_info;
547
}
548
549
550
/**
551
 * Check that a VideoPress video format has finished processing.
552
 *
553
 * This uses the info object, because that is what the WPCOM endpoint
554
 * uses, however we don't have a complete info object in the same way
555
 * WPCOM does, so we pull the meta information out of the post
556
 * options instead.
557
 *
558
 * Note: This mimics the WPCOM function of the same name and helps the media
559
 * API endpoint add all needed VideoPress data.
560
 *
561
 * @param stdClass $info
562
 * @param string   $format
563
 * @return bool
564
 */
565
function video_format_done( $info, $format ) {
566
567
	// Avoids notice when a non-videopress item is found.
568
	if ( ! is_object( $info ) ) {
569
		return false;
570
	}
571
572
	$post_id = $info->post_id;
573
574
	if ( get_post_mime_type( $post_id ) !== 'video/videopress' ) {
575
		return false;
576
	}
577
578
	$post = get_post( $post_id );
579
580
	if ( is_wp_error( $post ) ) {
581
		return false;
582
	}
583
584
	$meta = wp_get_attachment_metadata( $post->ID );
585
586
	switch ( $format ) {
587
		case 'fmt_hd':
588
			return isset( $meta['videopress']['files']['hd']['mp4'] );
589
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
590
591
		case 'fmt_dvd':
592
			return isset( $meta['videopress']['files']['dvd']['mp4'] );
593
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
594
595
		case 'fmt_std':
596
			return isset( $meta['videopress']['files']['std']['mp4'] );
597
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
598
599
		case 'fmt_ogg':
600
			return isset( $meta['videopress']['files']['std']['ogg'] );
601
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
602
	}
603
604
	return false;
605
}
606
607
/**
608
 * Get the image URL for the given VideoPress GUID
609
 *
610
 * We look up by GUID, because that is what WPCOM does and this needs to be
611
 * parameter compatible with that.
612
 *
613
 * Note: This mimics the WPCOM function of the same name and helps the media
614
 * API endpoint add all needed VideoPress data.
615
 *
616
 * @param string $guid
617
 * @param string $format
618
 * @return string
619
 */
620
function video_image_url_by_guid( $guid, $format ) {
621
622
	$post = video_get_post_by_guid( $guid );
623
624
	if ( is_wp_error( $post ) ) {
625
		return null;
626
	}
627
628
	$meta = wp_get_attachment_metadata( $post->ID );
629
630
	// We add ssl => 1 to make sure that the videos.files.wordpress.com domain is parsed as photon.
631
	$poster = apply_filters( 'jetpack_photon_url', $meta['videopress']['poster'], array( 'ssl' => 1 ), 'https' );
632
633
	return $poster;
634
}
635
636
/**
637
 * Using a GUID, find a post.
638
 *
639
 * @param string $guid
640
 * @return WP_Post
641
 */
642
function video_get_post_by_guid( $guid ) {
643
	$args = array(
644
		'post_type'      => 'attachment',
645
		'post_mime_type' => 'video/videopress',
646
		'post_status'    => 'inherit',
647
		'meta_query'     => array(
648
			array(
649
				'key'     => 'videopress_guid',
650
				'value'   => $guid,
651
				'compare' => '=',
652
			),
653
		),
654
	);
655
656
	$query = new WP_Query( $args );
657
658
	$post = $query->next_post();
659
660
	return $post;
661
}
662
663
/**
664
 * From the given VideoPress post_id, return back the appropriate attachment URL.
665
 *
666
 * When the MP4 hasn't been processed yet or this is not a VideoPress video, this will return null.
667
 *
668
 * @param int $post_id Post ID of the attachment.
669
 * @return string|null
670
 */
671
function videopress_get_attachment_url( $post_id ) {
672
673
	// We only handle VideoPress attachments.
674
	if ( get_post_mime_type( $post_id ) !== 'video/videopress' ) {
675
		return null;
676
	}
677
678
	$meta = wp_get_attachment_metadata( $post_id );
679
680
	if ( ! isset( $meta['videopress']['files']['hd']['mp4'] ) ) {
681
		// Use the original file as the url if it isn't transcoded yet.
682
		if ( isset( $meta['original'] ) ) {
683
			$return = $meta['original'];
684
		} else {
685
			// Otherwise, there isn't much we can do.
686
			return null;
687
		}
688
	} else {
689
		$return = $meta['videopress']['file_url_base']['https'] . $meta['videopress']['files']['hd']['mp4'];
690
	}
691
692
	// If the URL is a string, return it. Otherwise, we shouldn't to avoid errors downstream, so null.
693
	return ( is_string( $return ) ) ? $return : null;
694
}
695