Completed
Push — master ( fdb3a7...cde0c6 )
by Stephen
20:18
created

media.php ➔ wp_image_matches_ratio()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 9
c 1
b 0
f 0
nc 4
nop 4
dl 0
loc 18
rs 9.4285
1
<?php
2
/**
3
 * WordPress API for media display.
4
 *
5
 * @package WordPress
6
 * @subpackage Media
7
 */
8
9
/**
10
 * Scale down the default size of an image.
11
 *
12
 * This is so that the image is a better fit for the editor and theme.
13
 *
14
 * The `$size` parameter accepts either an array or a string. The supported string
15
 * values are 'thumb' or 'thumbnail' for the given thumbnail size or defaults at
16
 * 128 width and 96 height in pixels. Also supported for the string value is
17
 * 'medium', 'medium_large' and 'full'. The 'full' isn't actually supported, but any value other
18
 * than the supported will result in the content_width size or 500 if that is
19
 * not set.
20
 *
21
 * Finally, there is a filter named {@see 'editor_max_image_size'}, that will be
22
 * called on the calculated array for width and height, respectively. The second
23
 * parameter will be the value that was in the $size parameter. The returned
24
 * type for the hook is an array with the width as the first element and the
25
 * height as the second element.
26
 *
27
 * @since 2.5.0
28
 *
29
 * @global int   $content_width
30
 * @global array $_wp_additional_image_sizes
31
 *
32
 * @param int          $width   Width of the image in pixels.
33
 * @param int          $height  Height of the image in pixels.
34
 * @param string|array $size    Optional. Image size. Accepts any valid image size, or an array
35
 *                              of width and height values in pixels (in that order).
36
 *                              Default 'medium'.
37
 * @param string       $context Optional. Could be 'display' (like in a theme) or 'edit'
38
 *                              (like inserting into an editor). Default null.
39
 * @return array Width and height of what the result image should resize to.
40
 */
41
function image_constrain_size_for_editor( $width, $height, $size = 'medium', $context = null ) {
42
	global $content_width, $_wp_additional_image_sizes;
43
44
	if ( ! $context )
0 ignored issues
show
Bug Best Practice introduced by
The expression $context of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
45
		$context = is_admin() ? 'edit' : 'display';
46
47
	if ( is_array($size) ) {
48
		$max_width = $size[0];
49
		$max_height = $size[1];
50
	}
51
	elseif ( $size == 'thumb' || $size == 'thumbnail' ) {
52
		$max_width = intval(get_option('thumbnail_size_w'));
53
		$max_height = intval(get_option('thumbnail_size_h'));
54
		// last chance thumbnail size defaults
55
		if ( !$max_width && !$max_height ) {
56
			$max_width = 128;
57
			$max_height = 96;
58
		}
59
	}
60
	elseif ( $size == 'medium' ) {
61
		$max_width = intval(get_option('medium_size_w'));
62
		$max_height = intval(get_option('medium_size_h'));
63
64
	}
65 View Code Duplication
	elseif ( $size == 'medium_large' ) {
66
		$max_width = intval( get_option( 'medium_large_size_w' ) );
67
		$max_height = intval( get_option( 'medium_large_size_h' ) );
68
69
		if ( intval( $content_width ) > 0 ) {
70
			$max_width = min( intval( $content_width ), $max_width );
71
		}
72
	}
73 View Code Duplication
	elseif ( $size == 'large' ) {
74
		/*
75
		 * We're inserting a large size image into the editor. If it's a really
76
		 * big image we'll scale it down to fit reasonably within the editor
77
		 * itself, and within the theme's content width if it's known. The user
78
		 * can resize it in the editor if they wish.
79
		 */
80
		$max_width = intval(get_option('large_size_w'));
81
		$max_height = intval(get_option('large_size_h'));
82
		if ( intval($content_width) > 0 ) {
83
			$max_width = min( intval($content_width), $max_width );
84
		}
85
	} elseif ( isset( $_wp_additional_image_sizes ) && count( $_wp_additional_image_sizes ) && in_array( $size, array_keys( $_wp_additional_image_sizes ) ) ) {
86
		$max_width = intval( $_wp_additional_image_sizes[$size]['width'] );
87
		$max_height = intval( $_wp_additional_image_sizes[$size]['height'] );
88
		if ( intval($content_width) > 0 && 'edit' == $context ) // Only in admin. Assume that theme authors know what they're doing.
89
			$max_width = min( intval($content_width), $max_width );
90
	}
91
	// $size == 'full' has no constraint
92
	else {
93
		$max_width = $width;
94
		$max_height = $height;
95
	}
96
97
	/**
98
	 * Filters the maximum image size dimensions for the editor.
99
	 *
100
	 * @since 2.5.0
101
	 *
102
	 * @param array        $max_image_size An array with the width as the first element,
103
	 *                                     and the height as the second element.
104
	 * @param string|array $size           Size of what the result image should be.
105
	 * @param string       $context        The context the image is being resized for.
106
	 *                                     Possible values are 'display' (like in a theme)
107
	 *                                     or 'edit' (like inserting into an editor).
108
	 */
109
	list( $max_width, $max_height ) = apply_filters( 'editor_max_image_size', array( $max_width, $max_height ), $size, $context );
110
111
	return wp_constrain_dimensions( $width, $height, $max_width, $max_height );
112
}
113
114
/**
115
 * Retrieve width and height attributes using given width and height values.
116
 *
117
 * Both attributes are required in the sense that both parameters must have a
118
 * value, but are optional in that if you set them to false or null, then they
119
 * will not be added to the returned string.
120
 *
121
 * You can set the value using a string, but it will only take numeric values.
122
 * If you wish to put 'px' after the numbers, then it will be stripped out of
123
 * the return.
124
 *
125
 * @since 2.5.0
126
 *
127
 * @param int|string $width  Image width in pixels.
128
 * @param int|string $height Image height in pixels.
129
 * @return string HTML attributes for width and, or height.
130
 */
131
function image_hwstring( $width, $height ) {
132
	$out = '';
133
	if ($width)
134
		$out .= 'width="'.intval($width).'" ';
135
	if ($height)
136
		$out .= 'height="'.intval($height).'" ';
137
	return $out;
138
}
139
140
/**
141
 * Scale an image to fit a particular size (such as 'thumb' or 'medium').
142
 *
143
 * Array with image url, width, height, and whether is intermediate size, in
144
 * that order is returned on success is returned. $is_intermediate is true if
145
 * $url is a resized image, false if it is the original.
146
 *
147
 * The URL might be the original image, or it might be a resized version. This
148
 * function won't create a new resized copy, it will just return an already
149
 * resized one if it exists.
150
 *
151
 * A plugin may use the {@see 'image_downsize'} filter to hook into and offer image
152
 * resizing services for images. The hook must return an array with the same
153
 * elements that are returned in the function. The first element being the URL
154
 * to the new image that was resized.
155
 *
156
 * @since 2.5.0
157
 *
158
 * @param int          $id   Attachment ID for image.
159
 * @param array|string $size Optional. Image size to scale to. Accepts any valid image size,
160
 *                           or an array of width and height values in pixels (in that order).
161
 *                           Default 'medium'.
162
 * @return false|array Array containing the image URL, width, height, and boolean for whether
163
 *                     the image is an intermediate size. False on failure.
164
 */
165
function image_downsize( $id, $size = 'medium' ) {
166
167
	if ( !wp_attachment_is_image($id) )
168
		return false;
169
170
	/**
171
	 * Filters whether to preempt the output of image_downsize().
172
	 *
173
	 * Passing a truthy value to the filter will effectively short-circuit
174
	 * down-sizing the image, returning that value as output instead.
175
	 *
176
	 * @since 2.5.0
177
	 *
178
	 * @param bool         $downsize Whether to short-circuit the image downsize. Default false.
179
	 * @param int          $id       Attachment ID for image.
180
	 * @param array|string $size     Size of image. Image size or array of width and height values (in that order).
181
	 *                               Default 'medium'.
182
	 */
183
	if ( $out = apply_filters( 'image_downsize', false, $id, $size ) ) {
184
		return $out;
185
	}
186
187
	$img_url = wp_get_attachment_url($id);
188
	$meta = wp_get_attachment_metadata($id);
189
	$width = $height = 0;
190
	$is_intermediate = false;
191
	$img_url_basename = wp_basename($img_url);
0 ignored issues
show
Security Bug introduced by
It seems like $img_url defined by wp_get_attachment_url($id) on line 187 can also be of type false; however, wp_basename() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
192
193
	// try for a new style intermediate size
194
	if ( $intermediate = image_get_intermediate_size($id, $size) ) {
195
		$img_url = str_replace($img_url_basename, $intermediate['file'], $img_url);
196
		$width = $intermediate['width'];
197
		$height = $intermediate['height'];
198
		$is_intermediate = true;
199
	}
200
	elseif ( $size == 'thumbnail' ) {
201
		// fall back to the old thumbnail
202
		if ( ($thumb_file = wp_get_attachment_thumb_file($id)) && $info = getimagesize($thumb_file) ) {
203
			$img_url = str_replace($img_url_basename, wp_basename($thumb_file), $img_url);
204
			$width = $info[0];
205
			$height = $info[1];
206
			$is_intermediate = true;
207
		}
208
	}
209
	if ( !$width && !$height && isset( $meta['width'], $meta['height'] ) ) {
210
		// any other type: use the real image
211
		$width = $meta['width'];
212
		$height = $meta['height'];
213
	}
214
215
	if ( $img_url) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $img_url of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
216
		// we have the actual image size, but might need to further constrain it if content_width is narrower
217
		list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size );
218
219
		return array( $img_url, $width, $height, $is_intermediate );
220
	}
221
	return false;
222
223
}
224
225
/**
226
 * Register a new image size.
227
 *
228
 * Cropping behavior for the image size is dependent on the value of $crop:
229
 * 1. If false (default), images will be scaled, not cropped.
230
 * 2. If an array in the form of array( x_crop_position, y_crop_position ):
231
 *    - x_crop_position accepts 'left' 'center', or 'right'.
232
 *    - y_crop_position accepts 'top', 'center', or 'bottom'.
233
 *    Images will be cropped to the specified dimensions within the defined crop area.
234
 * 3. If true, images will be cropped to the specified dimensions using center positions.
235
 *
236
 * @since 2.9.0
237
 *
238
 * @global array $_wp_additional_image_sizes Associative array of additional image sizes.
239
 *
240
 * @param string     $name   Image size identifier.
241
 * @param int        $width  Image width in pixels.
242
 * @param int        $height Image height in pixels.
243
 * @param bool|array $crop   Optional. Whether to crop images to specified width and height or resize.
244
 *                           An array can specify positioning of the crop area. Default false.
245
 */
246
function add_image_size( $name, $width = 0, $height = 0, $crop = false ) {
247
	global $_wp_additional_image_sizes;
248
249
	$_wp_additional_image_sizes[ $name ] = array(
250
		'width'  => absint( $width ),
251
		'height' => absint( $height ),
252
		'crop'   => $crop,
253
	);
254
}
255
256
/**
257
 * Check if an image size exists.
258
 *
259
 * @since 3.9.0
260
 *
261
 * @global array $_wp_additional_image_sizes
262
 *
263
 * @param string $name The image size to check.
264
 * @return bool True if the image size exists, false if not.
265
 */
266
function has_image_size( $name ) {
267
	global $_wp_additional_image_sizes;
268
269
	return isset( $_wp_additional_image_sizes[ $name ] );
270
}
271
272
/**
273
 * Remove a new image size.
274
 *
275
 * @since 3.9.0
276
 *
277
 * @global array $_wp_additional_image_sizes
278
 *
279
 * @param string $name The image size to remove.
280
 * @return bool True if the image size was successfully removed, false on failure.
281
 */
282
function remove_image_size( $name ) {
283
	global $_wp_additional_image_sizes;
284
285
	if ( isset( $_wp_additional_image_sizes[ $name ] ) ) {
286
		unset( $_wp_additional_image_sizes[ $name ] );
287
		return true;
288
	}
289
290
	return false;
291
}
292
293
/**
294
 * Registers an image size for the post thumbnail.
295
 *
296
 * @since 2.9.0
297
 *
298
 * @see add_image_size() for details on cropping behavior.
299
 *
300
 * @param int        $width  Image width in pixels.
301
 * @param int        $height Image height in pixels.
302
 * @param bool|array $crop   Optional. Whether to crop images to specified width and height or resize.
303
 *                           An array can specify positioning of the crop area. Default false.
304
 */
305
function set_post_thumbnail_size( $width = 0, $height = 0, $crop = false ) {
306
	add_image_size( 'post-thumbnail', $width, $height, $crop );
307
}
308
309
/**
310
 * Gets an img tag for an image attachment, scaling it down if requested.
311
 *
312
 * The {@see 'get_image_tag_class'} filter allows for changing the class name for the
313
 * image without having to use regular expressions on the HTML content. The
314
 * parameters are: what WordPress will use for the class, the Attachment ID,
315
 * image align value, and the size the image should be.
316
 *
317
 * The second filter, {@see 'get_image_tag'}, has the HTML content, which can then be
318
 * further manipulated by a plugin to change all attribute values and even HTML
319
 * content.
320
 *
321
 * @since 2.5.0
322
 *
323
 * @param int          $id    Attachment ID.
324
 * @param string       $alt   Image Description for the alt attribute.
325
 * @param string       $title Image Description for the title attribute.
326
 * @param string       $align Part of the class name for aligning the image.
327
 * @param string|array $size  Optional. Registered image size to retrieve a tag for. Accepts any
328
 *                            valid image size, or an array of width and height values in pixels
329
 *                            (in that order). Default 'medium'.
330
 * @return string HTML IMG element for given image attachment
331
 */
332
function get_image_tag( $id, $alt, $title, $align, $size = 'medium' ) {
333
334
	list( $img_src, $width, $height ) = image_downsize($id, $size);
335
	$hwstring = image_hwstring($width, $height);
336
337
	$title = $title ? 'title="' . esc_attr( $title ) . '" ' : '';
338
339
	$class = 'align' . esc_attr($align) .' size-' . esc_attr($size) . ' wp-image-' . $id;
0 ignored issues
show
Bug introduced by
It seems like $size defined by parameter $size on line 332 can also be of type array; however, esc_attr() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
340
341
	/**
342
	 * Filters the value of the attachment's image tag class attribute.
343
	 *
344
	 * @since 2.6.0
345
	 *
346
	 * @param string       $class CSS class name or space-separated list of classes.
347
	 * @param int          $id    Attachment ID.
348
	 * @param string       $align Part of the class name for aligning the image.
349
	 * @param string|array $size  Size of image. Image size or array of width and height values (in that order).
350
	 *                            Default 'medium'.
351
	 */
352
	$class = apply_filters( 'get_image_tag_class', $class, $id, $align, $size );
353
354
	$html = '<img src="' . esc_attr($img_src) . '" alt="' . esc_attr($alt) . '" ' . $title . $hwstring . 'class="' . $class . '" />';
355
356
	/**
357
	 * Filters the HTML content for the image tag.
358
	 *
359
	 * @since 2.6.0
360
	 *
361
	 * @param string       $html  HTML content for the image.
362
	 * @param int          $id    Attachment ID.
363
	 * @param string       $alt   Alternate text.
364
	 * @param string       $title Attachment title.
365
	 * @param string       $align Part of the class name for aligning the image.
366
	 * @param string|array $size  Size of image. Image size or array of width and height values (in that order).
367
	 *                            Default 'medium'.
368
	 */
369
	return apply_filters( 'get_image_tag', $html, $id, $alt, $title, $align, $size );
370
}
371
372
/**
373
 * Calculates the new dimensions for a down-sampled image.
374
 *
375
 * If either width or height are empty, no constraint is applied on
376
 * that dimension.
377
 *
378
 * @since 2.5.0
379
 *
380
 * @param int $current_width  Current width of the image.
381
 * @param int $current_height Current height of the image.
382
 * @param int $max_width      Optional. Max width in pixels to constrain to. Default 0.
383
 * @param int $max_height     Optional. Max height in pixels to constrain to. Default 0.
384
 * @return array First item is the width, the second item is the height.
385
 */
386
function wp_constrain_dimensions( $current_width, $current_height, $max_width = 0, $max_height = 0 ) {
387
	if ( !$max_width && !$max_height )
388
		return array( $current_width, $current_height );
389
390
	$width_ratio = $height_ratio = 1.0;
391
	$did_width = $did_height = false;
392
393
	if ( $max_width > 0 && $current_width > 0 && $current_width > $max_width ) {
394
		$width_ratio = $max_width / $current_width;
395
		$did_width = true;
396
	}
397
398
	if ( $max_height > 0 && $current_height > 0 && $current_height > $max_height ) {
399
		$height_ratio = $max_height / $current_height;
400
		$did_height = true;
401
	}
402
403
	// Calculate the larger/smaller ratios
404
	$smaller_ratio = min( $width_ratio, $height_ratio );
405
	$larger_ratio  = max( $width_ratio, $height_ratio );
406
407
	if ( (int) round( $current_width * $larger_ratio ) > $max_width || (int) round( $current_height * $larger_ratio ) > $max_height ) {
408
 		// The larger ratio is too big. It would result in an overflow.
409
		$ratio = $smaller_ratio;
410
	} else {
411
		// The larger ratio fits, and is likely to be a more "snug" fit.
412
		$ratio = $larger_ratio;
413
	}
414
415
	// Very small dimensions may result in 0, 1 should be the minimum.
416
	$w = max ( 1, (int) round( $current_width  * $ratio ) );
417
	$h = max ( 1, (int) round( $current_height * $ratio ) );
418
419
	// Sometimes, due to rounding, we'll end up with a result like this: 465x700 in a 177x177 box is 117x176... a pixel short
420
	// We also have issues with recursive calls resulting in an ever-changing result. Constraining to the result of a constraint should yield the original result.
421
	// Thus we look for dimensions that are one pixel shy of the max value and bump them up
422
423
	// Note: $did_width means it is possible $smaller_ratio == $width_ratio.
424
	if ( $did_width && $w == $max_width - 1 ) {
425
		$w = $max_width; // Round it up
426
	}
427
428
	// Note: $did_height means it is possible $smaller_ratio == $height_ratio.
429
	if ( $did_height && $h == $max_height - 1 ) {
430
		$h = $max_height; // Round it up
431
	}
432
433
	/**
434
	 * Filters dimensions to constrain down-sampled images to.
435
	 *
436
	 * @since 4.1.0
437
	 *
438
	 * @param array $dimensions     The image width and height.
439
	 * @param int 	$current_width  The current width of the image.
440
	 * @param int 	$current_height The current height of the image.
441
	 * @param int 	$max_width      The maximum width permitted.
442
	 * @param int 	$max_height     The maximum height permitted.
443
	 */
444
	return apply_filters( 'wp_constrain_dimensions', array( $w, $h ), $current_width, $current_height, $max_width, $max_height );
445
}
446
447
/**
448
 * Retrieves calculated resize dimensions for use in WP_Image_Editor.
449
 *
450
 * Calculates dimensions and coordinates for a resized image that fits
451
 * within a specified width and height.
452
 *
453
 * Cropping behavior is dependent on the value of $crop:
454
 * 1. If false (default), images will not be cropped.
455
 * 2. If an array in the form of array( x_crop_position, y_crop_position ):
456
 *    - x_crop_position accepts 'left' 'center', or 'right'.
457
 *    - y_crop_position accepts 'top', 'center', or 'bottom'.
458
 *    Images will be cropped to the specified dimensions within the defined crop area.
459
 * 3. If true, images will be cropped to the specified dimensions using center positions.
460
 *
461
 * @since 2.5.0
462
 *
463
 * @param int        $orig_w Original width in pixels.
464
 * @param int        $orig_h Original height in pixels.
465
 * @param int        $dest_w New width in pixels.
466
 * @param int        $dest_h New height in pixels.
467
 * @param bool|array $crop   Optional. Whether to crop image to specified width and height or resize.
468
 *                           An array can specify positioning of the crop area. Default false.
469
 * @return false|array False on failure. Returned array matches parameters for `imagecopyresampled()`.
470
 */
471
function image_resize_dimensions( $orig_w, $orig_h, $dest_w, $dest_h, $crop = false ) {
472
473
	if ($orig_w <= 0 || $orig_h <= 0)
474
		return false;
475
	// at least one of dest_w or dest_h must be specific
476
	if ($dest_w <= 0 && $dest_h <= 0)
477
		return false;
478
479
	/**
480
	 * Filters whether to preempt calculating the image resize dimensions.
481
	 *
482
	 * Passing a non-null value to the filter will effectively short-circuit
483
	 * image_resize_dimensions(), returning that value instead.
484
	 *
485
	 * @since 3.4.0
486
	 *
487
	 * @param null|mixed $null   Whether to preempt output of the resize dimensions.
488
	 * @param int        $orig_w Original width in pixels.
489
	 * @param int        $orig_h Original height in pixels.
490
	 * @param int        $dest_w New width in pixels.
491
	 * @param int        $dest_h New height in pixels.
492
	 * @param bool|array $crop   Whether to crop image to specified width and height or resize.
493
	 *                           An array can specify positioning of the crop area. Default false.
494
	 */
495
	$output = apply_filters( 'image_resize_dimensions', null, $orig_w, $orig_h, $dest_w, $dest_h, $crop );
496
	if ( null !== $output )
497
		return $output;
498
499
	if ( $crop ) {
500
		// crop the largest possible portion of the original image that we can size to $dest_w x $dest_h
501
		$aspect_ratio = $orig_w / $orig_h;
502
		$new_w = min($dest_w, $orig_w);
503
		$new_h = min($dest_h, $orig_h);
504
505
		if ( ! $new_w ) {
506
			$new_w = (int) round( $new_h * $aspect_ratio );
507
		}
508
509
		if ( ! $new_h ) {
510
			$new_h = (int) round( $new_w / $aspect_ratio );
511
		}
512
513
		$size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
514
515
		$crop_w = round($new_w / $size_ratio);
516
		$crop_h = round($new_h / $size_ratio);
517
518
		if ( ! is_array( $crop ) || count( $crop ) !== 2 ) {
519
			$crop = array( 'center', 'center' );
520
		}
521
522
		list( $x, $y ) = $crop;
523
524
		if ( 'left' === $x ) {
525
			$s_x = 0;
526
		} elseif ( 'right' === $x ) {
527
			$s_x = $orig_w - $crop_w;
528
		} else {
529
			$s_x = floor( ( $orig_w - $crop_w ) / 2 );
530
		}
531
532
		if ( 'top' === $y ) {
533
			$s_y = 0;
534
		} elseif ( 'bottom' === $y ) {
535
			$s_y = $orig_h - $crop_h;
536
		} else {
537
			$s_y = floor( ( $orig_h - $crop_h ) / 2 );
538
		}
539
	} else {
540
		// don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
541
		$crop_w = $orig_w;
542
		$crop_h = $orig_h;
543
544
		$s_x = 0;
545
		$s_y = 0;
546
547
		list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
548
	}
549
550
	// if the resulting image would be the same size or larger we don't want to resize it
551
	if ( $new_w >= $orig_w && $new_h >= $orig_h && $dest_w != $orig_w && $dest_h != $orig_h ) {
552
		return false;
553
	}
554
555
	// the return array matches the parameters to imagecopyresampled()
556
	// int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
557
	return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h );
558
559
}
560
561
/**
562
 * Resizes an image to make a thumbnail or intermediate size.
563
 *
564
 * The returned array has the file size, the image width, and image height. The
565
 * {@see 'image_make_intermediate_size'} filter can be used to hook in and change the
566
 * values of the returned array. The only parameter is the resized file path.
567
 *
568
 * @since 2.5.0
569
 *
570
 * @param string $file   File path.
571
 * @param int    $width  Image width.
572
 * @param int    $height Image height.
573
 * @param bool   $crop   Optional. Whether to crop image to specified width and height or resize.
574
 *                       Default false.
575
 * @return false|array False, if no image was created. Metadata array on success.
576
 */
577
function image_make_intermediate_size( $file, $width, $height, $crop = false ) {
578
	if ( $width || $height ) {
579
		$editor = wp_get_image_editor( $file );
580
581
		if ( is_wp_error( $editor ) || is_wp_error( $editor->resize( $width, $height, $crop ) ) )
0 ignored issues
show
Bug introduced by
The method resize does only exist in WP_Image_Editor, but not in WP_Error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
582
			return false;
583
584
		$resized_file = $editor->save();
0 ignored issues
show
Bug introduced by
The method save does only exist in WP_Image_Editor, but not in WP_Error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
585
586
		if ( ! is_wp_error( $resized_file ) && $resized_file ) {
587
			unset( $resized_file['path'] );
588
			return $resized_file;
589
		}
590
	}
591
	return false;
592
}
593
594
/**
595
 * Helper function to test if aspect ratios for two images match.
596
 *
597
 * @since 4.6.0
598
 *
599
 * @param int $source_width  Width of the first image in pixels.
600
 * @param int $source_height Height of the first image in pixels.
601
 * @param int $target_width  Width of the second image in pixels.
602
 * @param int $target_height Height of the second image in pixels.
603
 * @return bool True if aspect ratios match within 1px. False if not.
604
 */
605
function wp_image_matches_ratio( $source_width, $source_height, $target_width, $target_height ) {
606
	/*
607
	 * To test for varying crops, we constrain the dimensions of the larger image
608
	 * to the dimensions of the smaller image and see if they match.
609
	 */
610
	if ( $source_width > $target_width ) {
611
		$constrained_size = wp_constrain_dimensions( $source_width, $source_height, $target_width );
612
		$expected_size = array( $target_width, $target_height );
613
	} else {
614
		$constrained_size = wp_constrain_dimensions( $target_width, $target_height, $source_width );
615
		$expected_size = array( $source_width, $source_height );
616
	}
617
618
	// If the image dimensions are within 1px of the expected size, we consider it a match.
619
	$matched = ( abs( $constrained_size[0] - $expected_size[0] ) <= 1 && abs( $constrained_size[1] - $expected_size[1] ) <= 1 );
620
621
	return $matched;
622
}
623
624
/**
625
 * Retrieves the image's intermediate size (resized) path, width, and height.
626
 *
627
 * The $size parameter can be an array with the width and height respectively.
628
 * If the size matches the 'sizes' metadata array for width and height, then it
629
 * will be used. If there is no direct match, then the nearest image size larger
630
 * than the specified size will be used. If nothing is found, then the function
631
 * will break out and return false.
632
 *
633
 * The metadata 'sizes' is used for compatible sizes that can be used for the
634
 * parameter $size value.
635
 *
636
 * The url path will be given, when the $size parameter is a string.
637
 *
638
 * If you are passing an array for the $size, you should consider using
639
 * add_image_size() so that a cropped version is generated. It's much more
640
 * efficient than having to find the closest-sized image and then having the
641
 * browser scale down the image.
642
 *
643
 * @since 2.5.0
644
 *
645
 * @param int          $post_id Attachment ID.
646
 * @param array|string $size    Optional. Image size. Accepts any valid image size, or an array
647
 *                              of width and height values in pixels (in that order).
648
 *                              Default 'thumbnail'.
649
 * @return false|array $data {
650
 *     Array of file relative path, width, and height on success. Additionally includes absolute
651
 *     path and URL if registered size is passed to $size parameter. False on failure.
652
 *
653
 *     @type string $file   Image's path relative to uploads directory
654
 *     @type int    $width  Width of image
655
 *     @type int    $height Height of image
656
 *     @type string $path   Image's absolute filesystem path.
657
 *     @type string $url    Image's URL.
658
 * }
659
 */
660
function image_get_intermediate_size( $post_id, $size = 'thumbnail' ) {
661
	if ( ! $size || ! is_array( $imagedata = wp_get_attachment_metadata( $post_id ) ) || empty( $imagedata['sizes'] )  ) {
662
		return false;
663
	}
664
665
	$data = array();
666
667
	// Find the best match when '$size' is an array.
668
	if ( is_array( $size ) ) {
669
		$candidates = array();
670
671
		foreach ( $imagedata['sizes'] as $_size => $data ) {
672
			// If there's an exact match to an existing image size, short circuit.
673
			if ( $data['width'] == $size[0] && $data['height'] == $size[1] ) {
674
				$candidates[ $data['width'] * $data['height'] ] = $data;
675
				break;
676
			}
677
678
			// If it's not an exact match, consider larger sizes with the same aspect ratio.
679
			if ( $data['width'] >= $size[0] && $data['height'] >= $size[1] ) {
680
				// If '0' is passed to either size, we test ratios against the original file.
681
				if ( 0 === $size[0] || 0 === $size[1] ) {
682
					$same_ratio = wp_image_matches_ratio( $data['width'], $data['height'], $imagedata['width'], $imagedata['height'] );
683
				} else {
684
					$same_ratio = wp_image_matches_ratio( $data['width'], $data['height'], $size[0], $size[1] );
685
				}
686
687
				if ( $same_ratio ) {
688
					$candidates[ $data['width'] * $data['height'] ] = $data;
689
				}
690
			}
691
		}
692
693
		if ( ! empty( $candidates ) ) {
694
			// Sort the array by size if we have more than one candidate.
695
			if ( 1 < count( $candidates ) ) {
696
				ksort( $candidates );
697
			}
698
699
			$data = array_shift( $candidates );
700
		/*
701
		 * When the size requested is smaller than the thumbnail dimensions, we
702
		 * fall back to the thumbnail size to maintain backwards compatibility with
703
		 * pre 4.6 versions of WordPress.
704
		 */
705
		} elseif ( ! empty( $imagedata['sizes']['thumbnail'] ) && $imagedata['sizes']['thumbnail']['width'] >= $size[0] && $imagedata['sizes']['thumbnail']['width'] >= $size[1] ) {
706
			$data = $imagedata['sizes']['thumbnail'];
707
		} else {
708
			return false;
709
		}
710
711
		// Constrain the width and height attributes to the requested values.
712
		list( $data['width'], $data['height'] ) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
713
714
	} elseif ( ! empty( $imagedata['sizes'][ $size ] ) ) {
715
		$data = $imagedata['sizes'][ $size ];
716
	}
717
718
	// If we still don't have a match at this point, return false.
719
	if ( empty( $data ) ) {
720
		return false;
721
	}
722
723
	// include the full filesystem path of the intermediate file
724
	if ( empty($data['path']) && !empty($data['file']) ) {
725
		$file_url = wp_get_attachment_url($post_id);
726
		$data['path'] = path_join( dirname($imagedata['file']), $data['file'] );
727
		$data['url'] = path_join( dirname($file_url), $data['file'] );
728
	}
729
730
	/**
731
	 * Filters the output of image_get_intermediate_size()
732
	 *
733
	 * @since 4.4.0
734
	 *
735
	 * @see image_get_intermediate_size()
736
	 *
737
	 * @param array        $data    Array of file relative path, width, and height on success. May also include
738
	 *                              file absolute path and URL.
739
	 * @param int          $post_id The post_id of the image attachment
740
	 * @param string|array $size    Registered image size or flat array of initially-requested height and width
741
	 *                              dimensions (in that order).
742
	 */
743
	return apply_filters( 'image_get_intermediate_size', $data, $post_id, $size );
744
}
745
746
/**
747
 * Gets the available intermediate image sizes.
748
 *
749
 * @since 3.0.0
750
 *
751
 * @global array $_wp_additional_image_sizes
752
 *
753
 * @return array Returns a filtered array of image size strings.
754
 */
755
function get_intermediate_image_sizes() {
756
	global $_wp_additional_image_sizes;
757
	$image_sizes = array('thumbnail', 'medium', 'medium_large', 'large'); // Standard sizes
758
	if ( isset( $_wp_additional_image_sizes ) && count( $_wp_additional_image_sizes ) )
759
		$image_sizes = array_merge( $image_sizes, array_keys( $_wp_additional_image_sizes ) );
760
761
	/**
762
	 * Filters the list of intermediate image sizes.
763
	 *
764
	 * @since 2.5.0
765
	 *
766
	 * @param array $image_sizes An array of intermediate image sizes. Defaults
767
	 *                           are 'thumbnail', 'medium', 'medium_large', 'large'.
768
	 */
769
	return apply_filters( 'intermediate_image_sizes', $image_sizes );
770
}
771
772
/**
773
 * Retrieve an image to represent an attachment.
774
 *
775
 * A mime icon for files, thumbnail or intermediate size for images.
776
 *
777
 * The returned array contains four values: the URL of the attachment image src,
778
 * the width of the image file, the height of the image file, and a boolean
779
 * representing whether the returned array describes an intermediate (generated)
780
 * image size or the original, full-sized upload.
781
 *
782
 * @since 2.5.0
783
 *
784
 * @param int          $attachment_id Image attachment ID.
785
 * @param string|array $size          Optional. Image size. Accepts any valid image size, or an array of width
786
 *                                    and height values in pixels (in that order). Default 'thumbnail'.
787
 * @param bool         $icon          Optional. Whether the image should be treated as an icon. Default false.
788
 * @return false|array Returns an array (url, width, height, is_intermediate), or false, if no image is available.
789
 */
790
function wp_get_attachment_image_src( $attachment_id, $size = 'thumbnail', $icon = false ) {
791
	// get a thumbnail or intermediate image if there is one
792
	$image = image_downsize( $attachment_id, $size );
793
	if ( ! $image ) {
794
		$src = false;
795
796
		if ( $icon && $src = wp_mime_type_icon( $attachment_id ) ) {
797
			/** This filter is documented in wp-includes/post.php */
798
			$icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' );
799
800
			$src_file = $icon_dir . '/' . wp_basename( $src );
801
			@list( $width, $height ) = getimagesize( $src_file );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
802
		}
803
804
		if ( $src && $width && $height ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $src of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
805
			$image = array( $src, $width, $height );
0 ignored issues
show
Bug introduced by
The variable $width does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $height does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
806
		}
807
	}
808
	/**
809
	 * Filters the image src result.
810
	 *
811
	 * @since 4.3.0
812
	 *
813
	 * @param array|false  $image         Either array with src, width & height, icon src, or false.
814
	 * @param int          $attachment_id Image attachment ID.
815
	 * @param string|array $size          Size of image. Image size or array of width and height values
816
	 *                                    (in that order). Default 'thumbnail'.
817
	 * @param bool         $icon          Whether the image should be treated as an icon. Default false.
818
	 */
819
	return apply_filters( 'wp_get_attachment_image_src', $image, $attachment_id, $size, $icon );
820
}
821
822
/**
823
 * Get an HTML img element representing an image attachment
824
 *
825
 * While `$size` will accept an array, it is better to register a size with
826
 * add_image_size() so that a cropped version is generated. It's much more
827
 * efficient than having to find the closest-sized image and then having the
828
 * browser scale down the image.
829
 *
830
 * @since 2.5.0
831
 *
832
 * @param int          $attachment_id Image attachment ID.
833
 * @param string|array $size          Optional. Image size. Accepts any valid image size, or an array of width
834
 *                                    and height values in pixels (in that order). Default 'thumbnail'.
835
 * @param bool         $icon          Optional. Whether the image should be treated as an icon. Default false.
836
 * @param string|array $attr          Optional. Attributes for the image markup. Default empty.
837
 * @return string HTML img element or empty string on failure.
838
 */
839
function wp_get_attachment_image($attachment_id, $size = 'thumbnail', $icon = false, $attr = '') {
840
	$html = '';
841
	$image = wp_get_attachment_image_src($attachment_id, $size, $icon);
842
	if ( $image ) {
843
		list($src, $width, $height) = $image;
844
		$hwstring = image_hwstring($width, $height);
845
		$size_class = $size;
846
		if ( is_array( $size_class ) ) {
847
			$size_class = join( 'x', $size_class );
848
		}
849
		$attachment = get_post($attachment_id);
850
		$default_attr = array(
851
			'src'	=> $src,
852
			'class'	=> "attachment-$size_class size-$size_class",
853
			'alt'	=> trim(strip_tags( get_post_meta($attachment_id, '_wp_attachment_image_alt', true) )), // Use Alt field first
854
		);
855
		if ( empty($default_attr['alt']) )
856
			$default_attr['alt'] = trim(strip_tags( $attachment->post_excerpt )); // If not, Use the Caption
857
		if ( empty($default_attr['alt']) )
858
			$default_attr['alt'] = trim(strip_tags( $attachment->post_title )); // Finally, use the title
859
860
		$attr = wp_parse_args( $attr, $default_attr );
861
862
		// Generate 'srcset' and 'sizes' if not already present.
863
		if ( empty( $attr['srcset'] ) ) {
864
			$image_meta = get_post_meta( $attachment_id, '_wp_attachment_metadata', true );
865
866
			if ( is_array( $image_meta ) ) {
867
				$size_array = array( absint( $width ), absint( $height ) );
868
				$srcset = wp_calculate_image_srcset( $size_array, $src, $image_meta, $attachment_id );
869
				$sizes = wp_calculate_image_sizes( $size_array, $src, $image_meta, $attachment_id );
870
871
				if ( $srcset && ( $sizes || ! empty( $attr['sizes'] ) ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $srcset of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
872
					$attr['srcset'] = $srcset;
873
874
					if ( empty( $attr['sizes'] ) ) {
875
						$attr['sizes'] = $sizes;
876
					}
877
				}
878
			}
879
		}
880
881
		/**
882
		 * Filters the list of attachment image attributes.
883
		 *
884
		 * @since 2.8.0
885
		 *
886
		 * @param array        $attr       Attributes for the image markup.
887
		 * @param WP_Post      $attachment Image attachment post.
888
		 * @param string|array $size       Requested size. Image size or array of width and height values
889
		 *                                 (in that order). Default 'thumbnail'.
890
		 */
891
		$attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment, $size );
892
		$attr = array_map( 'esc_attr', $attr );
893
		$html = rtrim("<img $hwstring");
894
		foreach ( $attr as $name => $value ) {
895
			$html .= " $name=" . '"' . $value . '"';
896
		}
897
		$html .= ' />';
898
	}
899
900
	return $html;
901
}
902
903
/**
904
 * Get the URL of an image attachment.
905
 *
906
 * @since 4.4.0
907
 *
908
 * @param int          $attachment_id Image attachment ID.
909
 * @param string|array $size          Optional. Image size to retrieve. Accepts any valid image size, or an array
910
 *                                    of width and height values in pixels (in that order). Default 'thumbnail'.
911
 * @param bool         $icon          Optional. Whether the image should be treated as an icon. Default false.
912
 * @return string|false Attachment URL or false if no image is available.
913
 */
914
function wp_get_attachment_image_url( $attachment_id, $size = 'thumbnail', $icon = false ) {
915
	$image = wp_get_attachment_image_src( $attachment_id, $size, $icon );
916
	return isset( $image['0'] ) ? $image['0'] : false;
917
}
918
919
/**
920
 * Get the attachment path relative to the upload directory.
921
 *
922
 * @since 4.4.1
923
 * @access private
924
 *
925
 * @param string $file Attachment file name.
926
 * @return string Attachment path relative to the upload directory.
927
 */
928
function _wp_get_attachment_relative_path( $file ) {
929
	$dirname = dirname( $file );
930
931
	if ( '.' === $dirname ) {
932
		return '';
933
	}
934
935
	if ( false !== strpos( $dirname, 'wp-content/uploads' ) ) {
936
		// Get the directory name relative to the upload directory (back compat for pre-2.7 uploads)
937
		$dirname = substr( $dirname, strpos( $dirname, 'wp-content/uploads' ) + 18 );
938
		$dirname = ltrim( $dirname, '/' );
939
	}
940
941
	return $dirname;
942
}
943
944
/**
945
 * Get the image size as array from its meta data.
946
 *
947
 * Used for responsive images.
948
 *
949
 * @since 4.4.0
950
 * @access private
951
 *
952
 * @param string $size_name  Image size. Accepts any valid image size name ('thumbnail', 'medium', etc.).
953
 * @param array  $image_meta The image meta data.
954
 * @return array|bool Array of width and height values in pixels (in that order)
955
 *                    or false if the size doesn't exist.
956
 */
957
function _wp_get_image_size_from_meta( $size_name, $image_meta ) {
958
	if ( $size_name === 'full' ) {
959
		return array(
960
			absint( $image_meta['width'] ),
961
			absint( $image_meta['height'] ),
962
		);
963
	} elseif ( ! empty( $image_meta['sizes'][$size_name] ) ) {
964
		return array(
965
			absint( $image_meta['sizes'][$size_name]['width'] ),
966
			absint( $image_meta['sizes'][$size_name]['height'] ),
967
		);
968
	}
969
970
	return false;
971
}
972
973
/**
974
 * Retrieves the value for an image attachment's 'srcset' attribute.
975
 *
976
 * @since 4.4.0
977
 *
978
 * @see wp_calculate_image_srcset()
979
 *
980
 * @param int          $attachment_id Image attachment ID.
981
 * @param array|string $size          Optional. Image size. Accepts any valid image size, or an array of
982
 *                                    width and height values in pixels (in that order). Default 'medium'.
983
 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
984
 *                                    Default null.
985
 * @return string|bool A 'srcset' value string or false.
986
 */
987 View Code Duplication
function wp_get_attachment_image_srcset( $attachment_id, $size = 'medium', $image_meta = null ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
988
	if ( ! $image = wp_get_attachment_image_src( $attachment_id, $size ) ) {
989
		return false;
990
	}
991
992
	if ( ! is_array( $image_meta ) ) {
993
		$image_meta = get_post_meta( $attachment_id, '_wp_attachment_metadata', true );
994
	}
995
996
	$image_src = $image[0];
997
	$size_array = array(
998
		absint( $image[1] ),
999
		absint( $image[2] )
1000
	);
1001
1002
	return wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id );
1003
}
1004
1005
/**
1006
 * A helper function to calculate the image sources to include in a 'srcset' attribute.
1007
 *
1008
 * @since 4.4.0
1009
 *
1010
 * @param array  $size_array    Array of width and height values in pixels (in that order).
1011
 * @param string $image_src     The 'src' of the image.
1012
 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1013
 * @param int    $attachment_id Optional. The image attachment ID to pass to the filter. Default 0.
1014
 * @return string|bool          The 'srcset' attribute value. False on error or when only one source exists.
1015
 */
1016
function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 ) {
1017
	/**
1018
	 * Let plugins pre-filter the image meta to be able to fix inconsistencies in the stored data.
1019
	 *
1020
	 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1021
	 * @param array  $size_array    Array of width and height values in pixels (in that order).
1022
	 * @param string $image_src     The 'src' of the image.
1023
	 * @param int    $attachment_id The image attachment ID or 0 if not supplied.
1024
	 */
1025
	$image_meta = apply_filters( 'wp_calculate_image_srcset_meta', $image_meta, $size_array, $image_src, $attachment_id );
1026
1027
	if ( empty( $image_meta['sizes'] ) || ! isset( $image_meta['file'] ) || strlen( $image_meta['file'] ) < 4 ) {
1028
		return false;
1029
	}
1030
1031
	$image_sizes = $image_meta['sizes'];
1032
1033
	// Get the width and height of the image.
1034
	$image_width = (int) $size_array[0];
1035
	$image_height = (int) $size_array[1];
1036
1037
	// Bail early if error/no width.
1038
	if ( $image_width < 1 ) {
1039
		return false;
1040
	}
1041
1042
	$image_basename = wp_basename( $image_meta['file'] );
1043
1044
	/*
1045
	 * WordPress flattens animated GIFs into one frame when generating intermediate sizes.
1046
	 * To avoid hiding animation in user content, if src is a full size GIF, a srcset attribute is not generated.
1047
	 * If src is an intermediate size GIF, the full size is excluded from srcset to keep a flattened GIF from becoming animated.
1048
	 */
1049
	if ( ! isset( $image_sizes['thumbnail']['mime-type'] ) || 'image/gif' !== $image_sizes['thumbnail']['mime-type'] ) {
1050
		$image_sizes[] = array(
1051
			'width'  => $image_meta['width'],
1052
			'height' => $image_meta['height'],
1053
			'file'   => $image_basename,
1054
		);
1055
	} elseif ( strpos( $image_src, $image_meta['file'] ) ) {
1056
		return false;
1057
	}
1058
1059
	// Retrieve the uploads sub-directory from the full size image.
1060
	$dirname = _wp_get_attachment_relative_path( $image_meta['file'] );
1061
1062
	if ( $dirname ) {
1063
		$dirname = trailingslashit( $dirname );
1064
	}
1065
1066
	$upload_dir = wp_get_upload_dir();
1067
	$image_baseurl = trailingslashit( $upload_dir['baseurl'] ) . $dirname;
1068
1069
	/*
1070
	 * If currently on HTTPS, prefer HTTPS URLs when we know they're supported by the domain
1071
	 * (which is to say, when they share the domain name of the current request).
1072
	 */
1073
	if ( is_ssl() && 'https' !== substr( $image_baseurl, 0, 5 ) && parse_url( $image_baseurl, PHP_URL_HOST ) === $_SERVER['HTTP_HOST'] ) {
1074
		$image_baseurl = set_url_scheme( $image_baseurl, 'https' );
1075
	}
1076
1077
	/*
1078
	 * Images that have been edited in WordPress after being uploaded will
1079
	 * contain a unique hash. Look for that hash and use it later to filter
1080
	 * out images that are leftovers from previous versions.
1081
	 */
1082
	$image_edited = preg_match( '/-e[0-9]{13}/', wp_basename( $image_src ), $image_edit_hash );
1083
1084
	/**
1085
	 * Filters the maximum image width to be included in a 'srcset' attribute.
1086
	 *
1087
	 * @since 4.4.0
1088
	 *
1089
	 * @param int   $max_width  The maximum image width to be included in the 'srcset'. Default '1600'.
1090
	 * @param array $size_array Array of width and height values in pixels (in that order).
1091
	 */
1092
	$max_srcset_image_width = apply_filters( 'max_srcset_image_width', 1600, $size_array );
1093
1094
	// Array to hold URL candidates.
1095
	$sources = array();
1096
1097
	/**
1098
	 * To make sure the ID matches our image src, we will check to see if any sizes in our attachment
1099
	 * meta match our $image_src. If no matches are found we don't return a srcset to avoid serving
1100
	 * an incorrect image. See #35045.
1101
	 */
1102
	$src_matched = false;
1103
1104
	/*
1105
	 * Loop through available images. Only use images that are resized
1106
	 * versions of the same edit.
1107
	 */
1108
	foreach ( $image_sizes as $image ) {
1109
		$is_src = false;
1110
1111
		// Check if image meta isn't corrupted.
1112
		if ( ! is_array( $image ) ) {
1113
			continue;
1114
		}
1115
1116
		// If the file name is part of the `src`, we've confirmed a match.
1117
		if ( ! $src_matched && false !== strpos( $image_src, $dirname . $image['file'] ) ) {
1118
			$src_matched = $is_src = true;
1119
		}
1120
1121
		// Filter out images that are from previous edits.
1122
		if ( $image_edited && ! strpos( $image['file'], $image_edit_hash[0] ) ) {
1123
			continue;
1124
		}
1125
1126
		/*
1127
		 * Filters out images that are wider than '$max_srcset_image_width' unless
1128
		 * that file is in the 'src' attribute.
1129
		 */
1130
		if ( $max_srcset_image_width && $image['width'] > $max_srcset_image_width && ! $is_src ) {
1131
			continue;
1132
		}
1133
1134
		// If the image dimensions are within 1px of the expected size, use it.
1135
		if ( wp_image_matches_ratio( $image_width, $image_height, $image['width'], $image['height'] ) ) {
1136
			// Add the URL, descriptor, and value to the sources array to be returned.
1137
			$source = array(
1138
				'url'        => $image_baseurl . $image['file'],
1139
				'descriptor' => 'w',
1140
				'value'      => $image['width'],
1141
			);
1142
1143
			// The 'src' image has to be the first in the 'srcset', because of a bug in iOS8. See #35030.
1144
			if ( $is_src ) {
1145
				$sources = array( $image['width'] => $source ) + $sources;
1146
			} else {
1147
				$sources[ $image['width'] ] = $source;
1148
			}
1149
		}
1150
	}
1151
1152
	/**
1153
	 * Filters an image's 'srcset' sources.
1154
	 *
1155
	 * @since 4.4.0
1156
	 *
1157
	 * @param array  $sources {
1158
	 *     One or more arrays of source data to include in the 'srcset'.
1159
	 *
1160
	 *     @type array $width {
1161
	 *         @type string $url        The URL of an image source.
1162
	 *         @type string $descriptor The descriptor type used in the image candidate string,
1163
	 *                                  either 'w' or 'x'.
1164
	 *         @type int    $value      The source width if paired with a 'w' descriptor, or a
1165
	 *                                  pixel density value if paired with an 'x' descriptor.
1166
	 *     }
1167
	 * }
1168
	 * @param array  $size_array    Array of width and height values in pixels (in that order).
1169
	 * @param string $image_src     The 'src' of the image.
1170
	 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1171
	 * @param int    $attachment_id Image attachment ID or 0.
1172
	 */
1173
	$sources = apply_filters( 'wp_calculate_image_srcset', $sources, $size_array, $image_src, $image_meta, $attachment_id );
1174
1175
	// Only return a 'srcset' value if there is more than one source.
1176
	if ( ! $src_matched || count( $sources ) < 2 ) {
1177
		return false;
1178
	}
1179
1180
	$srcset = '';
1181
1182
	foreach ( $sources as $source ) {
1183
		$srcset .= str_replace( ' ', '%20', $source['url'] ) . ' ' . $source['value'] . $source['descriptor'] . ', ';
1184
	}
1185
1186
	return rtrim( $srcset, ', ' );
1187
}
1188
1189
/**
1190
 * Retrieves the value for an image attachment's 'sizes' attribute.
1191
 *
1192
 * @since 4.4.0
1193
 *
1194
 * @see wp_calculate_image_sizes()
1195
 *
1196
 * @param int          $attachment_id Image attachment ID.
1197
 * @param array|string $size          Optional. Image size. Accepts any valid image size, or an array of width
1198
 *                                    and height values in pixels (in that order). Default 'medium'.
1199
 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
1200
 *                                    Default null.
1201
 * @return string|bool A valid source size value for use in a 'sizes' attribute or false.
1202
 */
1203 View Code Duplication
function wp_get_attachment_image_sizes( $attachment_id, $size = 'medium', $image_meta = null ) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1204
	if ( ! $image = wp_get_attachment_image_src( $attachment_id, $size ) ) {
1205
		return false;
1206
	}
1207
1208
	if ( ! is_array( $image_meta ) ) {
1209
		$image_meta = get_post_meta( $attachment_id, '_wp_attachment_metadata', true );
1210
	}
1211
1212
	$image_src = $image[0];
1213
	$size_array = array(
1214
		absint( $image[1] ),
1215
		absint( $image[2] )
1216
	);
1217
1218
	return wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id );
1219
}
1220
1221
/**
1222
 * Creates a 'sizes' attribute value for an image.
1223
 *
1224
 * @since 4.4.0
1225
 *
1226
 * @param array|string $size          Image size to retrieve. Accepts any valid image size, or an array
1227
 *                                    of width and height values in pixels (in that order). Default 'medium'.
1228
 * @param string       $image_src     Optional. The URL to the image file. Default null.
1229
 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
1230
 *                                    Default null.
1231
 * @param int          $attachment_id Optional. Image attachment ID. Either `$image_meta` or `$attachment_id`
1232
 *                                    is needed when using the image size name as argument for `$size`. Default 0.
1233
 * @return string|bool A valid source size value for use in a 'sizes' attribute or false.
1234
 */
1235
function wp_calculate_image_sizes( $size, $image_src = null, $image_meta = null, $attachment_id = 0 ) {
1236
	$width = 0;
1237
1238
	if ( is_array( $size ) ) {
1239
		$width = absint( $size[0] );
1240
	} elseif ( is_string( $size ) ) {
1241
		if ( ! $image_meta && $attachment_id ) {
1242
			$image_meta = get_post_meta( $attachment_id, '_wp_attachment_metadata', true );
1243
		}
1244
1245
		if ( is_array( $image_meta ) ) {
1246
			$size_array = _wp_get_image_size_from_meta( $size, $image_meta );
1247
			if ( $size_array ) {
1248
				$width = absint( $size_array[0] );
1249
			}
1250
		}
1251
	}
1252
1253
	if ( ! $width ) {
1254
		return false;
1255
	}
1256
1257
	// Setup the default 'sizes' attribute.
1258
	$sizes = sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', $width );
1259
1260
	/**
1261
	 * Filters the output of 'wp_calculate_image_sizes()'.
1262
	 *
1263
	 * @since 4.4.0
1264
	 *
1265
	 * @param string       $sizes         A source size value for use in a 'sizes' attribute.
1266
	 * @param array|string $size          Requested size. Image size or array of width and height values
1267
	 *                                    in pixels (in that order).
1268
	 * @param string|null  $image_src     The URL to the image file or null.
1269
	 * @param array|null   $image_meta    The image meta data as returned by wp_get_attachment_metadata() or null.
1270
	 * @param int          $attachment_id Image attachment ID of the original image or 0.
1271
	 */
1272
	return apply_filters( 'wp_calculate_image_sizes', $sizes, $size, $image_src, $image_meta, $attachment_id );
1273
}
1274
1275
/**
1276
 * Filters 'img' elements in post content to add 'srcset' and 'sizes' attributes.
1277
 *
1278
 * @since 4.4.0
1279
 *
1280
 * @see wp_image_add_srcset_and_sizes()
1281
 *
1282
 * @param string $content The raw post content to be filtered.
1283
 * @return string Converted content with 'srcset' and 'sizes' attributes added to images.
1284
 */
1285
function wp_make_content_images_responsive( $content ) {
1286
	if ( ! preg_match_all( '/<img [^>]+>/', $content, $matches ) ) {
1287
		return $content;
1288
	}
1289
1290
	$selected_images = $attachment_ids = array();
1291
1292
	foreach( $matches[0] as $image ) {
1293
		if ( false === strpos( $image, ' srcset=' ) && preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) &&
1294
			( $attachment_id = absint( $class_id[1] ) ) ) {
1295
1296
			/*
1297
			 * If exactly the same image tag is used more than once, overwrite it.
1298
			 * All identical tags will be replaced later with 'str_replace()'.
1299
			 */
1300
			$selected_images[ $image ] = $attachment_id;
1301
			// Overwrite the ID when the same image is included more than once.
1302
			$attachment_ids[ $attachment_id ] = true;
1303
		}
1304
	}
1305
1306
	if ( count( $attachment_ids ) > 1 ) {
1307
		/*
1308
		 * Warm object cache for use with 'get_post_meta()'.
1309
		 *
1310
		 * To avoid making a database call for each image, a single query
1311
		 * warms the object cache with the meta information for all images.
1312
		 */
1313
		update_meta_cache( 'post', array_keys( $attachment_ids ) );
1314
	}
1315
1316
	foreach ( $selected_images as $image => $attachment_id ) {
1317
		$image_meta = get_post_meta( $attachment_id, '_wp_attachment_metadata', true );
1318
		$content = str_replace( $image, wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id ), $content );
1319
	}
1320
1321
	return $content;
1322
}
1323
1324
/**
1325
 * Adds 'srcset' and 'sizes' attributes to an existing 'img' element.
1326
 *
1327
 * @since 4.4.0
1328
 *
1329
 * @see wp_calculate_image_srcset()
1330
 * @see wp_calculate_image_sizes()
1331
 *
1332
 * @param string $image         An HTML 'img' element to be filtered.
1333
 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1334
 * @param int    $attachment_id Image attachment ID.
1335
 * @return string Converted 'img' element with 'srcset' and 'sizes' attributes added.
1336
 */
1337
function wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id ) {
1338
	// Ensure the image meta exists.
1339
	if ( empty( $image_meta['sizes'] ) ) {
1340
		return $image;
1341
	}
1342
1343
	$image_src = preg_match( '/src="([^"]+)"/', $image, $match_src ) ? $match_src[1] : '';
1344
	list( $image_src ) = explode( '?', $image_src );
1345
1346
	// Return early if we couldn't get the image source.
1347
	if ( ! $image_src ) {
1348
		return $image;
1349
	}
1350
1351
	// Bail early if an image has been inserted and later edited.
1352
	if ( preg_match( '/-e[0-9]{13}/', $image_meta['file'], $img_edit_hash ) &&
1353
		strpos( wp_basename( $image_src ), $img_edit_hash[0] ) === false ) {
1354
1355
		return $image;
1356
	}
1357
1358
	$width  = preg_match( '/ width="([0-9]+)"/',  $image, $match_width  ) ? (int) $match_width[1]  : 0;
1359
	$height = preg_match( '/ height="([0-9]+)"/', $image, $match_height ) ? (int) $match_height[1] : 0;
1360
1361
	if ( ! $width || ! $height ) {
1362
		/*
1363
		 * If attempts to parse the size value failed, attempt to use the image meta data to match
1364
		 * the image file name from 'src' against the available sizes for an attachment.
1365
		 */
1366
		$image_filename = wp_basename( $image_src );
1367
1368
		if ( $image_filename === wp_basename( $image_meta['file'] ) ) {
1369
			$width = (int) $image_meta['width'];
1370
			$height = (int) $image_meta['height'];
1371
		} else {
1372
			foreach( $image_meta['sizes'] as $image_size_data ) {
1373
				if ( $image_filename === $image_size_data['file'] ) {
1374
					$width = (int) $image_size_data['width'];
1375
					$height = (int) $image_size_data['height'];
1376
					break;
1377
				}
1378
			}
1379
		}
1380
	}
1381
1382
	if ( ! $width || ! $height ) {
1383
		return $image;
1384
	}
1385
1386
	$size_array = array( $width, $height );
1387
	$srcset = wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id );
1388
1389
	if ( $srcset ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $srcset of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1390
		// Check if there is already a 'sizes' attribute.
1391
		$sizes = strpos( $image, ' sizes=' );
1392
1393
		if ( ! $sizes ) {
1394
			$sizes = wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id );
1395
		}
1396
	}
1397
1398
	if ( $srcset && $sizes ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $srcset of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1399
		// Format the 'srcset' and 'sizes' string and escape attributes.
1400
		$attr = sprintf( ' srcset="%s"', esc_attr( $srcset ) );
1401
1402
		if ( is_string( $sizes ) ) {
1403
			$attr .= sprintf( ' sizes="%s"', esc_attr( $sizes ) );
0 ignored issues
show
Bug introduced by
The variable $sizes does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1404
		}
1405
1406
		// Add 'srcset' and 'sizes' attributes to the image markup.
1407
		$image = preg_replace( '/<img ([^>]+?)[\/ ]*>/', '<img $1' . $attr . ' />', $image );
1408
	}
1409
1410
	return $image;
1411
}
1412
1413
/**
1414
 * Adds a 'wp-post-image' class to post thumbnails. Internal use only.
1415
 *
1416
 * Uses the {@see 'begin_fetch_post_thumbnail_html'} and {@see 'end_fetch_post_thumbnail_html'}
1417
 * action hooks to dynamically add/remove itself so as to only filter post thumbnails.
1418
 *
1419
 * @ignore
1420
 * @since 2.9.0
1421
 *
1422
 * @param array $attr Thumbnail attributes including src, class, alt, title.
1423
 * @return array Modified array of attributes including the new 'wp-post-image' class.
1424
 */
1425
function _wp_post_thumbnail_class_filter( $attr ) {
1426
	$attr['class'] .= ' wp-post-image';
1427
	return $attr;
1428
}
1429
1430
/**
1431
 * Adds '_wp_post_thumbnail_class_filter' callback to the 'wp_get_attachment_image_attributes'
1432
 * filter hook. Internal use only.
1433
 *
1434
 * @ignore
1435
 * @since 2.9.0
1436
 *
1437
 * @param array $attr Thumbnail attributes including src, class, alt, title.
1438
 */
1439
function _wp_post_thumbnail_class_filter_add( $attr ) {
0 ignored issues
show
Unused Code introduced by
The parameter $attr is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1440
	add_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
1441
}
1442
1443
/**
1444
 * Removes the '_wp_post_thumbnail_class_filter' callback from the 'wp_get_attachment_image_attributes'
1445
 * filter hook. Internal use only.
1446
 *
1447
 * @ignore
1448
 * @since 2.9.0
1449
 *
1450
 * @param array $attr Thumbnail attributes including src, class, alt, title.
1451
 */
1452
function _wp_post_thumbnail_class_filter_remove( $attr ) {
0 ignored issues
show
Unused Code introduced by
The parameter $attr is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1453
	remove_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
1454
}
1455
1456
add_shortcode('wp_caption', 'img_caption_shortcode');
1457
add_shortcode('caption', 'img_caption_shortcode');
1458
1459
/**
1460
 * Builds the Caption shortcode output.
1461
 *
1462
 * Allows a plugin to replace the content that would otherwise be returned. The
1463
 * filter is {@see 'img_caption_shortcode'} and passes an empty string, the attr
1464
 * parameter and the content parameter values.
1465
 *
1466
 * The supported attributes for the shortcode are 'id', 'align', 'width', and
1467
 * 'caption'.
1468
 *
1469
 * @since 2.6.0
1470
 *
1471
 * @param array  $attr {
1472
 *     Attributes of the caption shortcode.
1473
 *
1474
 *     @type string $id      ID of the div element for the caption.
1475
 *     @type string $align   Class name that aligns the caption. Default 'alignnone'. Accepts 'alignleft',
1476
 *                           'aligncenter', alignright', 'alignnone'.
1477
 *     @type int    $width   The width of the caption, in pixels.
1478
 *     @type string $caption The caption text.
1479
 *     @type string $class   Additional class name(s) added to the caption container.
1480
 * }
1481
 * @param string $content Shortcode content.
1482
 * @return string HTML content to display the caption.
1483
 */
1484
function img_caption_shortcode( $attr, $content = null ) {
1485
	// New-style shortcode with the caption inside the shortcode with the link and image tags.
1486
	if ( ! isset( $attr['caption'] ) ) {
1487
		if ( preg_match( '#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches ) ) {
1488
			$content = $matches[1];
1489
			$attr['caption'] = trim( $matches[2] );
1490
		}
1491
	} elseif ( strpos( $attr['caption'], '<' ) !== false ) {
1492
		$attr['caption'] = wp_kses( $attr['caption'], 'post' );
0 ignored issues
show
Documentation introduced by
'post' is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1493
	}
1494
1495
	/**
1496
	 * Filters the default caption shortcode output.
1497
	 *
1498
	 * If the filtered output isn't empty, it will be used instead of generating
1499
	 * the default caption template.
1500
	 *
1501
	 * @since 2.6.0
1502
	 *
1503
	 * @see img_caption_shortcode()
1504
	 *
1505
	 * @param string $output  The caption output. Default empty.
1506
	 * @param array  $attr    Attributes of the caption shortcode.
1507
	 * @param string $content The image element, possibly wrapped in a hyperlink.
1508
	 */
1509
	$output = apply_filters( 'img_caption_shortcode', '', $attr, $content );
1510
	if ( $output != '' )
1511
		return $output;
1512
1513
	$atts = shortcode_atts( array(
1514
		'id'	  => '',
1515
		'align'	  => 'alignnone',
1516
		'width'	  => '',
1517
		'caption' => '',
1518
		'class'   => '',
1519
	), $attr, 'caption' );
1520
1521
	$atts['width'] = (int) $atts['width'];
1522
	if ( $atts['width'] < 1 || empty( $atts['caption'] ) )
1523
		return $content;
1524
1525 View Code Duplication
	if ( ! empty( $atts['id'] ) )
1526
		$atts['id'] = 'id="' . esc_attr( sanitize_html_class( $atts['id'] ) ) . '" ';
1527
1528
	$class = trim( 'wp-caption ' . $atts['align'] . ' ' . $atts['class'] );
1529
1530
	$html5 = current_theme_supports( 'html5', 'caption' );
1531
	// HTML5 captions never added the extra 10px to the image width
1532
	$width = $html5 ? $atts['width'] : ( 10 + $atts['width'] );
1533
1534
	/**
1535
	 * Filters the width of an image's caption.
1536
	 *
1537
	 * By default, the caption is 10 pixels greater than the width of the image,
1538
	 * to prevent post content from running up against a floated image.
1539
	 *
1540
	 * @since 3.7.0
1541
	 *
1542
	 * @see img_caption_shortcode()
1543
	 *
1544
	 * @param int    $width    Width of the caption in pixels. To remove this inline style,
1545
	 *                         return zero.
1546
	 * @param array  $atts     Attributes of the caption shortcode.
1547
	 * @param string $content  The image element, possibly wrapped in a hyperlink.
1548
	 */
1549
	$caption_width = apply_filters( 'img_caption_shortcode_width', $width, $atts, $content );
1550
1551
	$style = '';
1552
	if ( $caption_width )
1553
		$style = 'style="width: ' . (int) $caption_width . 'px" ';
1554
1555
	$html = '';
0 ignored issues
show
Unused Code introduced by
$html is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1556
	if ( $html5 ) {
1557
		$html = '<figure ' . $atts['id'] . $style . 'class="' . esc_attr( $class ) . '">'
1558
		. do_shortcode( $content ) . '<figcaption class="wp-caption-text">' . $atts['caption'] . '</figcaption></figure>';
1559
	} else {
1560
		$html = '<div ' . $atts['id'] . $style . 'class="' . esc_attr( $class ) . '">'
1561
		. do_shortcode( $content ) . '<p class="wp-caption-text">' . $atts['caption'] . '</p></div>';
1562
	}
1563
1564
	return $html;
1565
}
1566
1567
add_shortcode('gallery', 'gallery_shortcode');
1568
1569
/**
1570
 * Builds the Gallery shortcode output.
1571
 *
1572
 * This implements the functionality of the Gallery Shortcode for displaying
1573
 * WordPress images on a post.
1574
 *
1575
 * @since 2.5.0
1576
 *
1577
 * @staticvar int $instance
1578
 *
1579
 * @param array $attr {
1580
 *     Attributes of the gallery shortcode.
1581
 *
1582
 *     @type string       $order      Order of the images in the gallery. Default 'ASC'. Accepts 'ASC', 'DESC'.
1583
 *     @type string       $orderby    The field to use when ordering the images. Default 'menu_order ID'.
1584
 *                                    Accepts any valid SQL ORDERBY statement.
1585
 *     @type int          $id         Post ID.
1586
 *     @type string       $itemtag    HTML tag to use for each image in the gallery.
1587
 *                                    Default 'dl', or 'figure' when the theme registers HTML5 gallery support.
1588
 *     @type string       $icontag    HTML tag to use for each image's icon.
1589
 *                                    Default 'dt', or 'div' when the theme registers HTML5 gallery support.
1590
 *     @type string       $captiontag HTML tag to use for each image's caption.
1591
 *                                    Default 'dd', or 'figcaption' when the theme registers HTML5 gallery support.
1592
 *     @type int          $columns    Number of columns of images to display. Default 3.
1593
 *     @type string|array $size       Size of the images to display. Accepts any valid image size, or an array of width
1594
 *                                    and height values in pixels (in that order). Default 'thumbnail'.
1595
 *     @type string       $ids        A comma-separated list of IDs of attachments to display. Default empty.
1596
 *     @type string       $include    A comma-separated list of IDs of attachments to include. Default empty.
1597
 *     @type string       $exclude    A comma-separated list of IDs of attachments to exclude. Default empty.
1598
 *     @type string       $link       What to link each image to. Default empty (links to the attachment page).
1599
 *                                    Accepts 'file', 'none'.
1600
 * }
1601
 * @return string HTML content to display gallery.
1602
 */
1603
function gallery_shortcode( $attr ) {
1604
	$post = get_post();
1605
1606
	static $instance = 0;
1607
	$instance++;
1608
1609 View Code Duplication
	if ( ! empty( $attr['ids'] ) ) {
1610
		// 'ids' is explicitly ordered, unless you specify otherwise.
1611
		if ( empty( $attr['orderby'] ) ) {
1612
			$attr['orderby'] = 'post__in';
1613
		}
1614
		$attr['include'] = $attr['ids'];
1615
	}
1616
1617
	/**
1618
	 * Filters the default gallery shortcode output.
1619
	 *
1620
	 * If the filtered output isn't empty, it will be used instead of generating
1621
	 * the default gallery template.
1622
	 *
1623
	 * @since 2.5.0
1624
	 * @since 4.2.0 The `$instance` parameter was added.
1625
	 *
1626
	 * @see gallery_shortcode()
1627
	 *
1628
	 * @param string $output   The gallery output. Default empty.
1629
	 * @param array  $attr     Attributes of the gallery shortcode.
1630
	 * @param int    $instance Unique numeric ID of this gallery shortcode instance.
1631
	 */
1632
	$output = apply_filters( 'post_gallery', '', $attr, $instance );
1633
	if ( $output != '' ) {
1634
		return $output;
1635
	}
1636
1637
	$html5 = current_theme_supports( 'html5', 'gallery' );
1638
	$atts = shortcode_atts( array(
1639
		'order'      => 'ASC',
1640
		'orderby'    => 'menu_order ID',
1641
		'id'         => $post ? $post->ID : 0,
1642
		'itemtag'    => $html5 ? 'figure'     : 'dl',
1643
		'icontag'    => $html5 ? 'div'        : 'dt',
1644
		'captiontag' => $html5 ? 'figcaption' : 'dd',
1645
		'columns'    => 3,
1646
		'size'       => 'thumbnail',
1647
		'include'    => '',
1648
		'exclude'    => '',
1649
		'link'       => ''
1650
	), $attr, 'gallery' );
1651
1652
	$id = intval( $atts['id'] );
1653
1654
	if ( ! empty( $atts['include'] ) ) {
1655
		$_attachments = get_posts( array( 'include' => $atts['include'], 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
1656
1657
		$attachments = array();
1658
		foreach ( $_attachments as $key => $val ) {
1659
			$attachments[$val->ID] = $_attachments[$key];
1660
		}
1661
	} elseif ( ! empty( $atts['exclude'] ) ) {
1662
		$attachments = get_children( array( 'post_parent' => $id, 'exclude' => $atts['exclude'], 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
1663
	} else {
1664
		$attachments = get_children( array( 'post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
1665
	}
1666
1667
	if ( empty( $attachments ) ) {
1668
		return '';
1669
	}
1670
1671 View Code Duplication
	if ( is_feed() ) {
1672
		$output = "\n";
1673
		foreach ( $attachments as $att_id => $attachment ) {
1674
			$output .= wp_get_attachment_link( $att_id, $atts['size'], true ) . "\n";
1675
		}
1676
		return $output;
1677
	}
1678
1679
	$itemtag = tag_escape( $atts['itemtag'] );
1680
	$captiontag = tag_escape( $atts['captiontag'] );
1681
	$icontag = tag_escape( $atts['icontag'] );
1682
	$valid_tags = wp_kses_allowed_html( 'post' );
1683
	if ( ! isset( $valid_tags[ $itemtag ] ) ) {
1684
		$itemtag = 'dl';
1685
	}
1686
	if ( ! isset( $valid_tags[ $captiontag ] ) ) {
1687
		$captiontag = 'dd';
1688
	}
1689
	if ( ! isset( $valid_tags[ $icontag ] ) ) {
1690
		$icontag = 'dt';
1691
	}
1692
1693
	$columns = intval( $atts['columns'] );
1694
	$itemwidth = $columns > 0 ? floor(100/$columns) : 100;
1695
	$float = is_rtl() ? 'right' : 'left';
1696
1697
	$selector = "gallery-{$instance}";
1698
1699
	$gallery_style = '';
1700
1701
	/**
1702
	 * Filters whether to print default gallery styles.
1703
	 *
1704
	 * @since 3.1.0
1705
	 *
1706
	 * @param bool $print Whether to print default gallery styles.
1707
	 *                    Defaults to false if the theme supports HTML5 galleries.
1708
	 *                    Otherwise, defaults to true.
1709
	 */
1710
	if ( apply_filters( 'use_default_gallery_style', ! $html5 ) ) {
1711
		$gallery_style = "
1712
		<style type='text/css'>
1713
			#{$selector} {
1714
				margin: auto;
1715
			}
1716
			#{$selector} .gallery-item {
1717
				float: {$float};
1718
				margin-top: 10px;
1719
				text-align: center;
1720
				width: {$itemwidth}%;
1721
			}
1722
			#{$selector} img {
1723
				border: 2px solid #cfcfcf;
1724
			}
1725
			#{$selector} .gallery-caption {
1726
				margin-left: 0;
1727
			}
1728
			/* see gallery_shortcode() in wp-includes/media.php */
1729
		</style>\n\t\t";
1730
	}
1731
1732
	$size_class = sanitize_html_class( $atts['size'] );
1733
	$gallery_div = "<div id='$selector' class='gallery galleryid-{$id} gallery-columns-{$columns} gallery-size-{$size_class}'>";
1734
1735
	/**
1736
	 * Filters the default gallery shortcode CSS styles.
1737
	 *
1738
	 * @since 2.5.0
1739
	 *
1740
	 * @param string $gallery_style Default CSS styles and opening HTML div container
1741
	 *                              for the gallery shortcode output.
1742
	 */
1743
	$output = apply_filters( 'gallery_style', $gallery_style . $gallery_div );
1744
1745
	$i = 0;
1746
	foreach ( $attachments as $id => $attachment ) {
1747
1748
		$attr = ( trim( $attachment->post_excerpt ) ) ? array( 'aria-describedby' => "$selector-$id" ) : '';
1749
		if ( ! empty( $atts['link'] ) && 'file' === $atts['link'] ) {
1750
			$image_output = wp_get_attachment_link( $id, $atts['size'], false, false, false, $attr );
1751
		} elseif ( ! empty( $atts['link'] ) && 'none' === $atts['link'] ) {
1752
			$image_output = wp_get_attachment_image( $id, $atts['size'], false, $attr );
1753
		} else {
1754
			$image_output = wp_get_attachment_link( $id, $atts['size'], true, false, false, $attr );
1755
		}
1756
		$image_meta  = wp_get_attachment_metadata( $id );
1757
1758
		$orientation = '';
1759
		if ( isset( $image_meta['height'], $image_meta['width'] ) ) {
1760
			$orientation = ( $image_meta['height'] > $image_meta['width'] ) ? 'portrait' : 'landscape';
1761
		}
1762
		$output .= "<{$itemtag} class='gallery-item'>";
1763
		$output .= "
1764
			<{$icontag} class='gallery-icon {$orientation}'>
1765
				$image_output
1766
			</{$icontag}>";
1767
		if ( $captiontag && trim($attachment->post_excerpt) ) {
1768
			$output .= "
1769
				<{$captiontag} class='wp-caption-text gallery-caption' id='$selector-$id'>
1770
				" . wptexturize($attachment->post_excerpt) . "
1771
				</{$captiontag}>";
1772
		}
1773
		$output .= "</{$itemtag}>";
1774 View Code Duplication
		if ( ! $html5 && $columns > 0 && ++$i % $columns == 0 ) {
1775
			$output .= '<br style="clear: both" />';
1776
		}
1777
	}
1778
1779 View Code Duplication
	if ( ! $html5 && $columns > 0 && $i % $columns !== 0 ) {
1780
		$output .= "
1781
			<br style='clear: both' />";
1782
	}
1783
1784
	$output .= "
1785
		</div>\n";
1786
1787
	return $output;
1788
}
1789
1790
/**
1791
 * Outputs the templates used by playlists.
1792
 *
1793
 * @since 3.9.0
1794
 */
1795
function wp_underscore_playlist_templates() {
1796
?>
1797
<script type="text/html" id="tmpl-wp-playlist-current-item">
1798
	<# if ( data.image ) { #>
1799
	<img src="{{ data.thumb.src }}" alt="" />
1800
	<# } #>
1801
	<div class="wp-playlist-caption">
1802
		<span class="wp-playlist-item-meta wp-playlist-item-title"><?php
1803
			/* translators: playlist item title */
1804
			printf( _x( '&#8220;%s&#8221;', 'playlist item title' ), '{{ data.title }}' );
1805
		?></span>
1806
		<# if ( data.meta.album ) { #><span class="wp-playlist-item-meta wp-playlist-item-album">{{ data.meta.album }}</span><# } #>
1807
		<# if ( data.meta.artist ) { #><span class="wp-playlist-item-meta wp-playlist-item-artist">{{ data.meta.artist }}</span><# } #>
1808
	</div>
1809
</script>
1810
<script type="text/html" id="tmpl-wp-playlist-item">
1811
	<div class="wp-playlist-item">
1812
		<a class="wp-playlist-caption" href="{{ data.src }}">
1813
			{{ data.index ? ( data.index + '. ' ) : '' }}
1814
			<# if ( data.caption ) { #>
1815
				{{ data.caption }}
1816
			<# } else { #>
1817
				<span class="wp-playlist-item-title"><?php
1818
					/* translators: playlist item title */
1819
					printf( _x( '&#8220;%s&#8221;', 'playlist item title' ), '{{{ data.title }}}' );
1820
				?></span>
1821
				<# if ( data.artists && data.meta.artist ) { #>
1822
				<span class="wp-playlist-item-artist"> &mdash; {{ data.meta.artist }}</span>
1823
				<# } #>
1824
			<# } #>
1825
		</a>
1826
		<# if ( data.meta.length_formatted ) { #>
1827
		<div class="wp-playlist-item-length">{{ data.meta.length_formatted }}</div>
1828
		<# } #>
1829
	</div>
1830
</script>
1831
<?php
1832
}
1833
1834
/**
1835
 * Outputs and enqueue default scripts and styles for playlists.
1836
 *
1837
 * @since 3.9.0
1838
 *
1839
 * @param string $type Type of playlist. Accepts 'audio' or 'video'.
1840
 */
1841
function wp_playlist_scripts( $type ) {
1842
	wp_enqueue_style( 'wp-mediaelement' );
1843
	wp_enqueue_script( 'wp-playlist' );
1844
?>
1845
<!--[if lt IE 9]><script>document.createElement('<?php echo esc_js( $type ) ?>');</script><![endif]-->
1846
<?php
1847
	add_action( 'wp_footer', 'wp_underscore_playlist_templates', 0 );
1848
	add_action( 'admin_footer', 'wp_underscore_playlist_templates', 0 );
1849
}
1850
1851
/**
1852
 * Builds the Playlist shortcode output.
1853
 *
1854
 * This implements the functionality of the playlist shortcode for displaying
1855
 * a collection of WordPress audio or video files in a post.
1856
 *
1857
 * @since 3.9.0
1858
 *
1859
 * @global int $content_width
1860
 * @staticvar int $instance
1861
 *
1862
 * @param array $attr {
1863
 *     Array of default playlist attributes.
1864
 *
1865
 *     @type string  $type         Type of playlist to display. Accepts 'audio' or 'video'. Default 'audio'.
1866
 *     @type string  $order        Designates ascending or descending order of items in the playlist.
1867
 *                                 Accepts 'ASC', 'DESC'. Default 'ASC'.
1868
 *     @type string  $orderby      Any column, or columns, to sort the playlist. If $ids are
1869
 *                                 passed, this defaults to the order of the $ids array ('post__in').
1870
 *                                 Otherwise default is 'menu_order ID'.
1871
 *     @type int     $id           If an explicit $ids array is not present, this parameter
1872
 *                                 will determine which attachments are used for the playlist.
1873
 *                                 Default is the current post ID.
1874
 *     @type array   $ids          Create a playlist out of these explicit attachment IDs. If empty,
1875
 *                                 a playlist will be created from all $type attachments of $id.
1876
 *                                 Default empty.
1877
 *     @type array   $exclude      List of specific attachment IDs to exclude from the playlist. Default empty.
1878
 *     @type string  $style        Playlist style to use. Accepts 'light' or 'dark'. Default 'light'.
1879
 *     @type bool    $tracklist    Whether to show or hide the playlist. Default true.
1880
 *     @type bool    $tracknumbers Whether to show or hide the numbers next to entries in the playlist. Default true.
1881
 *     @type bool    $images       Show or hide the video or audio thumbnail (Featured Image/post
1882
 *                                 thumbnail). Default true.
1883
 *     @type bool    $artists      Whether to show or hide artist name in the playlist. Default true.
1884
 * }
1885
 *
1886
 * @return string Playlist output. Empty string if the passed type is unsupported.
1887
 */
1888
function wp_playlist_shortcode( $attr ) {
1889
	global $content_width;
1890
	$post = get_post();
1891
1892
	static $instance = 0;
1893
	$instance++;
1894
1895 View Code Duplication
	if ( ! empty( $attr['ids'] ) ) {
1896
		// 'ids' is explicitly ordered, unless you specify otherwise.
1897
		if ( empty( $attr['orderby'] ) ) {
1898
			$attr['orderby'] = 'post__in';
1899
		}
1900
		$attr['include'] = $attr['ids'];
1901
	}
1902
1903
	/**
1904
	 * Filters the playlist output.
1905
	 *
1906
	 * Passing a non-empty value to the filter will short-circuit generation
1907
	 * of the default playlist output, returning the passed value instead.
1908
	 *
1909
	 * @since 3.9.0
1910
	 * @since 4.2.0 The `$instance` parameter was added.
1911
	 *
1912
	 * @param string $output   Playlist output. Default empty.
1913
	 * @param array  $attr     An array of shortcode attributes.
1914
	 * @param int    $instance Unique numeric ID of this playlist shortcode instance.
1915
	 */
1916
	$output = apply_filters( 'post_playlist', '', $attr, $instance );
1917
	if ( $output != '' ) {
1918
		return $output;
1919
	}
1920
1921
	$atts = shortcode_atts( array(
1922
		'type'		=> 'audio',
1923
		'order'		=> 'ASC',
1924
		'orderby'	=> 'menu_order ID',
1925
		'id'		=> $post ? $post->ID : 0,
1926
		'include'	=> '',
1927
		'exclude'   => '',
1928
		'style'		=> 'light',
1929
		'tracklist' => true,
1930
		'tracknumbers' => true,
1931
		'images'	=> true,
1932
		'artists'	=> true
1933
	), $attr, 'playlist' );
1934
1935
	$id = intval( $atts['id'] );
1936
1937
	if ( $atts['type'] !== 'audio' ) {
1938
		$atts['type'] = 'video';
1939
	}
1940
1941
	$args = array(
1942
		'post_status' => 'inherit',
1943
		'post_type' => 'attachment',
1944
		'post_mime_type' => $atts['type'],
1945
		'order' => $atts['order'],
1946
		'orderby' => $atts['orderby']
1947
	);
1948
1949
	if ( ! empty( $atts['include'] ) ) {
1950
		$args['include'] = $atts['include'];
1951
		$_attachments = get_posts( $args );
1952
1953
		$attachments = array();
1954
		foreach ( $_attachments as $key => $val ) {
1955
			$attachments[$val->ID] = $_attachments[$key];
1956
		}
1957
	} elseif ( ! empty( $atts['exclude'] ) ) {
1958
		$args['post_parent'] = $id;
1959
		$args['exclude'] = $atts['exclude'];
1960
		$attachments = get_children( $args );
1961
	} else {
1962
		$args['post_parent'] = $id;
1963
		$attachments = get_children( $args );
1964
	}
1965
1966
	if ( empty( $attachments ) ) {
1967
		return '';
1968
	}
1969
1970 View Code Duplication
	if ( is_feed() ) {
1971
		$output = "\n";
1972
		foreach ( $attachments as $att_id => $attachment ) {
1973
			$output .= wp_get_attachment_link( $att_id ) . "\n";
1974
		}
1975
		return $output;
1976
	}
1977
1978
	$outer = 22; // default padding and border of wrapper
1979
1980
	$default_width = 640;
1981
	$default_height = 360;
1982
1983
	$theme_width = empty( $content_width ) ? $default_width : ( $content_width - $outer );
1984
	$theme_height = empty( $content_width ) ? $default_height : round( ( $default_height * $theme_width ) / $default_width );
1985
1986
	$data = array(
1987
		'type' => $atts['type'],
1988
		// don't pass strings to JSON, will be truthy in JS
1989
		'tracklist' => wp_validate_boolean( $atts['tracklist'] ),
1990
		'tracknumbers' => wp_validate_boolean( $atts['tracknumbers'] ),
1991
		'images' => wp_validate_boolean( $atts['images'] ),
1992
		'artists' => wp_validate_boolean( $atts['artists'] ),
1993
	);
1994
1995
	$tracks = array();
1996
	foreach ( $attachments as $attachment ) {
1997
		$url = wp_get_attachment_url( $attachment->ID );
1998
		$ftype = wp_check_filetype( $url, wp_get_mime_types() );
0 ignored issues
show
Security Bug introduced by
It seems like $url defined by wp_get_attachment_url($attachment->ID) on line 1997 can also be of type false; however, wp_check_filetype() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1999
		$track = array(
2000
			'src' => $url,
2001
			'type' => $ftype['type'],
2002
			'title' => $attachment->post_title,
2003
			'caption' => $attachment->post_excerpt,
2004
			'description' => $attachment->post_content
2005
		);
2006
2007
		$track['meta'] = array();
2008
		$meta = wp_get_attachment_metadata( $attachment->ID );
2009
		if ( ! empty( $meta ) ) {
2010
2011
			foreach ( wp_get_attachment_id3_keys( $attachment ) as $key => $label ) {
2012
				if ( ! empty( $meta[ $key ] ) ) {
2013
					$track['meta'][ $key ] = $meta[ $key ];
2014
				}
2015
			}
2016
2017
			if ( 'video' === $atts['type'] ) {
2018
				if ( ! empty( $meta['width'] ) && ! empty( $meta['height'] ) ) {
2019
					$width = $meta['width'];
2020
					$height = $meta['height'];
2021
					$theme_height = round( ( $height * $theme_width ) / $width );
2022
				} else {
2023
					$width = $default_width;
2024
					$height = $default_height;
2025
				}
2026
2027
				$track['dimensions'] = array(
2028
					'original' => compact( 'width', 'height' ),
2029
					'resized' => array(
2030
						'width' => $theme_width,
2031
						'height' => $theme_height
2032
					)
2033
				);
2034
			}
2035
		}
2036
2037
		if ( $atts['images'] ) {
2038
			$thumb_id = get_post_thumbnail_id( $attachment->ID );
2039 View Code Duplication
			if ( ! empty( $thumb_id ) ) {
2040
				list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'full' );
2041
				$track['image'] = compact( 'src', 'width', 'height' );
2042
				list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'thumbnail' );
2043
				$track['thumb'] = compact( 'src', 'width', 'height' );
2044
			} else {
2045
				$src = wp_mime_type_icon( $attachment->ID );
2046
				$width = 48;
2047
				$height = 64;
2048
				$track['image'] = compact( 'src', 'width', 'height' );
2049
				$track['thumb'] = compact( 'src', 'width', 'height' );
2050
			}
2051
		}
2052
2053
		$tracks[] = $track;
2054
	}
2055
	$data['tracks'] = $tracks;
2056
2057
	$safe_type = esc_attr( $atts['type'] );
2058
	$safe_style = esc_attr( $atts['style'] );
2059
2060
	ob_start();
2061
2062
	if ( 1 === $instance ) {
2063
		/**
2064
		 * Prints and enqueues playlist scripts, styles, and JavaScript templates.
2065
		 *
2066
		 * @since 3.9.0
2067
		 *
2068
		 * @param string $type  Type of playlist. Possible values are 'audio' or 'video'.
2069
		 * @param string $style The 'theme' for the playlist. Core provides 'light' and 'dark'.
2070
		 */
2071
		do_action( 'wp_playlist_scripts', $atts['type'], $atts['style'] );
2072
	} ?>
2073
<div class="wp-playlist wp-<?php echo $safe_type ?>-playlist wp-playlist-<?php echo $safe_style ?>">
2074
	<?php if ( 'audio' === $atts['type'] ): ?>
2075
	<div class="wp-playlist-current-item"></div>
2076
	<?php endif ?>
2077
	<<?php echo $safe_type ?> controls="controls" preload="none" width="<?php
2078
		echo (int) $theme_width;
2079
	?>"<?php if ( 'video' === $safe_type ):
2080
		echo ' height="', (int) $theme_height, '"';
2081
	endif; ?>></<?php echo $safe_type ?>>
2082
	<div class="wp-playlist-next"></div>
2083
	<div class="wp-playlist-prev"></div>
2084
	<noscript>
2085
	<ol><?php
2086
	foreach ( $attachments as $att_id => $attachment ) {
2087
		printf( '<li>%s</li>', wp_get_attachment_link( $att_id ) );
2088
	}
2089
	?></ol>
2090
	</noscript>
2091
	<script type="application/json" class="wp-playlist-script"><?php echo wp_json_encode( $data ) ?></script>
2092
</div>
2093
	<?php
2094
	return ob_get_clean();
2095
}
2096
add_shortcode( 'playlist', 'wp_playlist_shortcode' );
2097
2098
/**
2099
 * Provides a No-JS Flash fallback as a last resort for audio / video.
2100
 *
2101
 * @since 3.6.0
2102
 *
2103
 * @param string $url The media element URL.
2104
 * @return string Fallback HTML.
2105
 */
2106
function wp_mediaelement_fallback( $url ) {
2107
	/**
2108
	 * Filters the Mediaelement fallback output for no-JS.
2109
	 *
2110
	 * @since 3.6.0
2111
	 *
2112
	 * @param string $output Fallback output for no-JS.
2113
	 * @param string $url    Media file URL.
2114
	 */
2115
	return apply_filters( 'wp_mediaelement_fallback', sprintf( '<a href="%1$s">%1$s</a>', esc_url( $url ) ), $url );
2116
}
2117
2118
/**
2119
 * Returns a filtered list of WP-supported audio formats.
2120
 *
2121
 * @since 3.6.0
2122
 *
2123
 * @return array Supported audio formats.
2124
 */
2125
function wp_get_audio_extensions() {
2126
	/**
2127
	 * Filters the list of supported audio formats.
2128
	 *
2129
	 * @since 3.6.0
2130
	 *
2131
	 * @param array $extensions An array of support audio formats. Defaults are
2132
	 *                          'mp3', 'ogg', 'wma', 'm4a', 'wav'.
2133
	 */
2134
	return apply_filters( 'wp_audio_extensions', array( 'mp3', 'ogg', 'wma', 'm4a', 'wav' ) );
2135
}
2136
2137
/**
2138
 * Returns useful keys to use to lookup data from an attachment's stored metadata.
2139
 *
2140
 * @since 3.9.0
2141
 *
2142
 * @param WP_Post $attachment The current attachment, provided for context.
2143
 * @param string  $context    Optional. The context. Accepts 'edit', 'display'. Default 'display'.
2144
 * @return array Key/value pairs of field keys to labels.
2145
 */
2146
function wp_get_attachment_id3_keys( $attachment, $context = 'display' ) {
2147
	$fields = array(
2148
		'artist' => __( 'Artist' ),
2149
		'album' => __( 'Album' ),
2150
	);
2151
2152
	if ( 'display' === $context ) {
2153
		$fields['genre']            = __( 'Genre' );
2154
		$fields['year']             = __( 'Year' );
2155
		$fields['length_formatted'] = _x( 'Length', 'video or audio' );
2156
	} elseif ( 'js' === $context ) {
2157
		$fields['bitrate']          = __( 'Bitrate' );
2158
		$fields['bitrate_mode']     = __( 'Bitrate Mode' );
2159
	}
2160
2161
	/**
2162
	 * Filters the editable list of keys to look up data from an attachment's metadata.
2163
	 *
2164
	 * @since 3.9.0
2165
	 *
2166
	 * @param array   $fields     Key/value pairs of field keys to labels.
2167
	 * @param WP_Post $attachment Attachment object.
2168
	 * @param string  $context    The context. Accepts 'edit', 'display'. Default 'display'.
2169
	 */
2170
	return apply_filters( 'wp_get_attachment_id3_keys', $fields, $attachment, $context );
2171
}
2172
/**
2173
 * Builds the Audio shortcode output.
2174
 *
2175
 * This implements the functionality of the Audio Shortcode for displaying
2176
 * WordPress mp3s in a post.
2177
 *
2178
 * @since 3.6.0
2179
 *
2180
 * @staticvar int $instance
2181
 *
2182
 * @param array  $attr {
2183
 *     Attributes of the audio shortcode.
2184
 *
2185
 *     @type string $src      URL to the source of the audio file. Default empty.
2186
 *     @type string $loop     The 'loop' attribute for the `<audio>` element. Default empty.
2187
 *     @type string $autoplay The 'autoplay' attribute for the `<audio>` element. Default empty.
2188
 *     @type string $preload  The 'preload' attribute for the `<audio>` element. Default 'none'.
2189
 *     @type string $class    The 'class' attribute for the `<audio>` element. Default 'wp-audio-shortcode'.
2190
 *     @type string $style    The 'style' attribute for the `<audio>` element. Default 'width: 100%;'.
2191
 * }
2192
 * @param string $content Shortcode content.
2193
 * @return string|void HTML content to display audio.
2194
 */
2195
function wp_audio_shortcode( $attr, $content = '' ) {
2196
	$post_id = get_post() ? get_the_ID() : 0;
2197
2198
	static $instance = 0;
2199
	$instance++;
2200
2201
	/**
2202
	 * Filters the default audio shortcode output.
2203
	 *
2204
	 * If the filtered output isn't empty, it will be used instead of generating the default audio template.
2205
	 *
2206
	 * @since 3.6.0
2207
	 *
2208
	 * @param string $html     Empty variable to be replaced with shortcode markup.
2209
	 * @param array  $attr     Attributes of the shortcode. @see wp_audio_shortcode()
2210
	 * @param string $content  Shortcode content.
2211
	 * @param int    $instance Unique numeric ID of this audio shortcode instance.
2212
	 */
2213
	$override = apply_filters( 'wp_audio_shortcode_override', '', $attr, $content, $instance );
2214
	if ( '' !== $override ) {
2215
		return $override;
2216
	}
2217
2218
	$audio = null;
2219
2220
	$default_types = wp_get_audio_extensions();
2221
	$defaults_atts = array(
2222
		'src'      => '',
2223
		'loop'     => '',
2224
		'autoplay' => '',
2225
		'preload'  => 'none',
2226
		'class'    => 'wp-audio-shortcode',
2227
		'style'    => 'width: 100%;'
2228
	);
2229
	foreach ( $default_types as $type ) {
2230
		$defaults_atts[$type] = '';
2231
	}
2232
2233
	$atts = shortcode_atts( $defaults_atts, $attr, 'audio' );
2234
2235
	$primary = false;
2236
	if ( ! empty( $atts['src'] ) ) {
2237
		$type = wp_check_filetype( $atts['src'], wp_get_mime_types() );
2238 View Code Duplication
		if ( ! in_array( strtolower( $type['ext'] ), $default_types ) ) {
2239
			return sprintf( '<a class="wp-embedded-audio" href="%s">%s</a>', esc_url( $atts['src'] ), esc_html( $atts['src'] ) );
2240
		}
2241
		$primary = true;
2242
		array_unshift( $default_types, 'src' );
2243 View Code Duplication
	} else {
2244
		foreach ( $default_types as $ext ) {
2245
			if ( ! empty( $atts[ $ext ] ) ) {
2246
				$type = wp_check_filetype( $atts[ $ext ], wp_get_mime_types() );
2247
				if ( strtolower( $type['ext'] ) === $ext ) {
2248
					$primary = true;
2249
				}
2250
			}
2251
		}
2252
	}
2253
2254 View Code Duplication
	if ( ! $primary ) {
2255
		$audios = get_attached_media( 'audio', $post_id );
2256
		if ( empty( $audios ) ) {
2257
			return;
2258
		}
2259
2260
		$audio = reset( $audios );
2261
		$atts['src'] = wp_get_attachment_url( $audio->ID );
2262
		if ( empty( $atts['src'] ) ) {
2263
			return;
2264
		}
2265
2266
		array_unshift( $default_types, 'src' );
2267
	}
2268
2269
	/**
2270
	 * Filters the media library used for the audio shortcode.
2271
	 *
2272
	 * @since 3.6.0
2273
	 *
2274
	 * @param string $library Media library used for the audio shortcode.
2275
	 */
2276
	$library = apply_filters( 'wp_audio_shortcode_library', 'mediaelement' );
2277
	if ( 'mediaelement' === $library && did_action( 'init' ) ) {
2278
		wp_enqueue_style( 'wp-mediaelement' );
2279
		wp_enqueue_script( 'wp-mediaelement' );
2280
	}
2281
2282
	/**
2283
	 * Filters the class attribute for the audio shortcode output container.
2284
	 *
2285
	 * @since 3.6.0
2286
	 *
2287
	 * @param string $class CSS class or list of space-separated classes.
2288
	 */
2289
	$atts['class'] = apply_filters( 'wp_audio_shortcode_class', $atts['class'] );
2290
2291
	$html_atts = array(
2292
		'class'    => $atts['class'],
2293
		'id'       => sprintf( 'audio-%d-%d', $post_id, $instance ),
2294
		'loop'     => wp_validate_boolean( $atts['loop'] ),
2295
		'autoplay' => wp_validate_boolean( $atts['autoplay'] ),
2296
		'preload'  => $atts['preload'],
2297
		'style'    => $atts['style'],
2298
	);
2299
2300
	// These ones should just be omitted altogether if they are blank
2301 View Code Duplication
	foreach ( array( 'loop', 'autoplay', 'preload' ) as $a ) {
2302
		if ( empty( $html_atts[$a] ) ) {
2303
			unset( $html_atts[$a] );
2304
		}
2305
	}
2306
2307
	$attr_strings = array();
2308 View Code Duplication
	foreach ( $html_atts as $k => $v ) {
2309
		$attr_strings[] = $k . '="' . esc_attr( $v ) . '"';
2310
	}
2311
2312
	$html = '';
2313
	if ( 'mediaelement' === $library && 1 === $instance ) {
2314
		$html .= "<!--[if lt IE 9]><script>document.createElement('audio');</script><![endif]-->\n";
2315
	}
2316
	$html .= sprintf( '<audio %s controls="controls">', join( ' ', $attr_strings ) );
2317
2318
	$fileurl = '';
2319
	$source = '<source type="%s" src="%s" />';
2320
	foreach ( $default_types as $fallback ) {
2321
		if ( ! empty( $atts[ $fallback ] ) ) {
2322
			if ( empty( $fileurl ) ) {
2323
				$fileurl = $atts[ $fallback ];
2324
			}
2325
			$type = wp_check_filetype( $atts[ $fallback ], wp_get_mime_types() );
2326
			$url = add_query_arg( '_', $instance, $atts[ $fallback ] );
2327
			$html .= sprintf( $source, $type['type'], esc_url( $url ) );
2328
		}
2329
	}
2330
2331
	if ( 'mediaelement' === $library ) {
2332
		$html .= wp_mediaelement_fallback( $fileurl );
2333
	}
2334
	$html .= '</audio>';
2335
2336
	/**
2337
	 * Filters the audio shortcode output.
2338
	 *
2339
	 * @since 3.6.0
2340
	 *
2341
	 * @param string $html    Audio shortcode HTML output.
2342
	 * @param array  $atts    Array of audio shortcode attributes.
2343
	 * @param string $audio   Audio file.
2344
	 * @param int    $post_id Post ID.
2345
	 * @param string $library Media library used for the audio shortcode.
2346
	 */
2347
	return apply_filters( 'wp_audio_shortcode', $html, $atts, $audio, $post_id, $library );
2348
}
2349
add_shortcode( 'audio', 'wp_audio_shortcode' );
2350
2351
/**
2352
 * Returns a filtered list of WP-supported video formats.
2353
 *
2354
 * @since 3.6.0
2355
 *
2356
 * @return array List of supported video formats.
2357
 */
2358
function wp_get_video_extensions() {
2359
	/**
2360
	 * Filters the list of supported video formats.
2361
	 *
2362
	 * @since 3.6.0
2363
	 *
2364
	 * @param array $extensions An array of support video formats. Defaults are
2365
	 *                          'mp4', 'm4v', 'webm', 'ogv', 'wmv', 'flv'.
2366
	 */
2367
	return apply_filters( 'wp_video_extensions', array( 'mp4', 'm4v', 'webm', 'ogv', 'wmv', 'flv' ) );
2368
}
2369
2370
/**
2371
 * Builds the Video shortcode output.
2372
 *
2373
 * This implements the functionality of the Video Shortcode for displaying
2374
 * WordPress mp4s in a post.
2375
 *
2376
 * @since 3.6.0
2377
 *
2378
 * @global int $content_width
2379
 * @staticvar int $instance
2380
 *
2381
 * @param array  $attr {
2382
 *     Attributes of the shortcode.
2383
 *
2384
 *     @type string $src      URL to the source of the video file. Default empty.
2385
 *     @type int    $height   Height of the video embed in pixels. Default 360.
2386
 *     @type int    $width    Width of the video embed in pixels. Default $content_width or 640.
2387
 *     @type string $poster   The 'poster' attribute for the `<video>` element. Default empty.
2388
 *     @type string $loop     The 'loop' attribute for the `<video>` element. Default empty.
2389
 *     @type string $autoplay The 'autoplay' attribute for the `<video>` element. Default empty.
2390
 *     @type string $preload  The 'preload' attribute for the `<video>` element.
2391
 *                            Default 'metadata'.
2392
 *     @type string $class    The 'class' attribute for the `<video>` element.
2393
 *                            Default 'wp-video-shortcode'.
2394
 * }
2395
 * @param string $content Shortcode content.
2396
 * @return string|void HTML content to display video.
2397
 */
2398
function wp_video_shortcode( $attr, $content = '' ) {
2399
	global $content_width;
2400
	$post_id = get_post() ? get_the_ID() : 0;
2401
2402
	static $instance = 0;
2403
	$instance++;
2404
2405
	/**
2406
	 * Filters the default video shortcode output.
2407
	 *
2408
	 * If the filtered output isn't empty, it will be used instead of generating
2409
	 * the default video template.
2410
	 *
2411
	 * @since 3.6.0
2412
	 *
2413
	 * @see wp_video_shortcode()
2414
	 *
2415
	 * @param string $html     Empty variable to be replaced with shortcode markup.
2416
	 * @param array  $attr     Attributes of the video shortcode.
2417
	 * @param string $content  Video shortcode content.
2418
	 * @param int    $instance Unique numeric ID of this video shortcode instance.
2419
	 */
2420
	$override = apply_filters( 'wp_video_shortcode_override', '', $attr, $content, $instance );
2421
	if ( '' !== $override ) {
2422
		return $override;
2423
	}
2424
2425
	$video = null;
2426
2427
	$default_types = wp_get_video_extensions();
2428
	$defaults_atts = array(
2429
		'src'      => '',
2430
		'poster'   => '',
2431
		'loop'     => '',
2432
		'autoplay' => '',
2433
		'preload'  => 'metadata',
2434
		'width'    => 640,
2435
		'height'   => 360,
2436
		'class'    => 'wp-video-shortcode',
2437
	);
2438
2439
	foreach ( $default_types as $type ) {
2440
		$defaults_atts[$type] = '';
2441
	}
2442
2443
	$atts = shortcode_atts( $defaults_atts, $attr, 'video' );
2444
2445
	if ( is_admin() ) {
2446
		// shrink the video so it isn't huge in the admin
2447
		if ( $atts['width'] > $defaults_atts['width'] ) {
2448
			$atts['height'] = round( ( $atts['height'] * $defaults_atts['width'] ) / $atts['width'] );
2449
			$atts['width'] = $defaults_atts['width'];
2450
		}
2451
	} else {
2452
		// if the video is bigger than the theme
2453
		if ( ! empty( $content_width ) && $atts['width'] > $content_width ) {
2454
			$atts['height'] = round( ( $atts['height'] * $content_width ) / $atts['width'] );
2455
			$atts['width'] = $content_width;
2456
		}
2457
	}
2458
2459
	$is_vimeo = $is_youtube = false;
2460
	$yt_pattern = '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#';
2461
	$vimeo_pattern = '#^https?://(.+\.)?vimeo\.com/.*#';
2462
2463
	$primary = false;
2464
	if ( ! empty( $atts['src'] ) ) {
2465
		$is_vimeo = ( preg_match( $vimeo_pattern, $atts['src'] ) );
2466
		$is_youtube = (  preg_match( $yt_pattern, $atts['src'] ) );
2467
		if ( ! $is_youtube && ! $is_vimeo ) {
2468
			$type = wp_check_filetype( $atts['src'], wp_get_mime_types() );
2469 View Code Duplication
			if ( ! in_array( strtolower( $type['ext'] ), $default_types ) ) {
2470
				return sprintf( '<a class="wp-embedded-video" href="%s">%s</a>', esc_url( $atts['src'] ), esc_html( $atts['src'] ) );
2471
			}
2472
		}
2473
2474
		if ( $is_vimeo ) {
2475
			wp_enqueue_script( 'froogaloop' );
2476
		}
2477
2478
		$primary = true;
2479
		array_unshift( $default_types, 'src' );
2480 View Code Duplication
	} else {
2481
		foreach ( $default_types as $ext ) {
2482
			if ( ! empty( $atts[ $ext ] ) ) {
2483
				$type = wp_check_filetype( $atts[ $ext ], wp_get_mime_types() );
2484
				if ( strtolower( $type['ext'] ) === $ext ) {
2485
					$primary = true;
2486
				}
2487
			}
2488
		}
2489
	}
2490
2491 View Code Duplication
	if ( ! $primary ) {
2492
		$videos = get_attached_media( 'video', $post_id );
2493
		if ( empty( $videos ) ) {
2494
			return;
2495
		}
2496
2497
		$video = reset( $videos );
2498
		$atts['src'] = wp_get_attachment_url( $video->ID );
2499
		if ( empty( $atts['src'] ) ) {
2500
			return;
2501
		}
2502
2503
		array_unshift( $default_types, 'src' );
2504
	}
2505
2506
	/**
2507
	 * Filters the media library used for the video shortcode.
2508
	 *
2509
	 * @since 3.6.0
2510
	 *
2511
	 * @param string $library Media library used for the video shortcode.
2512
	 */
2513
	$library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' );
2514
	if ( 'mediaelement' === $library && did_action( 'init' ) ) {
2515
		wp_enqueue_style( 'wp-mediaelement' );
2516
		wp_enqueue_script( 'wp-mediaelement' );
2517
	}
2518
2519
	/**
2520
	 * Filters the class attribute for the video shortcode output container.
2521
	 *
2522
	 * @since 3.6.0
2523
	 *
2524
	 * @param string $class CSS class or list of space-separated classes.
2525
	 */
2526
	$atts['class'] = apply_filters( 'wp_video_shortcode_class', $atts['class'] );
2527
2528
	$html_atts = array(
2529
		'class'    => $atts['class'],
2530
		'id'       => sprintf( 'video-%d-%d', $post_id, $instance ),
2531
		'width'    => absint( $atts['width'] ),
2532
		'height'   => absint( $atts['height'] ),
2533
		'poster'   => esc_url( $atts['poster'] ),
2534
		'loop'     => wp_validate_boolean( $atts['loop'] ),
2535
		'autoplay' => wp_validate_boolean( $atts['autoplay'] ),
2536
		'preload'  => $atts['preload'],
2537
	);
2538
2539
	// These ones should just be omitted altogether if they are blank
2540 View Code Duplication
	foreach ( array( 'poster', 'loop', 'autoplay', 'preload' ) as $a ) {
2541
		if ( empty( $html_atts[$a] ) ) {
2542
			unset( $html_atts[$a] );
2543
		}
2544
	}
2545
2546
	$attr_strings = array();
2547 View Code Duplication
	foreach ( $html_atts as $k => $v ) {
2548
		$attr_strings[] = $k . '="' . esc_attr( $v ) . '"';
2549
	}
2550
2551
	$html = '';
2552
	if ( 'mediaelement' === $library && 1 === $instance ) {
2553
		$html .= "<!--[if lt IE 9]><script>document.createElement('video');</script><![endif]-->\n";
2554
	}
2555
	$html .= sprintf( '<video %s controls="controls">', join( ' ', $attr_strings ) );
2556
2557
	$fileurl = '';
2558
	$source = '<source type="%s" src="%s" />';
2559
	foreach ( $default_types as $fallback ) {
2560
		if ( ! empty( $atts[ $fallback ] ) ) {
2561
			if ( empty( $fileurl ) ) {
2562
				$fileurl = $atts[ $fallback ];
2563
			}
2564
			if ( 'src' === $fallback && $is_youtube ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $is_youtube of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2565
				$type = array( 'type' => 'video/youtube' );
2566
			} elseif ( 'src' === $fallback && $is_vimeo ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $is_vimeo of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2567
				$type = array( 'type' => 'video/vimeo' );
2568
			} else {
2569
				$type = wp_check_filetype( $atts[ $fallback ], wp_get_mime_types() );
2570
			}
2571
			$url = add_query_arg( '_', $instance, $atts[ $fallback ] );
2572
			$html .= sprintf( $source, $type['type'], esc_url( $url ) );
2573
		}
2574
	}
2575
2576
	if ( ! empty( $content ) ) {
2577 View Code Duplication
		if ( false !== strpos( $content, "\n" ) ) {
2578
			$content = str_replace( array( "\r\n", "\n", "\t" ), '', $content );
2579
		}
2580
		$html .= trim( $content );
2581
	}
2582
2583
	if ( 'mediaelement' === $library ) {
2584
		$html .= wp_mediaelement_fallback( $fileurl );
2585
	}
2586
	$html .= '</video>';
2587
2588
	$width_rule = '';
2589
	if ( ! empty( $atts['width'] ) ) {
2590
		$width_rule = sprintf( 'width: %dpx; ', $atts['width'] );
2591
	}
2592
	$output = sprintf( '<div style="%s" class="wp-video">%s</div>', $width_rule, $html );
2593
2594
	/**
2595
	 * Filters the output of the video shortcode.
2596
	 *
2597
	 * @since 3.6.0
2598
	 *
2599
	 * @param string $output  Video shortcode HTML output.
2600
	 * @param array  $atts    Array of video shortcode attributes.
2601
	 * @param string $video   Video file.
2602
	 * @param int    $post_id Post ID.
2603
	 * @param string $library Media library used for the video shortcode.
2604
	 */
2605
	return apply_filters( 'wp_video_shortcode', $output, $atts, $video, $post_id, $library );
2606
}
2607
add_shortcode( 'video', 'wp_video_shortcode' );
2608
2609
/**
2610
 * Displays previous image link that has the same post parent.
2611
 *
2612
 * @since 2.5.0
2613
 *
2614
 * @see adjacent_image_link()
2615
 *
2616
 * @param string|array $size Optional. Image size. Accepts any valid image size, an array of width and
2617
 *                           height values in pixels (in that order), 0, or 'none'. 0 or 'none' will
2618
 *                           default to 'post_title' or `$text`. Default 'thumbnail'.
2619
 * @param string       $text Optional. Link text. Default false.
2620
 */
2621
function previous_image_link( $size = 'thumbnail', $text = false ) {
2622
	adjacent_image_link(true, $size, $text);
0 ignored issues
show
Bug introduced by
It seems like $text defined by parameter $text on line 2621 can also be of type string; however, adjacent_image_link() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
2623
}
2624
2625
/**
2626
 * Displays next image link that has the same post parent.
2627
 *
2628
 * @since 2.5.0
2629
 *
2630
 * @see adjacent_image_link()
2631
 *
2632
 * @param string|array $size Optional. Image size. Accepts any valid image size, an array of width and
2633
 *                           height values in pixels (in that order), 0, or 'none'. 0 or 'none' will
2634
 *                           default to 'post_title' or `$text`. Default 'thumbnail'.
2635
 * @param string       $text Optional. Link text. Default false.
2636
 */
2637
function next_image_link( $size = 'thumbnail', $text = false ) {
2638
	adjacent_image_link(false, $size, $text);
0 ignored issues
show
Bug introduced by
It seems like $text defined by parameter $text on line 2637 can also be of type string; however, adjacent_image_link() does only seem to accept boolean, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
2639
}
2640
2641
/**
2642
 * Displays next or previous image link that has the same post parent.
2643
 *
2644
 * Retrieves the current attachment object from the $post global.
2645
 *
2646
 * @since 2.5.0
2647
 *
2648
 * @param bool         $prev Optional. Whether to display the next (false) or previous (true) link. Default true.
2649
 * @param string|array $size Optional. Image size. Accepts any valid image size, or an array of width and height
2650
 *                           values in pixels (in that order). Default 'thumbnail'.
2651
 * @param bool         $text Optional. Link text. Default false.
2652
 */
2653
function adjacent_image_link( $prev = true, $size = 'thumbnail', $text = false ) {
2654
	$post = get_post();
2655
	$attachments = array_values( get_children( array( 'post_parent' => $post->post_parent, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID' ) ) );
2656
2657
	foreach ( $attachments as $k => $attachment ) {
2658
		if ( $attachment->ID == $post->ID ) {
2659
			break;
2660
		}
2661
	}
2662
2663
	$output = '';
2664
	$attachment_id = 0;
2665
2666
	if ( $attachments ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $attachments of type array 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...
2667
		$k = $prev ? $k - 1 : $k + 1;
0 ignored issues
show
Bug introduced by
The variable $k does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2668
2669
		if ( isset( $attachments[ $k ] ) ) {
2670
			$attachment_id = $attachments[ $k ]->ID;
2671
			$output = wp_get_attachment_link( $attachment_id, $size, true, false, $text );
0 ignored issues
show
Documentation introduced by
$text is of type boolean, but the function expects a false|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2672
		}
2673
	}
2674
2675
	$adjacent = $prev ? 'previous' : 'next';
2676
2677
	/**
2678
	 * Filters the adjacent image link.
2679
	 *
2680
	 * The dynamic portion of the hook name, `$adjacent`, refers to the type of adjacency,
2681
	 * either 'next', or 'previous'.
2682
	 *
2683
	 * @since 3.5.0
2684
	 *
2685
	 * @param string $output        Adjacent image HTML markup.
2686
	 * @param int    $attachment_id Attachment ID
2687
	 * @param string $size          Image size.
2688
	 * @param string $text          Link text.
2689
	 */
2690
	echo apply_filters( "{$adjacent}_image_link", $output, $attachment_id, $size, $text );
2691
}
2692
2693
/**
2694
 * Retrieves taxonomies attached to given the attachment.
2695
 *
2696
 * @since 2.5.0
2697
 *
2698
 * @param int|array|object $attachment Attachment ID, data array, or data object.
2699
 * @return array Empty array on failure. List of taxonomies on success.
2700
 */
2701
function get_attachment_taxonomies( $attachment ) {
2702
	if ( is_int( $attachment ) ) {
2703
		$attachment = get_post( $attachment );
2704
	} elseif ( is_array( $attachment ) ) {
2705
		$attachment = (object) $attachment;
2706
	}
2707
	if ( ! is_object($attachment) )
2708
		return array();
2709
2710
	$file = get_attached_file( $attachment->ID );
2711
	$filename = basename( $file );
2712
2713
	$objects = array('attachment');
2714
2715
	if ( false !== strpos($filename, '.') )
2716
		$objects[] = 'attachment:' . substr($filename, strrpos($filename, '.') + 1);
2717
	if ( !empty($attachment->post_mime_type) ) {
2718
		$objects[] = 'attachment:' . $attachment->post_mime_type;
2719
		if ( false !== strpos($attachment->post_mime_type, '/') )
2720
			foreach ( explode('/', $attachment->post_mime_type) as $token )
2721
				if ( !empty($token) )
2722
					$objects[] = "attachment:$token";
2723
	}
2724
2725
	$taxonomies = array();
2726
	foreach ( $objects as $object )
2727
		if ( $taxes = get_object_taxonomies($object) )
2728
			$taxonomies = array_merge($taxonomies, $taxes);
2729
2730
	return array_unique($taxonomies);
2731
}
2732
2733
/**
2734
 * Retrieves all of the taxonomy names that are registered for attachments.
2735
 *
2736
 * Handles mime-type-specific taxonomies such as attachment:image and attachment:video.
2737
 *
2738
 * @since 3.5.0
2739
 *
2740
 * @see get_taxonomies()
2741
 *
2742
 * @param string $output Optional. The type of taxonomy output to return. Accepts 'names' or 'objects'.
2743
 *                       Default 'names'.
2744
 * @return array The names of all taxonomy of $object_type.
2745
 */
2746
function get_taxonomies_for_attachments( $output = 'names' ) {
2747
	$taxonomies = array();
2748
	foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy ) {
2749
		foreach ( $taxonomy->object_type as $object_type ) {
2750
			if ( 'attachment' == $object_type || 0 === strpos( $object_type, 'attachment:' ) ) {
2751
				if ( 'names' == $output )
2752
					$taxonomies[] = $taxonomy->name;
2753
				else
2754
					$taxonomies[ $taxonomy->name ] = $taxonomy;
2755
				break;
2756
			}
2757
		}
2758
	}
2759
2760
	return $taxonomies;
2761
}
2762
2763
/**
2764
 * Create new GD image resource with transparency support
2765
 *
2766
 * @todo: Deprecate if possible.
2767
 *
2768
 * @since 2.9.0
2769
 *
2770
 * @param int $width  Image width in pixels.
2771
 * @param int $height Image height in pixels..
2772
 * @return resource The GD image resource.
2773
 */
2774
function wp_imagecreatetruecolor($width, $height) {
2775
	$img = imagecreatetruecolor($width, $height);
2776
	if ( is_resource($img) && function_exists('imagealphablending') && function_exists('imagesavealpha') ) {
2777
		imagealphablending($img, false);
2778
		imagesavealpha($img, true);
2779
	}
2780
	return $img;
2781
}
2782
2783
/**
2784
 * Based on a supplied width/height example, return the biggest possible dimensions based on the max width/height.
2785
 *
2786
 * @since 2.9.0
2787
 *
2788
 * @see wp_constrain_dimensions()
2789
 *
2790
 * @param int $example_width  The width of an example embed.
2791
 * @param int $example_height The height of an example embed.
2792
 * @param int $max_width      The maximum allowed width.
2793
 * @param int $max_height     The maximum allowed height.
2794
 * @return array The maximum possible width and height based on the example ratio.
2795
 */
2796
function wp_expand_dimensions( $example_width, $example_height, $max_width, $max_height ) {
2797
	$example_width  = (int) $example_width;
2798
	$example_height = (int) $example_height;
2799
	$max_width      = (int) $max_width;
2800
	$max_height     = (int) $max_height;
2801
2802
	return wp_constrain_dimensions( $example_width * 1000000, $example_height * 1000000, $max_width, $max_height );
2803
}
2804
2805
/**
2806
 * Determines the maximum upload size allowed in php.ini.
2807
 *
2808
 * @since 2.5.0
2809
 *
2810
 * @return int Allowed upload size.
2811
 */
2812
function wp_max_upload_size() {
2813
	$u_bytes = wp_convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) );
2814
	$p_bytes = wp_convert_hr_to_bytes( ini_get( 'post_max_size' ) );
2815
2816
	/**
2817
	 * Filters the maximum upload size allowed in php.ini.
2818
	 *
2819
	 * @since 2.5.0
2820
	 *
2821
	 * @param int $size    Max upload size limit in bytes.
2822
	 * @param int $u_bytes Maximum upload filesize in bytes.
2823
	 * @param int $p_bytes Maximum size of POST data in bytes.
2824
	 */
2825
	return apply_filters( 'upload_size_limit', min( $u_bytes, $p_bytes ), $u_bytes, $p_bytes );
2826
}
2827
2828
/**
2829
 * Returns a WP_Image_Editor instance and loads file into it.
2830
 *
2831
 * @since 3.5.0
2832
 *
2833
 * @param string $path Path to the file to load.
2834
 * @param array  $args Optional. Additional arguments for retrieving the image editor.
2835
 *                     Default empty array.
2836
 * @return WP_Image_Editor|WP_Error The WP_Image_Editor object if successful, an WP_Error
2837
 *                                  object otherwise.
2838
 */
2839
function wp_get_image_editor( $path, $args = array() ) {
2840
	$args['path'] = $path;
2841
2842
	if ( ! isset( $args['mime_type'] ) ) {
2843
		$file_info = wp_check_filetype( $args['path'] );
2844
2845
		// If $file_info['type'] is false, then we let the editor attempt to
2846
		// figure out the file type, rather than forcing a failure based on extension.
2847
		if ( isset( $file_info ) && $file_info['type'] )
2848
			$args['mime_type'] = $file_info['type'];
2849
	}
2850
2851
	$implementation = _wp_image_editor_choose( $args );
2852
2853
	if ( $implementation ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $implementation of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2854
		$editor = new $implementation( $path );
2855
		$loaded = $editor->load();
2856
2857
		if ( is_wp_error( $loaded ) )
2858
			return $loaded;
2859
2860
		return $editor;
2861
	}
2862
2863
	return new WP_Error( 'image_no_editor', __('No editor could be selected.') );
2864
}
2865
2866
/**
2867
 * Tests whether there is an editor that supports a given mime type or methods.
2868
 *
2869
 * @since 3.5.0
2870
 *
2871
 * @param string|array $args Optional. Array of arguments to retrieve the image editor supports.
2872
 *                           Default empty array.
2873
 * @return bool True if an eligible editor is found; false otherwise.
2874
 */
2875
function wp_image_editor_supports( $args = array() ) {
2876
	return (bool) _wp_image_editor_choose( $args );
0 ignored issues
show
Bug introduced by
It seems like $args defined by parameter $args on line 2875 can also be of type string; however, _wp_image_editor_choose() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
2877
}
2878
2879
/**
2880
 * Tests which editors are capable of supporting the request.
2881
 *
2882
 * @ignore
2883
 * @since 3.5.0
2884
 *
2885
 * @param array $args Optional. Array of arguments for choosing a capable editor. Default empty array.
2886
 * @return string|false Class name for the first editor that claims to support the request. False if no
2887
 *                     editor claims to support the request.
2888
 */
2889
function _wp_image_editor_choose( $args = array() ) {
2890
	require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
2891
	require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';
2892
	require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php';
2893
2894
	/**
2895
	 * Filters the list of image editing library classes.
2896
	 *
2897
	 * @since 3.5.0
2898
	 *
2899
	 * @param array $image_editors List of available image editors. Defaults are
2900
	 *                             'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD'.
2901
	 */
2902
	$implementations = apply_filters( 'wp_image_editors', array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) );
2903
2904
	foreach ( $implementations as $implementation ) {
2905
		if ( ! call_user_func( array( $implementation, 'test' ), $args ) )
2906
			continue;
2907
2908
		if ( isset( $args['mime_type'] ) &&
2909
			! call_user_func(
2910
				array( $implementation, 'supports_mime_type' ),
2911
				$args['mime_type'] ) ) {
2912
			continue;
2913
		}
2914
2915
		if ( isset( $args['methods'] ) &&
2916
			 array_diff( $args['methods'], get_class_methods( $implementation ) ) ) {
2917
			continue;
2918
		}
2919
2920
		return $implementation;
2921
	}
2922
2923
	return false;
2924
}
2925
2926
/**
2927
 * Prints default Plupload arguments.
2928
 *
2929
 * @since 3.4.0
2930
 */
2931
function wp_plupload_default_settings() {
2932
	$wp_scripts = wp_scripts();
2933
2934
	$data = $wp_scripts->get_data( 'wp-plupload', 'data' );
2935
	if ( $data && false !== strpos( $data, '_wpPluploadSettings' ) )
2936
		return;
2937
2938
	$max_upload_size = wp_max_upload_size();
2939
	$allowed_extensions = array_keys( get_allowed_mime_types() );
2940
	$extensions = array();
2941
	foreach ( $allowed_extensions as $extension ) {
2942
		$extensions = array_merge( $extensions, explode( '|', $extension ) );
2943
	}
2944
2945
	$defaults = array(
2946
		'runtimes'            => 'html5,flash,silverlight,html4',
2947
		'file_data_name'      => 'async-upload', // key passed to $_FILE.
2948
		'url'                 => admin_url( 'async-upload.php', 'relative' ),
2949
		'flash_swf_url'       => includes_url( 'js/plupload/plupload.flash.swf' ),
2950
		'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
2951
		'filters' => array(
2952
			'max_file_size'   => $max_upload_size . 'b',
2953
			'mime_types'      => array( array( 'extensions' => implode( ',', $extensions ) ) ),
2954
		),
2955
	);
2956
2957
	// Currently only iOS Safari supports multiple files uploading but iOS 7.x has a bug that prevents uploading of videos
2958
	// when enabled. See #29602.
2959 View Code Duplication
	if ( wp_is_mobile() && strpos( $_SERVER['HTTP_USER_AGENT'], 'OS 7_' ) !== false &&
2960
		strpos( $_SERVER['HTTP_USER_AGENT'], 'like Mac OS X' ) !== false ) {
2961
2962
		$defaults['multi_selection'] = false;
2963
	}
2964
2965
	/**
2966
	 * Filters the Plupload default settings.
2967
	 *
2968
	 * @since 3.4.0
2969
	 *
2970
	 * @param array $defaults Default Plupload settings array.
2971
	 */
2972
	$defaults = apply_filters( 'plupload_default_settings', $defaults );
2973
2974
	$params = array(
2975
		'action' => 'upload-attachment',
2976
	);
2977
2978
	/**
2979
	 * Filters the Plupload default parameters.
2980
	 *
2981
	 * @since 3.4.0
2982
	 *
2983
	 * @param array $params Default Plupload parameters array.
2984
	 */
2985
	$params = apply_filters( 'plupload_default_params', $params );
2986
	$params['_wpnonce'] = wp_create_nonce( 'media-form' );
2987
	$defaults['multipart_params'] = $params;
2988
2989
	$settings = array(
2990
		'defaults' => $defaults,
2991
		'browser'  => array(
2992
			'mobile'    => wp_is_mobile(),
2993
			'supported' => _device_can_upload(),
2994
		),
2995
		'limitExceeded' => is_multisite() && ! is_upload_space_available()
2996
	);
2997
2998
	$script = 'var _wpPluploadSettings = ' . wp_json_encode( $settings ) . ';';
2999
3000
	if ( $data )
3001
		$script = "$data\n$script";
3002
3003
	$wp_scripts->add_data( 'wp-plupload', 'data', $script );
3004
}
3005
3006
/**
3007
 * Prepares an attachment post object for JS, where it is expected
3008
 * to be JSON-encoded and fit into an Attachment model.
3009
 *
3010
 * @since 3.5.0
3011
 *
3012
 * @param mixed $attachment Attachment ID or object.
3013
 * @return array|void Array of attachment details.
3014
 */
3015
function wp_prepare_attachment_for_js( $attachment ) {
3016
	if ( ! $attachment = get_post( $attachment ) )
3017
		return;
3018
3019
	if ( 'attachment' != $attachment->post_type )
3020
		return;
3021
3022
	$meta = wp_get_attachment_metadata( $attachment->ID );
3023 View Code Duplication
	if ( false !== strpos( $attachment->post_mime_type, '/' ) )
3024
		list( $type, $subtype ) = explode( '/', $attachment->post_mime_type );
3025
	else
3026
		list( $type, $subtype ) = array( $attachment->post_mime_type, '' );
3027
3028
	$attachment_url = wp_get_attachment_url( $attachment->ID );
3029
3030
	$response = array(
3031
		'id'          => $attachment->ID,
3032
		'title'       => $attachment->post_title,
3033
		'filename'    => wp_basename( get_attached_file( $attachment->ID ) ),
0 ignored issues
show
Security Bug introduced by
It seems like get_attached_file($attachment->ID) targeting get_attached_file() can also be of type false; however, wp_basename() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
3034
		'url'         => $attachment_url,
3035
		'link'        => get_attachment_link( $attachment->ID ),
3036
		'alt'         => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ),
3037
		'author'      => $attachment->post_author,
3038
		'description' => $attachment->post_content,
3039
		'caption'     => $attachment->post_excerpt,
3040
		'name'        => $attachment->post_name,
3041
		'status'      => $attachment->post_status,
3042
		'uploadedTo'  => $attachment->post_parent,
3043
		'date'        => strtotime( $attachment->post_date_gmt ) * 1000,
3044
		'modified'    => strtotime( $attachment->post_modified_gmt ) * 1000,
3045
		'menuOrder'   => $attachment->menu_order,
3046
		'mime'        => $attachment->post_mime_type,
3047
		'type'        => $type,
3048
		'subtype'     => $subtype,
3049
		'icon'        => wp_mime_type_icon( $attachment->ID ),
3050
		'dateFormatted' => mysql2date( __( 'F j, Y' ), $attachment->post_date ),
3051
		'nonces'      => array(
3052
			'update' => false,
3053
			'delete' => false,
3054
			'edit'   => false
3055
		),
3056
		'editLink'   => false,
3057
		'meta'       => false,
3058
	);
3059
3060
	$author = new WP_User( $attachment->post_author );
3061
	$response['authorName'] = $author->display_name;
3062
3063
	if ( $attachment->post_parent ) {
3064
		$post_parent = get_post( $attachment->post_parent );
3065
	} else {
3066
		$post_parent = false;
3067
	}
3068
3069
	if ( $post_parent ) {
3070
		$parent_type = get_post_type_object( $post_parent->post_type );
3071
3072
		if ( $parent_type && $parent_type->show_ui && current_user_can( 'edit_post', $attachment->post_parent ) ) {
3073
			$response['uploadedToLink'] = get_edit_post_link( $attachment->post_parent, 'raw' );
3074
		}
3075
3076
		if ( $parent_type && current_user_can( 'read_post', $attachment->post_parent ) ) {
3077
			$response['uploadedToTitle'] = $post_parent->post_title ? $post_parent->post_title : __( '(no title)' );
3078
		}
3079
	}
3080
3081
	$attached_file = get_attached_file( $attachment->ID );
3082
3083
	if ( isset( $meta['filesize'] ) ) {
3084
		$bytes = $meta['filesize'];
3085
	} elseif ( file_exists( $attached_file ) ) {
3086
		$bytes = filesize( $attached_file );
3087
	} else {
3088
		$bytes = '';
3089
	}
3090
3091
	if ( $bytes ) {
3092
		$response['filesizeInBytes'] = $bytes;
3093
		$response['filesizeHumanReadable'] = size_format( $bytes );
3094
	}
3095
3096
	if ( current_user_can( 'edit_post', $attachment->ID ) ) {
3097
		$response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID );
3098
		$response['nonces']['edit'] = wp_create_nonce( 'image_editor-' . $attachment->ID );
3099
		$response['editLink'] = get_edit_post_link( $attachment->ID, 'raw' );
3100
	}
3101
3102
	if ( current_user_can( 'delete_post', $attachment->ID ) )
3103
		$response['nonces']['delete'] = wp_create_nonce( 'delete-post_' . $attachment->ID );
3104
3105
	if ( $meta && 'image' === $type ) {
3106
		$sizes = array();
3107
3108
		/** This filter is documented in wp-admin/includes/media.php */
3109
		$possible_sizes = apply_filters( 'image_size_names_choose', array(
3110
			'thumbnail' => __('Thumbnail'),
3111
			'medium'    => __('Medium'),
3112
			'large'     => __('Large'),
3113
			'full'      => __('Full Size'),
3114
		) );
3115
		unset( $possible_sizes['full'] );
3116
3117
		// Loop through all potential sizes that may be chosen. Try to do this with some efficiency.
3118
		// First: run the image_downsize filter. If it returns something, we can use its data.
3119
		// If the filter does not return something, then image_downsize() is just an expensive
3120
		// way to check the image metadata, which we do second.
3121
		foreach ( $possible_sizes as $size => $label ) {
3122
3123
			/** This filter is documented in wp-includes/media.php */
3124
			if ( $downsize = apply_filters( 'image_downsize', false, $attachment->ID, $size ) ) {
3125
				if ( ! $downsize[3] )
3126
					continue;
3127
				$sizes[ $size ] = array(
3128
					'height'      => $downsize[2],
3129
					'width'       => $downsize[1],
3130
					'url'         => $downsize[0],
3131
					'orientation' => $downsize[2] > $downsize[1] ? 'portrait' : 'landscape',
3132
				);
3133
			} elseif ( isset( $meta['sizes'][ $size ] ) ) {
3134
				if ( ! isset( $base_url ) )
3135
					$base_url = str_replace( wp_basename( $attachment_url ), '', $attachment_url );
0 ignored issues
show
Security Bug introduced by
It seems like $attachment_url defined by wp_get_attachment_url($attachment->ID) on line 3028 can also be of type false; however, wp_basename() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
3136
3137
				// Nothing from the filter, so consult image metadata if we have it.
3138
				$size_meta = $meta['sizes'][ $size ];
3139
3140
				// We have the actual image size, but might need to further constrain it if content_width is narrower.
3141
				// Thumbnail, medium, and full sizes are also checked against the site's height/width options.
3142
				list( $width, $height ) = image_constrain_size_for_editor( $size_meta['width'], $size_meta['height'], $size, 'edit' );
3143
3144
				$sizes[ $size ] = array(
3145
					'height'      => $height,
3146
					'width'       => $width,
3147
					'url'         => $base_url . $size_meta['file'],
3148
					'orientation' => $height > $width ? 'portrait' : 'landscape',
3149
				);
3150
			}
3151
		}
3152
3153
		$sizes['full'] = array( 'url' => $attachment_url );
3154
3155
		if ( isset( $meta['height'], $meta['width'] ) ) {
3156
			$sizes['full']['height'] = $meta['height'];
3157
			$sizes['full']['width'] = $meta['width'];
3158
			$sizes['full']['orientation'] = $meta['height'] > $meta['width'] ? 'portrait' : 'landscape';
3159
		}
3160
3161
		$response = array_merge( $response, array( 'sizes' => $sizes ), $sizes['full'] );
3162
	} elseif ( $meta && 'video' === $type ) {
3163
		if ( isset( $meta['width'] ) )
3164
			$response['width'] = (int) $meta['width'];
3165
		if ( isset( $meta['height'] ) )
3166
			$response['height'] = (int) $meta['height'];
3167
	}
3168
3169
	if ( $meta && ( 'audio' === $type || 'video' === $type ) ) {
3170
		if ( isset( $meta['length_formatted'] ) )
3171
			$response['fileLength'] = $meta['length_formatted'];
3172
3173
		$response['meta'] = array();
3174
		foreach ( wp_get_attachment_id3_keys( $attachment, 'js' ) as $key => $label ) {
0 ignored issues
show
Bug introduced by
It seems like $attachment defined by get_post($attachment) on line 3016 can also be of type array; however, wp_get_attachment_id3_keys() does only seem to accept object<WP_Post>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
3175
			$response['meta'][ $key ] = false;
3176
3177
			if ( ! empty( $meta[ $key ] ) ) {
3178
				$response['meta'][ $key ] = $meta[ $key ];
3179
			}
3180
		}
3181
3182
		$id = get_post_thumbnail_id( $attachment->ID );
3183 View Code Duplication
		if ( ! empty( $id ) ) {
3184
			list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' );
3185
			$response['image'] = compact( 'src', 'width', 'height' );
3186
			list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumbnail' );
3187
			$response['thumb'] = compact( 'src', 'width', 'height' );
3188
		} else {
3189
			$src = wp_mime_type_icon( $attachment->ID );
3190
			$width = 48;
3191
			$height = 64;
3192
			$response['image'] = compact( 'src', 'width', 'height' );
3193
			$response['thumb'] = compact( 'src', 'width', 'height' );
3194
		}
3195
	}
3196
3197
	if ( function_exists('get_compat_media_markup') )
3198
		$response['compat'] = get_compat_media_markup( $attachment->ID, array( 'in_modal' => true ) );
3199
3200
	/**
3201
	 * Filters the attachment data prepared for JavaScript.
3202
	 *
3203
	 * @since 3.5.0
3204
	 *
3205
	 * @param array      $response   Array of prepared attachment data.
3206
	 * @param int|object $attachment Attachment ID or object.
3207
	 * @param array      $meta       Array of attachment meta data.
3208
	 */
3209
	return apply_filters( 'wp_prepare_attachment_for_js', $response, $attachment, $meta );
3210
}
3211
3212
/**
3213
 * Enqueues all scripts, styles, settings, and templates necessary to use
3214
 * all media JS APIs.
3215
 *
3216
 * @since 3.5.0
3217
 *
3218
 * @global int       $content_width
3219
 * @global wpdb      $wpdb
3220
 * @global WP_Locale $wp_locale
3221
 *
3222
 * @param array $args {
3223
 *     Arguments for enqueuing media scripts.
3224
 *
3225
 *     @type int|WP_Post A post object or ID.
3226
 * }
3227
 */
3228
function wp_enqueue_media( $args = array() ) {
3229
	// Enqueue me just once per page, please.
3230
	if ( did_action( 'wp_enqueue_media' ) )
3231
		return;
3232
3233
	global $content_width, $wpdb, $wp_locale;
3234
3235
	$defaults = array(
3236
		'post' => null,
3237
	);
3238
	$args = wp_parse_args( $args, $defaults );
3239
3240
	// We're going to pass the old thickbox media tabs to `media_upload_tabs`
3241
	// to ensure plugins will work. We will then unset those tabs.
3242
	$tabs = array(
3243
		// handler action suffix => tab label
3244
		'type'     => '',
3245
		'type_url' => '',
3246
		'gallery'  => '',
3247
		'library'  => '',
3248
	);
3249
3250
	/** This filter is documented in wp-admin/includes/media.php */
3251
	$tabs = apply_filters( 'media_upload_tabs', $tabs );
3252
	unset( $tabs['type'], $tabs['type_url'], $tabs['gallery'], $tabs['library'] );
3253
3254
	$props = array(
3255
		'link'  => get_option( 'image_default_link_type' ), // db default is 'file'
3256
		'align' => get_option( 'image_default_align' ), // empty default
3257
		'size'  => get_option( 'image_default_size' ),  // empty default
3258
	);
3259
3260
	$exts = array_merge( wp_get_audio_extensions(), wp_get_video_extensions() );
3261
	$mimes = get_allowed_mime_types();
3262
	$ext_mimes = array();
3263 View Code Duplication
	foreach ( $exts as $ext ) {
3264
		foreach ( $mimes as $ext_preg => $mime_match ) {
3265
			if ( preg_match( '#' . $ext . '#i', $ext_preg ) ) {
3266
				$ext_mimes[ $ext ] = $mime_match;
3267
				break;
3268
			}
3269
		}
3270
	}
3271
3272
	$has_audio = $wpdb->get_var( "
3273
		SELECT ID
3274
		FROM $wpdb->posts
3275
		WHERE post_type = 'attachment'
3276
		AND post_mime_type LIKE 'audio%'
3277
		LIMIT 1
3278
	" );
3279
	$has_video = $wpdb->get_var( "
3280
		SELECT ID
3281
		FROM $wpdb->posts
3282
		WHERE post_type = 'attachment'
3283
		AND post_mime_type LIKE 'video%'
3284
		LIMIT 1
3285
	" );
3286
	$months = $wpdb->get_results( $wpdb->prepare( "
3287
		SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
3288
		FROM $wpdb->posts
3289
		WHERE post_type = %s
3290
		ORDER BY post_date DESC
3291
	", 'attachment' ) );
3292
	foreach ( $months as $month_year ) {
3293
		$month_year->text = sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month_year->month ), $month_year->year );
3294
	}
3295
3296
	$settings = array(
3297
		'tabs'      => $tabs,
3298
		'tabUrl'    => add_query_arg( array( 'chromeless' => true ), admin_url('media-upload.php') ),
3299
		'mimeTypes' => wp_list_pluck( get_post_mime_types(), 0 ),
3300
		/** This filter is documented in wp-admin/includes/media.php */
3301
		'captions'  => ! apply_filters( 'disable_captions', '' ),
3302
		'nonce'     => array(
3303
			'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
3304
		),
3305
		'post'    => array(
3306
			'id' => 0,
3307
		),
3308
		'defaultProps' => $props,
3309
		'attachmentCounts' => array(
3310
			'audio' => ( $has_audio ) ? 1 : 0,
3311
			'video' => ( $has_video ) ? 1 : 0
3312
		),
3313
		'embedExts'    => $exts,
3314
		'embedMimes'   => $ext_mimes,
3315
		'contentWidth' => $content_width,
3316
		'months'       => $months,
3317
		'mediaTrash'   => MEDIA_TRASH ? 1 : 0
3318
	);
3319
3320
	$post = null;
3321
	if ( isset( $args['post'] ) ) {
3322
		$post = get_post( $args['post'] );
3323
		$settings['post'] = array(
3324
			'id' => $post->ID,
3325
			'nonce' => wp_create_nonce( 'update-post_' . $post->ID ),
3326
		);
3327
3328
		$thumbnail_support = current_theme_supports( 'post-thumbnails', $post->post_type ) && post_type_supports( $post->post_type, 'thumbnail' );
3329 View Code Duplication
		if ( ! $thumbnail_support && 'attachment' === $post->post_type && $post->post_mime_type ) {
3330
			if ( wp_attachment_is( 'audio', $post ) ) {
0 ignored issues
show
Bug introduced by
It seems like $post defined by get_post($args['post']) on line 3322 can also be of type array; however, wp_attachment_is() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
3331
				$thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' );
3332
			} elseif ( wp_attachment_is( 'video', $post ) ) {
0 ignored issues
show
Bug introduced by
It seems like $post defined by get_post($args['post']) on line 3322 can also be of type array; however, wp_attachment_is() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
3333
				$thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' );
3334
			}
3335
		}
3336
3337
		if ( $thumbnail_support ) {
3338
			$featured_image_id = get_post_meta( $post->ID, '_thumbnail_id', true );
3339
			$settings['post']['featuredImageId'] = $featured_image_id ? $featured_image_id : -1;
3340
		}
3341
	}
3342
3343
	if ( $post ) {
3344
		$post_type_object = get_post_type_object( $post->post_type );
3345
	} else {
3346
		$post_type_object = get_post_type_object( 'post' );
3347
	}
3348
3349
	$strings = array(
3350
		// Generic
3351
		'url'         => __( 'URL' ),
3352
		'addMedia'    => __( 'Add Media' ),
3353
		'search'      => __( 'Search' ),
3354
		'select'      => __( 'Select' ),
3355
		'cancel'      => __( 'Cancel' ),
3356
		'update'      => __( 'Update' ),
3357
		'replace'     => __( 'Replace' ),
3358
		'remove'      => __( 'Remove' ),
3359
		'back'        => __( 'Back' ),
3360
		/* translators: This is a would-be plural string used in the media manager.
3361
		   If there is not a word you can use in your language to avoid issues with the
3362
		   lack of plural support here, turn it into "selected: %d" then translate it.
3363
		 */
3364
		'selected'    => __( '%d selected' ),
3365
		'dragInfo'    => __( 'Drag and drop to reorder media files.' ),
3366
3367
		// Upload
3368
		'uploadFilesTitle'  => __( 'Upload Files' ),
3369
		'uploadImagesTitle' => __( 'Upload Images' ),
3370
3371
		// Library
3372
		'mediaLibraryTitle'      => __( 'Media Library' ),
3373
		'insertMediaTitle'       => __( 'Insert Media' ),
3374
		'createNewGallery'       => __( 'Create a new gallery' ),
3375
		'createNewPlaylist'      => __( 'Create a new playlist' ),
3376
		'createNewVideoPlaylist' => __( 'Create a new video playlist' ),
3377
		'returnToLibrary'        => __( '&#8592; Return to library' ),
3378
		'allMediaItems'          => __( 'All media items' ),
3379
		'allDates'               => __( 'All dates' ),
3380
		'noItemsFound'           => __( 'No items found.' ),
3381
		'insertIntoPost'         => $post_type_object->labels->insert_into_item,
3382
		'unattached'             => __( 'Unattached' ),
3383
		'trash'                  => _x( 'Trash', 'noun' ),
3384
		'uploadedToThisPost'     => $post_type_object->labels->uploaded_to_this_item,
3385
		'warnDelete'             => __( "You are about to permanently delete this item.\n  'Cancel' to stop, 'OK' to delete." ),
3386
		'warnBulkDelete'         => __( "You are about to permanently delete these items.\n  'Cancel' to stop, 'OK' to delete." ),
3387
		'warnBulkTrash'          => __( "You are about to trash these items.\n  'Cancel' to stop, 'OK' to delete." ),
3388
		'bulkSelect'             => __( 'Bulk Select' ),
3389
		'cancelSelection'        => __( 'Cancel Selection' ),
3390
		'trashSelected'          => __( 'Trash Selected' ),
3391
		'untrashSelected'        => __( 'Untrash Selected' ),
3392
		'deleteSelected'         => __( 'Delete Selected' ),
3393
		'deletePermanently'      => __( 'Delete Permanently' ),
3394
		'apply'                  => __( 'Apply' ),
3395
		'filterByDate'           => __( 'Filter by date' ),
3396
		'filterByType'           => __( 'Filter by type' ),
3397
		'searchMediaLabel'       => __( 'Search Media' ),
3398
		'noMedia'                => __( 'No media files found.' ),
3399
3400
		// Library Details
3401
		'attachmentDetails'  => __( 'Attachment Details' ),
3402
3403
		// From URL
3404
		'insertFromUrlTitle' => __( 'Insert from URL' ),
3405
3406
		// Featured Images
3407
		'setFeaturedImageTitle' => $post_type_object->labels->featured_image,
3408
		'setFeaturedImage'      => $post_type_object->labels->set_featured_image,
3409
3410
		// Gallery
3411
		'createGalleryTitle' => __( 'Create Gallery' ),
3412
		'editGalleryTitle'   => __( 'Edit Gallery' ),
3413
		'cancelGalleryTitle' => __( '&#8592; Cancel Gallery' ),
3414
		'insertGallery'      => __( 'Insert gallery' ),
3415
		'updateGallery'      => __( 'Update gallery' ),
3416
		'addToGallery'       => __( 'Add to gallery' ),
3417
		'addToGalleryTitle'  => __( 'Add to Gallery' ),
3418
		'reverseOrder'       => __( 'Reverse order' ),
3419
3420
		// Edit Image
3421
		'imageDetailsTitle'     => __( 'Image Details' ),
3422
		'imageReplaceTitle'     => __( 'Replace Image' ),
3423
		'imageDetailsCancel'    => __( 'Cancel Edit' ),
3424
		'editImage'             => __( 'Edit Image' ),
3425
3426
		// Crop Image
3427
		'chooseImage' => __( 'Choose Image' ),
3428
		'selectAndCrop' => __( 'Select and Crop' ),
3429
		'skipCropping' => __( 'Skip Cropping' ),
3430
		'cropImage' => __( 'Crop Image' ),
3431
		'cropYourImage' => __( 'Crop your image' ),
3432
		'cropping' => __( 'Cropping&hellip;' ),
3433
		'suggestedDimensions' => __( 'Suggested image dimensions:' ),
3434
		'cropError' => __( 'There has been an error cropping your image.' ),
3435
3436
		// Edit Audio
3437
		'audioDetailsTitle'     => __( 'Audio Details' ),
3438
		'audioReplaceTitle'     => __( 'Replace Audio' ),
3439
		'audioAddSourceTitle'   => __( 'Add Audio Source' ),
3440
		'audioDetailsCancel'    => __( 'Cancel Edit' ),
3441
3442
		// Edit Video
3443
		'videoDetailsTitle'     => __( 'Video Details' ),
3444
		'videoReplaceTitle'     => __( 'Replace Video' ),
3445
		'videoAddSourceTitle'   => __( 'Add Video Source' ),
3446
		'videoDetailsCancel'    => __( 'Cancel Edit' ),
3447
		'videoSelectPosterImageTitle' => __( 'Select Poster Image' ),
3448
		'videoAddTrackTitle'	=> __( 'Add Subtitles' ),
3449
3450
 		// Playlist
3451
 		'playlistDragInfo'    => __( 'Drag and drop to reorder tracks.' ),
3452
 		'createPlaylistTitle' => __( 'Create Audio Playlist' ),
3453
 		'editPlaylistTitle'   => __( 'Edit Audio Playlist' ),
3454
 		'cancelPlaylistTitle' => __( '&#8592; Cancel Audio Playlist' ),
3455
 		'insertPlaylist'      => __( 'Insert audio playlist' ),
3456
 		'updatePlaylist'      => __( 'Update audio playlist' ),
3457
 		'addToPlaylist'       => __( 'Add to audio playlist' ),
3458
 		'addToPlaylistTitle'  => __( 'Add to Audio Playlist' ),
3459
3460
 		// Video Playlist
3461
 		'videoPlaylistDragInfo'    => __( 'Drag and drop to reorder videos.' ),
3462
 		'createVideoPlaylistTitle' => __( 'Create Video Playlist' ),
3463
 		'editVideoPlaylistTitle'   => __( 'Edit Video Playlist' ),
3464
 		'cancelVideoPlaylistTitle' => __( '&#8592; Cancel Video Playlist' ),
3465
 		'insertVideoPlaylist'      => __( 'Insert video playlist' ),
3466
 		'updateVideoPlaylist'      => __( 'Update video playlist' ),
3467
 		'addToVideoPlaylist'       => __( 'Add to video playlist' ),
3468
 		'addToVideoPlaylistTitle'  => __( 'Add to Video Playlist' ),
3469
	);
3470
3471
	/**
3472
	 * Filters the media view settings.
3473
	 *
3474
	 * @since 3.5.0
3475
	 *
3476
	 * @param array   $settings List of media view settings.
3477
	 * @param WP_Post $post     Post object.
3478
	 */
3479
	$settings = apply_filters( 'media_view_settings', $settings, $post );
3480
3481
	/**
3482
	 * Filters the media view strings.
3483
	 *
3484
	 * @since 3.5.0
3485
	 *
3486
	 * @param array   $strings List of media view strings.
3487
	 * @param WP_Post $post    Post object.
3488
	 */
3489
	$strings = apply_filters( 'media_view_strings', $strings,  $post );
3490
3491
	$strings['settings'] = $settings;
3492
3493
	// Ensure we enqueue media-editor first, that way media-views is
3494
	// registered internally before we try to localize it. see #24724.
3495
	wp_enqueue_script( 'media-editor' );
3496
	wp_localize_script( 'media-views', '_wpMediaViewsL10n', $strings );
3497
3498
	wp_enqueue_script( 'media-audiovideo' );
3499
	wp_enqueue_style( 'media-views' );
3500
	if ( is_admin() ) {
3501
		wp_enqueue_script( 'mce-view' );
3502
		wp_enqueue_script( 'image-edit' );
3503
	}
3504
	wp_enqueue_style( 'imgareaselect' );
3505
	wp_plupload_default_settings();
3506
3507
	require_once ABSPATH . WPINC . '/media-template.php';
3508
	add_action( 'admin_footer', 'wp_print_media_templates' );
3509
	add_action( 'wp_footer', 'wp_print_media_templates' );
3510
	add_action( 'customize_controls_print_footer_scripts', 'wp_print_media_templates' );
3511
3512
	/**
3513
	 * Fires at the conclusion of wp_enqueue_media().
3514
	 *
3515
	 * @since 3.5.0
3516
	 */
3517
	do_action( 'wp_enqueue_media' );
3518
}
3519
3520
/**
3521
 * Retrieves media attached to the passed post.
3522
 *
3523
 * @since 3.6.0
3524
 *
3525
 * @param string      $type Mime type.
3526
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
3527
 * @return array Found attachments.
3528
 */
3529
function get_attached_media( $type, $post = 0 ) {
3530
	if ( ! $post = get_post( $post ) )
3531
		return array();
3532
3533
	$args = array(
3534
		'post_parent' => $post->ID,
3535
		'post_type' => 'attachment',
3536
		'post_mime_type' => $type,
3537
		'posts_per_page' => -1,
3538
		'orderby' => 'menu_order',
3539
		'order' => 'ASC',
3540
	);
3541
3542
	/**
3543
	 * Filters arguments used to retrieve media attached to the given post.
3544
	 *
3545
	 * @since 3.6.0
3546
	 *
3547
	 * @param array  $args Post query arguments.
3548
	 * @param string $type Mime type of the desired media.
3549
	 * @param mixed  $post Post ID or object.
3550
	 */
3551
	$args = apply_filters( 'get_attached_media_args', $args, $type, $post );
3552
3553
	$children = get_children( $args );
3554
3555
	/**
3556
	 * Filters the list of media attached to the given post.
3557
	 *
3558
	 * @since 3.6.0
3559
	 *
3560
	 * @param array  $children Associative array of media attached to the given post.
3561
	 * @param string $type     Mime type of the media desired.
3562
	 * @param mixed  $post     Post ID or object.
3563
	 */
3564
	return (array) apply_filters( 'get_attached_media', $children, $type, $post );
3565
}
3566
3567
/**
3568
 * Check the content blob for an audio, video, object, embed, or iframe tags.
3569
 *
3570
 * @since 3.6.0
3571
 *
3572
 * @param string $content A string which might contain media data.
3573
 * @param array  $types   An array of media types: 'audio', 'video', 'object', 'embed', or 'iframe'.
3574
 * @return array A list of found HTML media embeds.
3575
 */
3576
function get_media_embedded_in_content( $content, $types = null ) {
3577
	$html = array();
3578
3579
	/**
3580
	 * Filters the embedded media types that are allowed to be returned from the content blob.
3581
	 *
3582
	 * @since 4.2.0
3583
	 *
3584
	 * @param array $allowed_media_types An array of allowed media types. Default media types are
3585
	 *                                   'audio', 'video', 'object', 'embed', and 'iframe'.
3586
	 */
3587
	$allowed_media_types = apply_filters( 'media_embedded_in_content_allowed_types', array( 'audio', 'video', 'object', 'embed', 'iframe' ) );
3588
3589
	if ( ! empty( $types ) ) {
3590
		if ( ! is_array( $types ) ) {
3591
			$types = array( $types );
3592
		}
3593
3594
		$allowed_media_types = array_intersect( $allowed_media_types, $types );
3595
	}
3596
3597
	$tags = implode( '|', $allowed_media_types );
3598
3599
	if ( preg_match_all( '#<(?P<tag>' . $tags . ')[^<]*?(?:>[\s\S]*?<\/(?P=tag)>|\s*\/>)#', $content, $matches ) ) {
3600
		foreach ( $matches[0] as $match ) {
3601
			$html[] = $match;
3602
		}
3603
	}
3604
3605
	return $html;
3606
}
3607
3608
/**
3609
 * Retrieves galleries from the passed post's content.
3610
 *
3611
 * @since 3.6.0
3612
 *
3613
 * @param int|WP_Post $post Post ID or object.
3614
 * @param bool        $html Optional. Whether to return HTML or data in the array. Default true.
3615
 * @return array A list of arrays, each containing gallery data and srcs parsed
3616
 *               from the expanded shortcode.
3617
 */
3618
function get_post_galleries( $post, $html = true ) {
3619
	if ( ! $post = get_post( $post ) )
3620
		return array();
3621
3622
	if ( ! has_shortcode( $post->post_content, 'gallery' ) )
3623
		return array();
3624
3625
	$galleries = array();
3626
	if ( preg_match_all( '/' . get_shortcode_regex() . '/s', $post->post_content, $matches, PREG_SET_ORDER ) ) {
3627
		foreach ( $matches as $shortcode ) {
3628
			if ( 'gallery' === $shortcode[2] ) {
3629
				$srcs = array();
3630
3631
				$gallery = do_shortcode_tag( $shortcode );
3632
				if ( $html ) {
3633
					$galleries[] = $gallery;
3634
				} else {
3635
					preg_match_all( '#src=([\'"])(.+?)\1#is', $gallery, $src, PREG_SET_ORDER );
3636
					if ( ! empty( $src ) ) {
3637
						foreach ( $src as $s )
3638
							$srcs[] = $s[2];
3639
					}
3640
3641
					$data = shortcode_parse_atts( $shortcode[3] );
3642
					$data['src'] = array_values( array_unique( $srcs ) );
3643
					$galleries[] = $data;
3644
				}
3645
			}
3646
		}
3647
	}
3648
3649
	/**
3650
	 * Filters the list of all found galleries in the given post.
3651
	 *
3652
	 * @since 3.6.0
3653
	 *
3654
	 * @param array   $galleries Associative array of all found post galleries.
3655
	 * @param WP_Post $post      Post object.
3656
	 */
3657
	return apply_filters( 'get_post_galleries', $galleries, $post );
3658
}
3659
3660
/**
3661
 * Check a specified post's content for gallery and, if present, return the first
3662
 *
3663
 * @since 3.6.0
3664
 *
3665
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
3666
 * @param bool        $html Optional. Whether to return HTML or data. Default is true.
3667
 * @return string|array Gallery data and srcs parsed from the expanded shortcode.
3668
 */
3669
function get_post_gallery( $post = 0, $html = true ) {
3670
	$galleries = get_post_galleries( $post, $html );
3671
	$gallery = reset( $galleries );
3672
3673
	/**
3674
	 * Filters the first-found post gallery.
3675
	 *
3676
	 * @since 3.6.0
3677
	 *
3678
	 * @param array       $gallery   The first-found post gallery.
3679
	 * @param int|WP_Post $post      Post ID or object.
3680
	 * @param array       $galleries Associative array of all found post galleries.
3681
	 */
3682
	return apply_filters( 'get_post_gallery', $gallery, $post, $galleries );
3683
}
3684
3685
/**
3686
 * Retrieve the image srcs from galleries from a post's content, if present
3687
 *
3688
 * @since 3.6.0
3689
 *
3690
 * @see get_post_galleries()
3691
 *
3692
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global `$post`.
3693
 * @return array A list of lists, each containing image srcs parsed.
3694
 *               from an expanded shortcode
3695
 */
3696
function get_post_galleries_images( $post = 0 ) {
3697
	$galleries = get_post_galleries( $post, false );
3698
	return wp_list_pluck( $galleries, 'src' );
3699
}
3700
3701
/**
3702
 * Checks a post's content for galleries and return the image srcs for the first found gallery
3703
 *
3704
 * @since 3.6.0
3705
 *
3706
 * @see get_post_gallery()
3707
 *
3708
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global `$post`.
3709
 * @return array A list of a gallery's image srcs in order.
3710
 */
3711
function get_post_gallery_images( $post = 0 ) {
3712
	$gallery = get_post_gallery( $post, false );
3713
	return empty( $gallery['src'] ) ? array() : $gallery['src'];
3714
}
3715
3716
/**
3717
 * Maybe attempts to generate attachment metadata, if missing.
3718
 *
3719
 * @since 3.9.0
3720
 *
3721
 * @param WP_Post $attachment Attachment object.
3722
 */
3723
function wp_maybe_generate_attachment_metadata( $attachment ) {
3724
	if ( empty( $attachment ) || ( empty( $attachment->ID ) || ! $attachment_id = (int) $attachment->ID ) ) {
3725
		return;
3726
	}
3727
3728
	$file = get_attached_file( $attachment_id );
3729
	$meta = wp_get_attachment_metadata( $attachment_id );
3730
	if ( empty( $meta ) && file_exists( $file ) ) {
3731
		$_meta = get_post_meta( $attachment_id );
3732
		$regeneration_lock = 'wp_generating_att_' . $attachment_id;
3733
		if ( ! array_key_exists( '_wp_attachment_metadata', $_meta ) && ! get_transient( $regeneration_lock ) ) {
3734
			set_transient( $regeneration_lock, $file );
3735
			wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
0 ignored issues
show
Security Bug introduced by
It seems like $file defined by get_attached_file($attachment_id) on line 3728 can also be of type false; however, wp_generate_attachment_metadata() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
3736
			delete_transient( $regeneration_lock );
3737
		}
3738
	}
3739
}
3740
3741
/**
3742
 * Tries to convert an attachment URL into a post ID.
3743
 *
3744
 * @since 4.0.0
3745
 *
3746
 * @global wpdb $wpdb WordPress database abstraction object.
3747
 *
3748
 * @param string $url The URL to resolve.
3749
 * @return int The found post ID, or 0 on failure.
3750
 */
3751
function attachment_url_to_postid( $url ) {
3752
	global $wpdb;
3753
3754
	$dir = wp_get_upload_dir();
3755
	$path = $url;
3756
3757
	$site_url = parse_url( $dir['url'] );
3758
	$image_path = parse_url( $path );
3759
3760
	//force the protocols to match if needed
3761
	if ( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) {
3762
		$path = str_replace( $image_path['scheme'], $site_url['scheme'], $path );
3763
	}
3764
3765
	if ( 0 === strpos( $path, $dir['baseurl'] . '/' ) ) {
3766
		$path = substr( $path, strlen( $dir['baseurl'] . '/' ) );
3767
	}
3768
3769
	$sql = $wpdb->prepare(
3770
		"SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
3771
		$path
3772
	);
3773
	$post_id = $wpdb->get_var( $sql );
3774
3775
	/**
3776
	 * Filters an attachment id found by URL.
3777
	 *
3778
	 * @since 4.2.0
3779
	 *
3780
	 * @param int|null $post_id The post_id (if any) found by the function.
3781
	 * @param string   $url     The URL being looked up.
3782
	 */
3783
	return (int) apply_filters( 'attachment_url_to_postid', $post_id, $url );
3784
}
3785
3786
/**
3787
 * Returns the URLs for CSS files used in an iframe-sandbox'd TinyMCE media view.
3788
 *
3789
 * @since 4.0.0
3790
 *
3791
 * @global string $wp_version
3792
 *
3793
 * @return array The relevant CSS file URLs.
3794
 */
3795
function wpview_media_sandbox_styles() {
3796
 	$version = 'ver=' . $GLOBALS['wp_version'];
3797
 	$mediaelement = includes_url( "js/mediaelement/mediaelementplayer.min.css?$version" );
3798
 	$wpmediaelement = includes_url( "js/mediaelement/wp-mediaelement.css?$version" );
3799
3800
	return array( $mediaelement, $wpmediaelement );
3801
}
3802