Issues (2010)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

wp-includes/media.php (23 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

Code
1
<?php
2
/**
3
 * WordPress API for media display.
4
 *
5
 * @package WordPress
6
 * @subpackage Media
7
 */
8
9
/**
10
 * Retrieve additional image sizes.
11
 *
12
 * @since 4.7.0
13
 *
14
 * @global array $_wp_additional_image_sizes
15
 *
16
 * @return array Additional images size data.
17
 */
18
function wp_get_additional_image_sizes() {
19
	global $_wp_additional_image_sizes;
20
	if ( ! $_wp_additional_image_sizes ) {
21
		$_wp_additional_image_sizes = array();
22
	}
23
	return $_wp_additional_image_sizes;
24
}
25
26
/**
27
 * Scale down the default size of an image.
28
 *
29
 * This is so that the image is a better fit for the editor and theme.
30
 *
31
 * The `$size` parameter accepts either an array or a string. The supported string
32
 * values are 'thumb' or 'thumbnail' for the given thumbnail size or defaults at
33
 * 128 width and 96 height in pixels. Also supported for the string value is
34
 * 'medium', 'medium_large' and 'full'. The 'full' isn't actually supported, but any value other
35
 * than the supported will result in the content_width size or 500 if that is
36
 * not set.
37
 *
38
 * Finally, there is a filter named {@see 'editor_max_image_size'}, that will be
39
 * called on the calculated array for width and height, respectively. The second
40
 * parameter will be the value that was in the $size parameter. The returned
41
 * type for the hook is an array with the width as the first element and the
42
 * height as the second element.
43
 *
44
 * @since 2.5.0
45
 *
46
 * @global int   $content_width
47
 *
48
 * @param int          $width   Width of the image in pixels.
49
 * @param int          $height  Height of the image in pixels.
50
 * @param string|array $size    Optional. Image size. Accepts any valid image size, or an array
51
 *                              of width and height values in pixels (in that order).
52
 *                              Default 'medium'.
53
 * @param string       $context Optional. Could be 'display' (like in a theme) or 'edit'
54
 *                              (like inserting into an editor). Default null.
55
 * @return array Width and height of what the result image should resize to.
56
 */
57
function image_constrain_size_for_editor( $width, $height, $size = 'medium', $context = null ) {
58
	global $content_width;
59
60
	$_wp_additional_image_sizes = wp_get_additional_image_sizes();
61
62
	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...
63
		$context = is_admin() ? 'edit' : 'display';
64
65
	if ( is_array($size) ) {
66
		$max_width = $size[0];
67
		$max_height = $size[1];
68
	}
69
	elseif ( $size == 'thumb' || $size == 'thumbnail' ) {
70
		$max_width = intval(get_option('thumbnail_size_w'));
71
		$max_height = intval(get_option('thumbnail_size_h'));
72
		// last chance thumbnail size defaults
73
		if ( !$max_width && !$max_height ) {
74
			$max_width = 128;
75
			$max_height = 96;
76
		}
77
	}
78
	elseif ( $size == 'medium' ) {
79
		$max_width = intval(get_option('medium_size_w'));
80
		$max_height = intval(get_option('medium_size_h'));
81
82
	}
83 View Code Duplication
	elseif ( $size == 'medium_large' ) {
84
		$max_width = intval( get_option( 'medium_large_size_w' ) );
85
		$max_height = intval( get_option( 'medium_large_size_h' ) );
86
87
		if ( intval( $content_width ) > 0 ) {
88
			$max_width = min( intval( $content_width ), $max_width );
89
		}
90
	}
91 View Code Duplication
	elseif ( $size == 'large' ) {
92
		/*
93
		 * We're inserting a large size image into the editor. If it's a really
94
		 * big image we'll scale it down to fit reasonably within the editor
95
		 * itself, and within the theme's content width if it's known. The user
96
		 * can resize it in the editor if they wish.
97
		 */
98
		$max_width = intval(get_option('large_size_w'));
99
		$max_height = intval(get_option('large_size_h'));
100
		if ( intval($content_width) > 0 ) {
101
			$max_width = min( intval($content_width), $max_width );
102
		}
103
	} elseif ( ! empty( $_wp_additional_image_sizes ) && in_array( $size, array_keys( $_wp_additional_image_sizes ) ) ) {
104
		$max_width = intval( $_wp_additional_image_sizes[$size]['width'] );
105
		$max_height = intval( $_wp_additional_image_sizes[$size]['height'] );
106
		// Only in admin. Assume that theme authors know what they're doing.
107
		if ( intval( $content_width ) > 0 && 'edit' === $context ) {
108
			$max_width = min( intval( $content_width ), $max_width );
109
		}
110
	}
111
	// $size == 'full' has no constraint
112
	else {
113
		$max_width = $width;
114
		$max_height = $height;
115
	}
116
117
	/**
118
	 * Filters the maximum image size dimensions for the editor.
119
	 *
120
	 * @since 2.5.0
121
	 *
122
	 * @param array        $max_image_size An array with the width as the first element,
123
	 *                                     and the height as the second element.
124
	 * @param string|array $size           Size of what the result image should be.
125
	 * @param string       $context        The context the image is being resized for.
126
	 *                                     Possible values are 'display' (like in a theme)
127
	 *                                     or 'edit' (like inserting into an editor).
128
	 */
129
	list( $max_width, $max_height ) = apply_filters( 'editor_max_image_size', array( $max_width, $max_height ), $size, $context );
130
131
	return wp_constrain_dimensions( $width, $height, $max_width, $max_height );
132
}
133
134
/**
135
 * Retrieve width and height attributes using given width and height values.
136
 *
137
 * Both attributes are required in the sense that both parameters must have a
138
 * value, but are optional in that if you set them to false or null, then they
139
 * will not be added to the returned string.
140
 *
141
 * You can set the value using a string, but it will only take numeric values.
142
 * If you wish to put 'px' after the numbers, then it will be stripped out of
143
 * the return.
144
 *
145
 * @since 2.5.0
146
 *
147
 * @param int|string $width  Image width in pixels.
148
 * @param int|string $height Image height in pixels.
149
 * @return string HTML attributes for width and, or height.
150
 */
151
function image_hwstring( $width, $height ) {
152
	$out = '';
153
	if ($width)
154
		$out .= 'width="'.intval($width).'" ';
155
	if ($height)
156
		$out .= 'height="'.intval($height).'" ';
157
	return $out;
158
}
159
160
/**
161
 * Scale an image to fit a particular size (such as 'thumb' or 'medium').
162
 *
163
 * Array with image url, width, height, and whether is intermediate size, in
164
 * that order is returned on success is returned. $is_intermediate is true if
165
 * $url is a resized image, false if it is the original.
166
 *
167
 * The URL might be the original image, or it might be a resized version. This
168
 * function won't create a new resized copy, it will just return an already
169
 * resized one if it exists.
170
 *
171
 * A plugin may use the {@see 'image_downsize'} filter to hook into and offer image
172
 * resizing services for images. The hook must return an array with the same
173
 * elements that are returned in the function. The first element being the URL
174
 * to the new image that was resized.
175
 *
176
 * @since 2.5.0
177
 *
178
 * @param int          $id   Attachment ID for image.
179
 * @param array|string $size Optional. Image size to scale to. Accepts any valid image size,
180
 *                           or an array of width and height values in pixels (in that order).
181
 *                           Default 'medium'.
182
 * @return false|array Array containing the image URL, width, height, and boolean for whether
183
 *                     the image is an intermediate size. False on failure.
184
 */
185
function image_downsize( $id, $size = 'medium' ) {
186
187
	if ( !wp_attachment_is_image($id) )
188
		return false;
189
190
	/**
191
	 * Filters whether to preempt the output of image_downsize().
192
	 *
193
	 * Passing a truthy value to the filter will effectively short-circuit
194
	 * down-sizing the image, returning that value as output instead.
195
	 *
196
	 * @since 2.5.0
197
	 *
198
	 * @param bool         $downsize Whether to short-circuit the image downsize. Default false.
199
	 * @param int          $id       Attachment ID for image.
200
	 * @param array|string $size     Size of image. Image size or array of width and height values (in that order).
201
	 *                               Default 'medium'.
202
	 */
203
	if ( $out = apply_filters( 'image_downsize', false, $id, $size ) ) {
204
		return $out;
205
	}
206
207
	$img_url = wp_get_attachment_url($id);
208
	$meta = wp_get_attachment_metadata($id);
209
	$width = $height = 0;
210
	$is_intermediate = false;
211
	$img_url_basename = wp_basename($img_url);
0 ignored issues
show
It seems like $img_url defined by wp_get_attachment_url($id) on line 207 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...
212
213
	// try for a new style intermediate size
214
	if ( $intermediate = image_get_intermediate_size($id, $size) ) {
215
		$img_url = str_replace($img_url_basename, $intermediate['file'], $img_url);
216
		$width = $intermediate['width'];
217
		$height = $intermediate['height'];
218
		$is_intermediate = true;
219
	}
220
	elseif ( $size == 'thumbnail' ) {
221
		// fall back to the old thumbnail
222
		if ( ($thumb_file = wp_get_attachment_thumb_file($id)) && $info = getimagesize($thumb_file) ) {
223
			$img_url = str_replace($img_url_basename, wp_basename($thumb_file), $img_url);
224
			$width = $info[0];
225
			$height = $info[1];
226
			$is_intermediate = true;
227
		}
228
	}
229
	if ( !$width && !$height && isset( $meta['width'], $meta['height'] ) ) {
230
		// any other type: use the real image
231
		$width = $meta['width'];
232
		$height = $meta['height'];
233
	}
234
235
	if ( $img_url) {
236
		// we have the actual image size, but might need to further constrain it if content_width is narrower
237
		list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size );
238
239
		return array( $img_url, $width, $height, $is_intermediate );
240
	}
241
	return false;
242
243
}
244
245
/**
246
 * Register a new image size.
247
 *
248
 * Cropping behavior for the image size is dependent on the value of $crop:
249
 * 1. If false (default), images will be scaled, not cropped.
250
 * 2. If an array in the form of array( x_crop_position, y_crop_position ):
251
 *    - x_crop_position accepts 'left' 'center', or 'right'.
252
 *    - y_crop_position accepts 'top', 'center', or 'bottom'.
253
 *    Images will be cropped to the specified dimensions within the defined crop area.
254
 * 3. If true, images will be cropped to the specified dimensions using center positions.
255
 *
256
 * @since 2.9.0
257
 *
258
 * @global array $_wp_additional_image_sizes Associative array of additional image sizes.
259
 *
260
 * @param string     $name   Image size identifier.
261
 * @param int        $width  Image width in pixels.
262
 * @param int        $height Image height in pixels.
263
 * @param bool|array $crop   Optional. Whether to crop images to specified width and height or resize.
264
 *                           An array can specify positioning of the crop area. Default false.
265
 */
266
function add_image_size( $name, $width = 0, $height = 0, $crop = false ) {
267
	global $_wp_additional_image_sizes;
268
269
	$_wp_additional_image_sizes[ $name ] = array(
270
		'width'  => absint( $width ),
271
		'height' => absint( $height ),
272
		'crop'   => $crop,
273
	);
274
}
275
276
/**
277
 * Check if an image size exists.
278
 *
279
 * @since 3.9.0
280
 *
281
 * @param string $name The image size to check.
282
 * @return bool True if the image size exists, false if not.
283
 */
284
function has_image_size( $name ) {
285
	$sizes = wp_get_additional_image_sizes();
286
	return isset( $sizes[ $name ] );
287
}
288
289
/**
290
 * Remove a new image size.
291
 *
292
 * @since 3.9.0
293
 *
294
 * @global array $_wp_additional_image_sizes
295
 *
296
 * @param string $name The image size to remove.
297
 * @return bool True if the image size was successfully removed, false on failure.
298
 */
299
function remove_image_size( $name ) {
300
	global $_wp_additional_image_sizes;
301
302
	if ( isset( $_wp_additional_image_sizes[ $name ] ) ) {
303
		unset( $_wp_additional_image_sizes[ $name ] );
304
		return true;
305
	}
306
307
	return false;
308
}
309
310
/**
311
 * Registers an image size for the post thumbnail.
312
 *
313
 * @since 2.9.0
314
 *
315
 * @see add_image_size() for details on cropping behavior.
316
 *
317
 * @param int        $width  Image width in pixels.
318
 * @param int        $height Image height in pixels.
319
 * @param bool|array $crop   Optional. Whether to crop images to specified width and height or resize.
320
 *                           An array can specify positioning of the crop area. Default false.
321
 */
322
function set_post_thumbnail_size( $width = 0, $height = 0, $crop = false ) {
323
	add_image_size( 'post-thumbnail', $width, $height, $crop );
324
}
325
326
/**
327
 * Gets an img tag for an image attachment, scaling it down if requested.
328
 *
329
 * The {@see 'get_image_tag_class'} filter allows for changing the class name for the
330
 * image without having to use regular expressions on the HTML content. The
331
 * parameters are: what WordPress will use for the class, the Attachment ID,
332
 * image align value, and the size the image should be.
333
 *
334
 * The second filter, {@see 'get_image_tag'}, has the HTML content, which can then be
335
 * further manipulated by a plugin to change all attribute values and even HTML
336
 * content.
337
 *
338
 * @since 2.5.0
339
 *
340
 * @param int          $id    Attachment ID.
341
 * @param string       $alt   Image Description for the alt attribute.
342
 * @param string       $title Image Description for the title attribute.
343
 * @param string       $align Part of the class name for aligning the image.
344
 * @param string|array $size  Optional. Registered image size to retrieve a tag for. Accepts any
345
 *                            valid image size, or an array of width and height values in pixels
346
 *                            (in that order). Default 'medium'.
347
 * @return string HTML IMG element for given image attachment
348
 */
349
function get_image_tag( $id, $alt, $title, $align, $size = 'medium' ) {
350
351
	list( $img_src, $width, $height ) = image_downsize($id, $size);
352
	$hwstring = image_hwstring($width, $height);
353
354
	$title = $title ? 'title="' . esc_attr( $title ) . '" ' : '';
355
356
	$class = 'align' . esc_attr($align) .' size-' . esc_attr($size) . ' wp-image-' . $id;
0 ignored issues
show
It seems like $size defined by parameter $size on line 349 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...
357
358
	/**
359
	 * Filters the value of the attachment's image tag class attribute.
360
	 *
361
	 * @since 2.6.0
362
	 *
363
	 * @param string       $class CSS class name or space-separated list of classes.
364
	 * @param int          $id    Attachment ID.
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
	$class = apply_filters( 'get_image_tag_class', $class, $id, $align, $size );
370
371
	$html = '<img src="' . esc_attr($img_src) . '" alt="' . esc_attr($alt) . '" ' . $title . $hwstring . 'class="' . $class . '" />';
372
373
	/**
374
	 * Filters the HTML content for the image tag.
375
	 *
376
	 * @since 2.6.0
377
	 *
378
	 * @param string       $html  HTML content for the image.
379
	 * @param int          $id    Attachment ID.
380
	 * @param string       $alt   Alternate text.
381
	 * @param string       $title Attachment title.
382
	 * @param string       $align Part of the class name for aligning the image.
383
	 * @param string|array $size  Size of image. Image size or array of width and height values (in that order).
384
	 *                            Default 'medium'.
385
	 */
386
	return apply_filters( 'get_image_tag', $html, $id, $alt, $title, $align, $size );
387
}
388
389
/**
390
 * Calculates the new dimensions for a down-sampled image.
391
 *
392
 * If either width or height are empty, no constraint is applied on
393
 * that dimension.
394
 *
395
 * @since 2.5.0
396
 *
397
 * @param int $current_width  Current width of the image.
398
 * @param int $current_height Current height of the image.
399
 * @param int $max_width      Optional. Max width in pixels to constrain to. Default 0.
400
 * @param int $max_height     Optional. Max height in pixels to constrain to. Default 0.
401
 * @return array First item is the width, the second item is the height.
402
 */
403
function wp_constrain_dimensions( $current_width, $current_height, $max_width = 0, $max_height = 0 ) {
404
	if ( !$max_width && !$max_height )
405
		return array( $current_width, $current_height );
406
407
	$width_ratio = $height_ratio = 1.0;
408
	$did_width = $did_height = false;
409
410
	if ( $max_width > 0 && $current_width > 0 && $current_width > $max_width ) {
411
		$width_ratio = $max_width / $current_width;
412
		$did_width = true;
413
	}
414
415
	if ( $max_height > 0 && $current_height > 0 && $current_height > $max_height ) {
416
		$height_ratio = $max_height / $current_height;
417
		$did_height = true;
418
	}
419
420
	// Calculate the larger/smaller ratios
421
	$smaller_ratio = min( $width_ratio, $height_ratio );
422
	$larger_ratio  = max( $width_ratio, $height_ratio );
423
424
	if ( (int) round( $current_width * $larger_ratio ) > $max_width || (int) round( $current_height * $larger_ratio ) > $max_height ) {
425
 		// The larger ratio is too big. It would result in an overflow.
426
		$ratio = $smaller_ratio;
427
	} else {
428
		// The larger ratio fits, and is likely to be a more "snug" fit.
429
		$ratio = $larger_ratio;
430
	}
431
432
	// Very small dimensions may result in 0, 1 should be the minimum.
433
	$w = max ( 1, (int) round( $current_width  * $ratio ) );
434
	$h = max ( 1, (int) round( $current_height * $ratio ) );
435
436
	// Sometimes, due to rounding, we'll end up with a result like this: 465x700 in a 177x177 box is 117x176... a pixel short
437
	// 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.
438
	// Thus we look for dimensions that are one pixel shy of the max value and bump them up
439
440
	// Note: $did_width means it is possible $smaller_ratio == $width_ratio.
441
	if ( $did_width && $w == $max_width - 1 ) {
442
		$w = $max_width; // Round it up
443
	}
444
445
	// Note: $did_height means it is possible $smaller_ratio == $height_ratio.
446
	if ( $did_height && $h == $max_height - 1 ) {
447
		$h = $max_height; // Round it up
448
	}
449
450
	/**
451
	 * Filters dimensions to constrain down-sampled images to.
452
	 *
453
	 * @since 4.1.0
454
	 *
455
	 * @param array $dimensions     The image width and height.
456
	 * @param int 	$current_width  The current width of the image.
457
	 * @param int 	$current_height The current height of the image.
458
	 * @param int 	$max_width      The maximum width permitted.
459
	 * @param int 	$max_height     The maximum height permitted.
460
	 */
461
	return apply_filters( 'wp_constrain_dimensions', array( $w, $h ), $current_width, $current_height, $max_width, $max_height );
462
}
463
464
/**
465
 * Retrieves calculated resize dimensions for use in WP_Image_Editor.
466
 *
467
 * Calculates dimensions and coordinates for a resized image that fits
468
 * within a specified width and height.
469
 *
470
 * Cropping behavior is dependent on the value of $crop:
471
 * 1. If false (default), images will not be cropped.
472
 * 2. If an array in the form of array( x_crop_position, y_crop_position ):
473
 *    - x_crop_position accepts 'left' 'center', or 'right'.
474
 *    - y_crop_position accepts 'top', 'center', or 'bottom'.
475
 *    Images will be cropped to the specified dimensions within the defined crop area.
476
 * 3. If true, images will be cropped to the specified dimensions using center positions.
477
 *
478
 * @since 2.5.0
479
 *
480
 * @param int        $orig_w Original width in pixels.
481
 * @param int        $orig_h Original height in pixels.
482
 * @param int        $dest_w New width in pixels.
483
 * @param int        $dest_h New height in pixels.
484
 * @param bool|array $crop   Optional. Whether to crop image to specified width and height or resize.
485
 *                           An array can specify positioning of the crop area. Default false.
486
 * @return false|array False on failure. Returned array matches parameters for `imagecopyresampled()`.
487
 */
488
function image_resize_dimensions( $orig_w, $orig_h, $dest_w, $dest_h, $crop = false ) {
489
490
	if ($orig_w <= 0 || $orig_h <= 0)
491
		return false;
492
	// at least one of dest_w or dest_h must be specific
493
	if ($dest_w <= 0 && $dest_h <= 0)
494
		return false;
495
496
	/**
497
	 * Filters whether to preempt calculating the image resize dimensions.
498
	 *
499
	 * Passing a non-null value to the filter will effectively short-circuit
500
	 * image_resize_dimensions(), returning that value instead.
501
	 *
502
	 * @since 3.4.0
503
	 *
504
	 * @param null|mixed $null   Whether to preempt output of the resize dimensions.
505
	 * @param int        $orig_w Original width in pixels.
506
	 * @param int        $orig_h Original height in pixels.
507
	 * @param int        $dest_w New width in pixels.
508
	 * @param int        $dest_h New height in pixels.
509
	 * @param bool|array $crop   Whether to crop image to specified width and height or resize.
510
	 *                           An array can specify positioning of the crop area. Default false.
511
	 */
512
	$output = apply_filters( 'image_resize_dimensions', null, $orig_w, $orig_h, $dest_w, $dest_h, $crop );
513
	if ( null !== $output )
514
		return $output;
515
516
	if ( $crop ) {
517
		// crop the largest possible portion of the original image that we can size to $dest_w x $dest_h
518
		$aspect_ratio = $orig_w / $orig_h;
519
		$new_w = min($dest_w, $orig_w);
520
		$new_h = min($dest_h, $orig_h);
521
522
		if ( ! $new_w ) {
523
			$new_w = (int) round( $new_h * $aspect_ratio );
524
		}
525
526
		if ( ! $new_h ) {
527
			$new_h = (int) round( $new_w / $aspect_ratio );
528
		}
529
530
		$size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
531
532
		$crop_w = round($new_w / $size_ratio);
533
		$crop_h = round($new_h / $size_ratio);
534
535
		if ( ! is_array( $crop ) || count( $crop ) !== 2 ) {
536
			$crop = array( 'center', 'center' );
537
		}
538
539
		list( $x, $y ) = $crop;
540
541
		if ( 'left' === $x ) {
542
			$s_x = 0;
543
		} elseif ( 'right' === $x ) {
544
			$s_x = $orig_w - $crop_w;
545
		} else {
546
			$s_x = floor( ( $orig_w - $crop_w ) / 2 );
547
		}
548
549
		if ( 'top' === $y ) {
550
			$s_y = 0;
551
		} elseif ( 'bottom' === $y ) {
552
			$s_y = $orig_h - $crop_h;
553
		} else {
554
			$s_y = floor( ( $orig_h - $crop_h ) / 2 );
555
		}
556
	} else {
557
		// don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
558
		$crop_w = $orig_w;
559
		$crop_h = $orig_h;
560
561
		$s_x = 0;
562
		$s_y = 0;
563
564
		list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
565
	}
566
567
	// if the resulting image would be the same size or larger we don't want to resize it
568
	if ( $new_w >= $orig_w && $new_h >= $orig_h && $dest_w != $orig_w && $dest_h != $orig_h ) {
569
		return false;
570
	}
571
572
	// the return array matches the parameters to imagecopyresampled()
573
	// int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
574
	return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h );
575
576
}
577
578
/**
579
 * Resizes an image to make a thumbnail or intermediate size.
580
 *
581
 * The returned array has the file size, the image width, and image height. The
582
 * {@see 'image_make_intermediate_size'} filter can be used to hook in and change the
583
 * values of the returned array. The only parameter is the resized file path.
584
 *
585
 * @since 2.5.0
586
 *
587
 * @param string $file   File path.
588
 * @param int    $width  Image width.
589
 * @param int    $height Image height.
590
 * @param bool   $crop   Optional. Whether to crop image to specified width and height or resize.
591
 *                       Default false.
592
 * @return false|array False, if no image was created. Metadata array on success.
593
 */
594
function image_make_intermediate_size( $file, $width, $height, $crop = false ) {
595
	if ( $width || $height ) {
596
		$editor = wp_get_image_editor( $file );
597
598
		if ( is_wp_error( $editor ) || is_wp_error( $editor->resize( $width, $height, $crop ) ) )
599
			return false;
600
601
		$resized_file = $editor->save();
602
603
		if ( ! is_wp_error( $resized_file ) && $resized_file ) {
604
			unset( $resized_file['path'] );
605
			return $resized_file;
606
		}
607
	}
608
	return false;
609
}
610
611
/**
612
 * Helper function to test if aspect ratios for two images match.
613
 *
614
 * @since 4.6.0
615
 *
616
 * @param int $source_width  Width of the first image in pixels.
617
 * @param int $source_height Height of the first image in pixels.
618
 * @param int $target_width  Width of the second image in pixels.
619
 * @param int $target_height Height of the second image in pixels.
620
 * @return bool True if aspect ratios match within 1px. False if not.
621
 */
622
function wp_image_matches_ratio( $source_width, $source_height, $target_width, $target_height ) {
623
	/*
624
	 * To test for varying crops, we constrain the dimensions of the larger image
625
	 * to the dimensions of the smaller image and see if they match.
626
	 */
627
	if ( $source_width > $target_width ) {
628
		$constrained_size = wp_constrain_dimensions( $source_width, $source_height, $target_width );
629
		$expected_size = array( $target_width, $target_height );
630
	} else {
631
		$constrained_size = wp_constrain_dimensions( $target_width, $target_height, $source_width );
632
		$expected_size = array( $source_width, $source_height );
633
	}
634
635
	// If the image dimensions are within 1px of the expected size, we consider it a match.
636
	$matched = ( abs( $constrained_size[0] - $expected_size[0] ) <= 1 && abs( $constrained_size[1] - $expected_size[1] ) <= 1 );
637
638
	return $matched;
639
}
640
641
/**
642
 * Retrieves the image's intermediate size (resized) path, width, and height.
643
 *
644
 * The $size parameter can be an array with the width and height respectively.
645
 * If the size matches the 'sizes' metadata array for width and height, then it
646
 * will be used. If there is no direct match, then the nearest image size larger
647
 * than the specified size will be used. If nothing is found, then the function
648
 * will break out and return false.
649
 *
650
 * The metadata 'sizes' is used for compatible sizes that can be used for the
651
 * parameter $size value.
652
 *
653
 * The url path will be given, when the $size parameter is a string.
654
 *
655
 * If you are passing an array for the $size, you should consider using
656
 * add_image_size() so that a cropped version is generated. It's much more
657
 * efficient than having to find the closest-sized image and then having the
658
 * browser scale down the image.
659
 *
660
 * @since 2.5.0
661
 *
662
 * @param int          $post_id Attachment ID.
663
 * @param array|string $size    Optional. Image size. Accepts any valid image size, or an array
664
 *                              of width and height values in pixels (in that order).
665
 *                              Default 'thumbnail'.
666
 * @return false|array $data {
667
 *     Array of file relative path, width, and height on success. Additionally includes absolute
668
 *     path and URL if registered size is passed to $size parameter. False on failure.
669
 *
670
 *     @type string $file   Image's path relative to uploads directory
671
 *     @type int    $width  Width of image
672
 *     @type int    $height Height of image
673
 *     @type string $path   Image's absolute filesystem path.
674
 *     @type string $url    Image's URL.
675
 * }
676
 */
677
function image_get_intermediate_size( $post_id, $size = 'thumbnail' ) {
678
	if ( ! $size || ! is_array( $imagedata = wp_get_attachment_metadata( $post_id ) ) || empty( $imagedata['sizes'] )  ) {
679
		return false;
680
	}
681
682
	$data = array();
683
684
	// Find the best match when '$size' is an array.
685
	if ( is_array( $size ) ) {
686
		$candidates = array();
687
688
		foreach ( $imagedata['sizes'] as $_size => $data ) {
689
			// If there's an exact match to an existing image size, short circuit.
690
			if ( $data['width'] == $size[0] && $data['height'] == $size[1] ) {
691
				$candidates[ $data['width'] * $data['height'] ] = $data;
692
				break;
693
			}
694
695
			// If it's not an exact match, consider larger sizes with the same aspect ratio.
696
			if ( $data['width'] >= $size[0] && $data['height'] >= $size[1] ) {
697
				// If '0' is passed to either size, we test ratios against the original file.
698
				if ( 0 === $size[0] || 0 === $size[1] ) {
699
					$same_ratio = wp_image_matches_ratio( $data['width'], $data['height'], $imagedata['width'], $imagedata['height'] );
700
				} else {
701
					$same_ratio = wp_image_matches_ratio( $data['width'], $data['height'], $size[0], $size[1] );
702
				}
703
704
				if ( $same_ratio ) {
705
					$candidates[ $data['width'] * $data['height'] ] = $data;
706
				}
707
			}
708
		}
709
710
		if ( ! empty( $candidates ) ) {
711
			// Sort the array by size if we have more than one candidate.
712
			if ( 1 < count( $candidates ) ) {
713
				ksort( $candidates );
714
			}
715
716
			$data = array_shift( $candidates );
717
		/*
718
		 * When the size requested is smaller than the thumbnail dimensions, we
719
		 * fall back to the thumbnail size to maintain backwards compatibility with
720
		 * pre 4.6 versions of WordPress.
721
		 */
722
		} elseif ( ! empty( $imagedata['sizes']['thumbnail'] ) && $imagedata['sizes']['thumbnail']['width'] >= $size[0] && $imagedata['sizes']['thumbnail']['width'] >= $size[1] ) {
723
			$data = $imagedata['sizes']['thumbnail'];
724
		} else {
725
			return false;
726
		}
727
728
		// Constrain the width and height attributes to the requested values.
729
		list( $data['width'], $data['height'] ) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
730
731
	} elseif ( ! empty( $imagedata['sizes'][ $size ] ) ) {
732
		$data = $imagedata['sizes'][ $size ];
733
	}
734
735
	// If we still don't have a match at this point, return false.
736
	if ( empty( $data ) ) {
737
		return false;
738
	}
739
740
	// include the full filesystem path of the intermediate file
741
	if ( empty($data['path']) && !empty($data['file']) ) {
742
		$file_url = wp_get_attachment_url($post_id);
743
		$data['path'] = path_join( dirname($imagedata['file']), $data['file'] );
744
		$data['url'] = path_join( dirname($file_url), $data['file'] );
745
	}
746
747
	/**
748
	 * Filters the output of image_get_intermediate_size()
749
	 *
750
	 * @since 4.4.0
751
	 *
752
	 * @see image_get_intermediate_size()
753
	 *
754
	 * @param array        $data    Array of file relative path, width, and height on success. May also include
755
	 *                              file absolute path and URL.
756
	 * @param int          $post_id The post_id of the image attachment
757
	 * @param string|array $size    Registered image size or flat array of initially-requested height and width
758
	 *                              dimensions (in that order).
759
	 */
760
	return apply_filters( 'image_get_intermediate_size', $data, $post_id, $size );
761
}
762
763
/**
764
 * Gets the available intermediate image sizes.
765
 *
766
 * @since 3.0.0
767
 *
768
 * @return array Returns a filtered array of image size strings.
769
 */
770
function get_intermediate_image_sizes() {
771
	$_wp_additional_image_sizes = wp_get_additional_image_sizes();
772
	$image_sizes = array('thumbnail', 'medium', 'medium_large', 'large'); // Standard sizes
773
	if ( ! empty( $_wp_additional_image_sizes ) ) {
774
		$image_sizes = array_merge( $image_sizes, array_keys( $_wp_additional_image_sizes ) );
775
	}
776
777
	/**
778
	 * Filters the list of intermediate image sizes.
779
	 *
780
	 * @since 2.5.0
781
	 *
782
	 * @param array $image_sizes An array of intermediate image sizes. Defaults
783
	 *                           are 'thumbnail', 'medium', 'medium_large', 'large'.
784
	 */
785
	return apply_filters( 'intermediate_image_sizes', $image_sizes );
786
}
787
788
/**
789
 * Retrieve an image to represent an attachment.
790
 *
791
 * A mime icon for files, thumbnail or intermediate size for images.
792
 *
793
 * The returned array contains four values: the URL of the attachment image src,
794
 * the width of the image file, the height of the image file, and a boolean
795
 * representing whether the returned array describes an intermediate (generated)
796
 * image size or the original, full-sized upload.
797
 *
798
 * @since 2.5.0
799
 *
800
 * @param int          $attachment_id Image attachment ID.
801
 * @param string|array $size          Optional. Image size. Accepts any valid image size, or an array of width
802
 *                                    and height values in pixels (in that order). Default 'thumbnail'.
803
 * @param bool         $icon          Optional. Whether the image should be treated as an icon. Default false.
804
 * @return false|array Returns an array (url, width, height, is_intermediate), or false, if no image is available.
805
 */
806
function wp_get_attachment_image_src( $attachment_id, $size = 'thumbnail', $icon = false ) {
807
	// get a thumbnail or intermediate image if there is one
808
	$image = image_downsize( $attachment_id, $size );
809
	if ( ! $image ) {
810
		$src = false;
811
812
		if ( $icon && $src = wp_mime_type_icon( $attachment_id ) ) {
813
			/** This filter is documented in wp-includes/post.php */
814
			$icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' );
815
816
			$src_file = $icon_dir . '/' . wp_basename( $src );
817
			@list( $width, $height ) = getimagesize( $src_file );
818
		}
819
820
		if ( $src && $width && $height ) {
821
			$image = array( $src, $width, $height );
0 ignored issues
show
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...
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...
822
		}
823
	}
824
	/**
825
	 * Filters the image src result.
826
	 *
827
	 * @since 4.3.0
828
	 *
829
	 * @param array|false  $image         Either array with src, width & height, icon src, or false.
830
	 * @param int          $attachment_id Image attachment ID.
831
	 * @param string|array $size          Size of image. Image size or array of width and height values
832
	 *                                    (in that order). Default 'thumbnail'.
833
	 * @param bool         $icon          Whether the image should be treated as an icon. Default false.
834
	 */
835
	return apply_filters( 'wp_get_attachment_image_src', $image, $attachment_id, $size, $icon );
836
}
837
838
/**
839
 * Get an HTML img element representing an image attachment
840
 *
841
 * While `$size` will accept an array, it is better to register a size with
842
 * add_image_size() so that a cropped version is generated. It's much more
843
 * efficient than having to find the closest-sized image and then having the
844
 * browser scale down the image.
845
 *
846
 * @since 2.5.0
847
 *
848
 * @param int          $attachment_id Image attachment ID.
849
 * @param string|array $size          Optional. Image size. Accepts any valid image size, or an array of width
850
 *                                    and height values in pixels (in that order). Default 'thumbnail'.
851
 * @param bool         $icon          Optional. Whether the image should be treated as an icon. Default false.
852
 * @param string|array $attr          Optional. Attributes for the image markup. Default empty.
853
 * @return string HTML img element or empty string on failure.
854
 */
855
function wp_get_attachment_image($attachment_id, $size = 'thumbnail', $icon = false, $attr = '') {
856
	$html = '';
857
	$image = wp_get_attachment_image_src($attachment_id, $size, $icon);
858
	if ( $image ) {
859
		list($src, $width, $height) = $image;
860
		$hwstring = image_hwstring($width, $height);
861
		$size_class = $size;
862
		if ( is_array( $size_class ) ) {
863
			$size_class = join( 'x', $size_class );
864
		}
865
		$attachment = get_post($attachment_id);
866
		$default_attr = array(
867
			'src'	=> $src,
868
			'class'	=> "attachment-$size_class size-$size_class",
869
			'alt'	=> trim(strip_tags( get_post_meta($attachment_id, '_wp_attachment_image_alt', true) )), // Use Alt field first
870
		);
871
		if ( empty($default_attr['alt']) )
872
			$default_attr['alt'] = trim(strip_tags( $attachment->post_excerpt )); // If not, Use the Caption
873
		if ( empty($default_attr['alt']) )
874
			$default_attr['alt'] = trim(strip_tags( $attachment->post_title )); // Finally, use the title
875
876
		$attr = wp_parse_args( $attr, $default_attr );
877
878
		// Generate 'srcset' and 'sizes' if not already present.
879
		if ( empty( $attr['srcset'] ) ) {
880
			$image_meta = wp_get_attachment_metadata( $attachment_id );
881
882
			if ( is_array( $image_meta ) ) {
883
				$size_array = array( absint( $width ), absint( $height ) );
884
				$srcset = wp_calculate_image_srcset( $size_array, $src, $image_meta, $attachment_id );
885
				$sizes = wp_calculate_image_sizes( $size_array, $src, $image_meta, $attachment_id );
886
887
				if ( $srcset && ( $sizes || ! empty( $attr['sizes'] ) ) ) {
888
					$attr['srcset'] = $srcset;
889
890
					if ( empty( $attr['sizes'] ) ) {
891
						$attr['sizes'] = $sizes;
892
					}
893
				}
894
			}
895
		}
896
897
		/**
898
		 * Filters the list of attachment image attributes.
899
		 *
900
		 * @since 2.8.0
901
		 *
902
		 * @param array        $attr       Attributes for the image markup.
903
		 * @param WP_Post      $attachment Image attachment post.
904
		 * @param string|array $size       Requested size. Image size or array of width and height values
905
		 *                                 (in that order). Default 'thumbnail'.
906
		 */
907
		$attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment, $size );
908
		$attr = array_map( 'esc_attr', $attr );
909
		$html = rtrim("<img $hwstring");
910
		foreach ( $attr as $name => $value ) {
911
			$html .= " $name=" . '"' . $value . '"';
912
		}
913
		$html .= ' />';
914
	}
915
916
	return $html;
917
}
918
919
/**
920
 * Get the URL of an image attachment.
921
 *
922
 * @since 4.4.0
923
 *
924
 * @param int          $attachment_id Image attachment ID.
925
 * @param string|array $size          Optional. Image size to retrieve. Accepts any valid image size, or an array
926
 *                                    of width and height values in pixels (in that order). Default 'thumbnail'.
927
 * @param bool         $icon          Optional. Whether the image should be treated as an icon. Default false.
928
 * @return string|false Attachment URL or false if no image is available.
929
 */
930
function wp_get_attachment_image_url( $attachment_id, $size = 'thumbnail', $icon = false ) {
931
	$image = wp_get_attachment_image_src( $attachment_id, $size, $icon );
932
	return isset( $image['0'] ) ? $image['0'] : false;
933
}
934
935
/**
936
 * Get the attachment path relative to the upload directory.
937
 *
938
 * @since 4.4.1
939
 * @access private
940
 *
941
 * @param string $file Attachment file name.
942
 * @return string Attachment path relative to the upload directory.
943
 */
944
function _wp_get_attachment_relative_path( $file ) {
945
	$dirname = dirname( $file );
946
947
	if ( '.' === $dirname ) {
948
		return '';
949
	}
950
951
	if ( false !== strpos( $dirname, 'wp-content/uploads' ) ) {
952
		// Get the directory name relative to the upload directory (back compat for pre-2.7 uploads)
953
		$dirname = substr( $dirname, strpos( $dirname, 'wp-content/uploads' ) + 18 );
954
		$dirname = ltrim( $dirname, '/' );
955
	}
956
957
	return $dirname;
958
}
959
960
/**
961
 * Get the image size as array from its meta data.
962
 *
963
 * Used for responsive images.
964
 *
965
 * @since 4.4.0
966
 * @access private
967
 *
968
 * @param string $size_name  Image size. Accepts any valid image size name ('thumbnail', 'medium', etc.).
969
 * @param array  $image_meta The image meta data.
970
 * @return array|bool Array of width and height values in pixels (in that order)
971
 *                    or false if the size doesn't exist.
972
 */
973
function _wp_get_image_size_from_meta( $size_name, $image_meta ) {
974
	if ( $size_name === 'full' ) {
975
		return array(
976
			absint( $image_meta['width'] ),
977
			absint( $image_meta['height'] ),
978
		);
979
	} elseif ( ! empty( $image_meta['sizes'][$size_name] ) ) {
980
		return array(
981
			absint( $image_meta['sizes'][$size_name]['width'] ),
982
			absint( $image_meta['sizes'][$size_name]['height'] ),
983
		);
984
	}
985
986
	return false;
987
}
988
989
/**
990
 * Retrieves the value for an image attachment's 'srcset' attribute.
991
 *
992
 * @since 4.4.0
993
 *
994
 * @see wp_calculate_image_srcset()
995
 *
996
 * @param int          $attachment_id Image attachment ID.
997
 * @param array|string $size          Optional. Image size. Accepts any valid image size, or an array of
998
 *                                    width and height values in pixels (in that order). Default 'medium'.
999
 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
1000
 *                                    Default null.
1001
 * @return string|bool A 'srcset' value string or false.
1002
 */
1003 View Code Duplication
function wp_get_attachment_image_srcset( $attachment_id, $size = 'medium', $image_meta = null ) {
0 ignored issues
show
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...
1004
	if ( ! $image = wp_get_attachment_image_src( $attachment_id, $size ) ) {
1005
		return false;
1006
	}
1007
1008
	if ( ! is_array( $image_meta ) ) {
1009
		$image_meta = wp_get_attachment_metadata( $attachment_id );
1010
	}
1011
1012
	$image_src = $image[0];
1013
	$size_array = array(
1014
		absint( $image[1] ),
1015
		absint( $image[2] )
1016
	);
1017
1018
	return wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id );
1019
}
1020
1021
/**
1022
 * A helper function to calculate the image sources to include in a 'srcset' attribute.
1023
 *
1024
 * @since 4.4.0
1025
 *
1026
 * @param array  $size_array    Array of width and height values in pixels (in that order).
1027
 * @param string $image_src     The 'src' of the image.
1028
 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1029
 * @param int    $attachment_id Optional. The image attachment ID to pass to the filter. Default 0.
1030
 * @return string|bool          The 'srcset' attribute value. False on error or when only one source exists.
1031
 */
1032
function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 ) {
1033
	/**
1034
	 * Let plugins pre-filter the image meta to be able to fix inconsistencies in the stored data.
1035
	 *
1036
	 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1037
	 * @param array  $size_array    Array of width and height values in pixels (in that order).
1038
	 * @param string $image_src     The 'src' of the image.
1039
	 * @param int    $attachment_id The image attachment ID or 0 if not supplied.
1040
	 */
1041
	$image_meta = apply_filters( 'wp_calculate_image_srcset_meta', $image_meta, $size_array, $image_src, $attachment_id );
1042
1043
	if ( empty( $image_meta['sizes'] ) || ! isset( $image_meta['file'] ) || strlen( $image_meta['file'] ) < 4 ) {
1044
		return false;
1045
	}
1046
1047
	$image_sizes = $image_meta['sizes'];
1048
1049
	// Get the width and height of the image.
1050
	$image_width = (int) $size_array[0];
1051
	$image_height = (int) $size_array[1];
1052
1053
	// Bail early if error/no width.
1054
	if ( $image_width < 1 ) {
1055
		return false;
1056
	}
1057
1058
	$image_basename = wp_basename( $image_meta['file'] );
1059
1060
	/*
1061
	 * WordPress flattens animated GIFs into one frame when generating intermediate sizes.
1062
	 * To avoid hiding animation in user content, if src is a full size GIF, a srcset attribute is not generated.
1063
	 * If src is an intermediate size GIF, the full size is excluded from srcset to keep a flattened GIF from becoming animated.
1064
	 */
1065
	if ( ! isset( $image_sizes['thumbnail']['mime-type'] ) || 'image/gif' !== $image_sizes['thumbnail']['mime-type'] ) {
1066
		$image_sizes[] = array(
1067
			'width'  => $image_meta['width'],
1068
			'height' => $image_meta['height'],
1069
			'file'   => $image_basename,
1070
		);
1071
	} elseif ( strpos( $image_src, $image_meta['file'] ) ) {
1072
		return false;
1073
	}
1074
1075
	// Retrieve the uploads sub-directory from the full size image.
1076
	$dirname = _wp_get_attachment_relative_path( $image_meta['file'] );
1077
1078
	if ( $dirname ) {
1079
		$dirname = trailingslashit( $dirname );
1080
	}
1081
1082
	$upload_dir = wp_get_upload_dir();
1083
	$image_baseurl = trailingslashit( $upload_dir['baseurl'] ) . $dirname;
1084
1085
	/*
1086
	 * If currently on HTTPS, prefer HTTPS URLs when we know they're supported by the domain
1087
	 * (which is to say, when they share the domain name of the current request).
1088
	 */
1089
	if ( is_ssl() && 'https' !== substr( $image_baseurl, 0, 5 ) && parse_url( $image_baseurl, PHP_URL_HOST ) === $_SERVER['HTTP_HOST'] ) {
1090
		$image_baseurl = set_url_scheme( $image_baseurl, 'https' );
1091
	}
1092
1093
	/*
1094
	 * Images that have been edited in WordPress after being uploaded will
1095
	 * contain a unique hash. Look for that hash and use it later to filter
1096
	 * out images that are leftovers from previous versions.
1097
	 */
1098
	$image_edited = preg_match( '/-e[0-9]{13}/', wp_basename( $image_src ), $image_edit_hash );
1099
1100
	/**
1101
	 * Filters the maximum image width to be included in a 'srcset' attribute.
1102
	 *
1103
	 * @since 4.4.0
1104
	 *
1105
	 * @param int   $max_width  The maximum image width to be included in the 'srcset'. Default '1600'.
1106
	 * @param array $size_array Array of width and height values in pixels (in that order).
1107
	 */
1108
	$max_srcset_image_width = apply_filters( 'max_srcset_image_width', 1600, $size_array );
1109
1110
	// Array to hold URL candidates.
1111
	$sources = array();
1112
1113
	/**
1114
	 * To make sure the ID matches our image src, we will check to see if any sizes in our attachment
1115
	 * meta match our $image_src. If no matches are found we don't return a srcset to avoid serving
1116
	 * an incorrect image. See #35045.
1117
	 */
1118
	$src_matched = false;
1119
1120
	/*
1121
	 * Loop through available images. Only use images that are resized
1122
	 * versions of the same edit.
1123
	 */
1124
	foreach ( $image_sizes as $image ) {
1125
		$is_src = false;
1126
1127
		// Check if image meta isn't corrupted.
1128
		if ( ! is_array( $image ) ) {
1129
			continue;
1130
		}
1131
1132
		// If the file name is part of the `src`, we've confirmed a match.
1133
		if ( ! $src_matched && false !== strpos( $image_src, $dirname . $image['file'] ) ) {
1134
			$src_matched = $is_src = true;
1135
		}
1136
1137
		// Filter out images that are from previous edits.
1138
		if ( $image_edited && ! strpos( $image['file'], $image_edit_hash[0] ) ) {
1139
			continue;
1140
		}
1141
1142
		/*
1143
		 * Filters out images that are wider than '$max_srcset_image_width' unless
1144
		 * that file is in the 'src' attribute.
1145
		 */
1146
		if ( $max_srcset_image_width && $image['width'] > $max_srcset_image_width && ! $is_src ) {
1147
			continue;
1148
		}
1149
1150
		// If the image dimensions are within 1px of the expected size, use it.
1151
		if ( wp_image_matches_ratio( $image_width, $image_height, $image['width'], $image['height'] ) ) {
1152
			// Add the URL, descriptor, and value to the sources array to be returned.
1153
			$source = array(
1154
				'url'        => $image_baseurl . $image['file'],
1155
				'descriptor' => 'w',
1156
				'value'      => $image['width'],
1157
			);
1158
1159
			// The 'src' image has to be the first in the 'srcset', because of a bug in iOS8. See #35030.
1160
			if ( $is_src ) {
1161
				$sources = array( $image['width'] => $source ) + $sources;
1162
			} else {
1163
				$sources[ $image['width'] ] = $source;
1164
			}
1165
		}
1166
	}
1167
1168
	/**
1169
	 * Filters an image's 'srcset' sources.
1170
	 *
1171
	 * @since 4.4.0
1172
	 *
1173
	 * @param array  $sources {
1174
	 *     One or more arrays of source data to include in the 'srcset'.
1175
	 *
1176
	 *     @type array $width {
1177
	 *         @type string $url        The URL of an image source.
1178
	 *         @type string $descriptor The descriptor type used in the image candidate string,
1179
	 *                                  either 'w' or 'x'.
1180
	 *         @type int    $value      The source width if paired with a 'w' descriptor, or a
1181
	 *                                  pixel density value if paired with an 'x' descriptor.
1182
	 *     }
1183
	 * }
1184
	 * @param array  $size_array    Array of width and height values in pixels (in that order).
1185
	 * @param string $image_src     The 'src' of the image.
1186
	 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1187
	 * @param int    $attachment_id Image attachment ID or 0.
1188
	 */
1189
	$sources = apply_filters( 'wp_calculate_image_srcset', $sources, $size_array, $image_src, $image_meta, $attachment_id );
1190
1191
	// Only return a 'srcset' value if there is more than one source.
1192
	if ( ! $src_matched || count( $sources ) < 2 ) {
1193
		return false;
1194
	}
1195
1196
	$srcset = '';
1197
1198
	foreach ( $sources as $source ) {
1199
		$srcset .= str_replace( ' ', '%20', $source['url'] ) . ' ' . $source['value'] . $source['descriptor'] . ', ';
1200
	}
1201
1202
	return rtrim( $srcset, ', ' );
1203
}
1204
1205
/**
1206
 * Retrieves the value for an image attachment's 'sizes' attribute.
1207
 *
1208
 * @since 4.4.0
1209
 *
1210
 * @see wp_calculate_image_sizes()
1211
 *
1212
 * @param int          $attachment_id Image attachment ID.
1213
 * @param array|string $size          Optional. Image size. Accepts any valid image size, or an array of width
1214
 *                                    and height values in pixels (in that order). Default 'medium'.
1215
 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
1216
 *                                    Default null.
1217
 * @return string|bool A valid source size value for use in a 'sizes' attribute or false.
1218
 */
1219 View Code Duplication
function wp_get_attachment_image_sizes( $attachment_id, $size = 'medium', $image_meta = null ) {
0 ignored issues
show
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...
1220
	if ( ! $image = wp_get_attachment_image_src( $attachment_id, $size ) ) {
1221
		return false;
1222
	}
1223
1224
	if ( ! is_array( $image_meta ) ) {
1225
		$image_meta = wp_get_attachment_metadata( $attachment_id );
1226
	}
1227
1228
	$image_src = $image[0];
1229
	$size_array = array(
1230
		absint( $image[1] ),
1231
		absint( $image[2] )
1232
	);
1233
1234
	return wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id );
1235
}
1236
1237
/**
1238
 * Creates a 'sizes' attribute value for an image.
1239
 *
1240
 * @since 4.4.0
1241
 *
1242
 * @param array|string $size          Image size to retrieve. Accepts any valid image size, or an array
1243
 *                                    of width and height values in pixels (in that order). Default 'medium'.
1244
 * @param string       $image_src     Optional. The URL to the image file. Default null.
1245
 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
1246
 *                                    Default null.
1247
 * @param int          $attachment_id Optional. Image attachment ID. Either `$image_meta` or `$attachment_id`
1248
 *                                    is needed when using the image size name as argument for `$size`. Default 0.
1249
 * @return string|bool A valid source size value for use in a 'sizes' attribute or false.
1250
 */
1251
function wp_calculate_image_sizes( $size, $image_src = null, $image_meta = null, $attachment_id = 0 ) {
1252
	$width = 0;
1253
1254
	if ( is_array( $size ) ) {
1255
		$width = absint( $size[0] );
1256
	} elseif ( is_string( $size ) ) {
1257
		if ( ! $image_meta && $attachment_id ) {
1258
			$image_meta = wp_get_attachment_metadata( $attachment_id );
1259
		}
1260
1261
		if ( is_array( $image_meta ) ) {
1262
			$size_array = _wp_get_image_size_from_meta( $size, $image_meta );
1263
			if ( $size_array ) {
1264
				$width = absint( $size_array[0] );
1265
			}
1266
		}
1267
	}
1268
1269
	if ( ! $width ) {
1270
		return false;
1271
	}
1272
1273
	// Setup the default 'sizes' attribute.
1274
	$sizes = sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', $width );
1275
1276
	/**
1277
	 * Filters the output of 'wp_calculate_image_sizes()'.
1278
	 *
1279
	 * @since 4.4.0
1280
	 *
1281
	 * @param string       $sizes         A source size value for use in a 'sizes' attribute.
1282
	 * @param array|string $size          Requested size. Image size or array of width and height values
1283
	 *                                    in pixels (in that order).
1284
	 * @param string|null  $image_src     The URL to the image file or null.
1285
	 * @param array|null   $image_meta    The image meta data as returned by wp_get_attachment_metadata() or null.
1286
	 * @param int          $attachment_id Image attachment ID of the original image or 0.
1287
	 */
1288
	return apply_filters( 'wp_calculate_image_sizes', $sizes, $size, $image_src, $image_meta, $attachment_id );
1289
}
1290
1291
/**
1292
 * Filters 'img' elements in post content to add 'srcset' and 'sizes' attributes.
1293
 *
1294
 * @since 4.4.0
1295
 *
1296
 * @see wp_image_add_srcset_and_sizes()
1297
 *
1298
 * @param string $content The raw post content to be filtered.
1299
 * @return string Converted content with 'srcset' and 'sizes' attributes added to images.
1300
 */
1301
function wp_make_content_images_responsive( $content ) {
1302
	if ( ! preg_match_all( '/<img [^>]+>/', $content, $matches ) ) {
1303
		return $content;
1304
	}
1305
1306
	$selected_images = $attachment_ids = array();
1307
1308
	foreach( $matches[0] as $image ) {
1309
		if ( false === strpos( $image, ' srcset=' ) && preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) &&
1310
			( $attachment_id = absint( $class_id[1] ) ) ) {
1311
1312
			/*
1313
			 * If exactly the same image tag is used more than once, overwrite it.
1314
			 * All identical tags will be replaced later with 'str_replace()'.
1315
			 */
1316
			$selected_images[ $image ] = $attachment_id;
1317
			// Overwrite the ID when the same image is included more than once.
1318
			$attachment_ids[ $attachment_id ] = true;
1319
		}
1320
	}
1321
1322
	if ( count( $attachment_ids ) > 1 ) {
1323
		/*
1324
		 * Warm object cache for use with 'get_post_meta()'.
1325
		 *
1326
		 * To avoid making a database call for each image, a single query
1327
		 * warms the object cache with the meta information for all images.
1328
		 */
1329
		update_meta_cache( 'post', array_keys( $attachment_ids ) );
1330
	}
1331
1332
	foreach ( $selected_images as $image => $attachment_id ) {
1333
		$image_meta = wp_get_attachment_metadata( $attachment_id );
1334
		$content = str_replace( $image, wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id ), $content );
1335
	}
1336
1337
	return $content;
1338
}
1339
1340
/**
1341
 * Adds 'srcset' and 'sizes' attributes to an existing 'img' element.
1342
 *
1343
 * @since 4.4.0
1344
 *
1345
 * @see wp_calculate_image_srcset()
1346
 * @see wp_calculate_image_sizes()
1347
 *
1348
 * @param string $image         An HTML 'img' element to be filtered.
1349
 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1350
 * @param int    $attachment_id Image attachment ID.
1351
 * @return string Converted 'img' element with 'srcset' and 'sizes' attributes added.
1352
 */
1353
function wp_image_add_srcset_and_sizes( $image, $image_meta, $attachment_id ) {
1354
	// Ensure the image meta exists.
1355
	if ( empty( $image_meta['sizes'] ) ) {
1356
		return $image;
1357
	}
1358
1359
	$image_src = preg_match( '/src="([^"]+)"/', $image, $match_src ) ? $match_src[1] : '';
1360
	list( $image_src ) = explode( '?', $image_src );
1361
1362
	// Return early if we couldn't get the image source.
1363
	if ( ! $image_src ) {
1364
		return $image;
1365
	}
1366
1367
	// Bail early if an image has been inserted and later edited.
1368
	if ( preg_match( '/-e[0-9]{13}/', $image_meta['file'], $img_edit_hash ) &&
1369
		strpos( wp_basename( $image_src ), $img_edit_hash[0] ) === false ) {
1370
1371
		return $image;
1372
	}
1373
1374
	$width  = preg_match( '/ width="([0-9]+)"/',  $image, $match_width  ) ? (int) $match_width[1]  : 0;
1375
	$height = preg_match( '/ height="([0-9]+)"/', $image, $match_height ) ? (int) $match_height[1] : 0;
1376
1377
	if ( ! $width || ! $height ) {
1378
		/*
1379
		 * If attempts to parse the size value failed, attempt to use the image meta data to match
1380
		 * the image file name from 'src' against the available sizes for an attachment.
1381
		 */
1382
		$image_filename = wp_basename( $image_src );
1383
1384
		if ( $image_filename === wp_basename( $image_meta['file'] ) ) {
1385
			$width = (int) $image_meta['width'];
1386
			$height = (int) $image_meta['height'];
1387
		} else {
1388
			foreach( $image_meta['sizes'] as $image_size_data ) {
1389
				if ( $image_filename === $image_size_data['file'] ) {
1390
					$width = (int) $image_size_data['width'];
1391
					$height = (int) $image_size_data['height'];
1392
					break;
1393
				}
1394
			}
1395
		}
1396
	}
1397
1398
	if ( ! $width || ! $height ) {
1399
		return $image;
1400
	}
1401
1402
	$size_array = array( $width, $height );
1403
	$srcset = wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id );
1404
1405
	if ( $srcset ) {
1406
		// Check if there is already a 'sizes' attribute.
1407
		$sizes = strpos( $image, ' sizes=' );
1408
1409
		if ( ! $sizes ) {
1410
			$sizes = wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id );
1411
		}
1412
	}
1413
1414
	if ( $srcset && $sizes ) {
1415
		// Format the 'srcset' and 'sizes' string and escape attributes.
1416
		$attr = sprintf( ' srcset="%s"', esc_attr( $srcset ) );
1417
1418
		if ( is_string( $sizes ) ) {
1419
			$attr .= sprintf( ' sizes="%s"', esc_attr( $sizes ) );
0 ignored issues
show
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...
1420
		}
1421
1422
		// Add 'srcset' and 'sizes' attributes to the image markup.
1423
		$image = preg_replace( '/<img ([^>]+?)[\/ ]*>/', '<img $1' . $attr . ' />', $image );
1424
	}
1425
1426
	return $image;
1427
}
1428
1429
/**
1430
 * Adds a 'wp-post-image' class to post thumbnails. Internal use only.
1431
 *
1432
 * Uses the {@see 'begin_fetch_post_thumbnail_html'} and {@see 'end_fetch_post_thumbnail_html'}
1433
 * action hooks to dynamically add/remove itself so as to only filter post thumbnails.
1434
 *
1435
 * @ignore
1436
 * @since 2.9.0
1437
 *
1438
 * @param array $attr Thumbnail attributes including src, class, alt, title.
1439
 * @return array Modified array of attributes including the new 'wp-post-image' class.
1440
 */
1441
function _wp_post_thumbnail_class_filter( $attr ) {
1442
	$attr['class'] .= ' wp-post-image';
1443
	return $attr;
1444
}
1445
1446
/**
1447
 * Adds '_wp_post_thumbnail_class_filter' callback to the 'wp_get_attachment_image_attributes'
1448
 * filter hook. Internal use only.
1449
 *
1450
 * @ignore
1451
 * @since 2.9.0
1452
 *
1453
 * @param array $attr Thumbnail attributes including src, class, alt, title.
1454
 */
1455
function _wp_post_thumbnail_class_filter_add( $attr ) {
1456
	add_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
1457
}
1458
1459
/**
1460
 * Removes the '_wp_post_thumbnail_class_filter' callback from the 'wp_get_attachment_image_attributes'
1461
 * filter hook. Internal use only.
1462
 *
1463
 * @ignore
1464
 * @since 2.9.0
1465
 *
1466
 * @param array $attr Thumbnail attributes including src, class, alt, title.
1467
 */
1468
function _wp_post_thumbnail_class_filter_remove( $attr ) {
1469
	remove_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
1470
}
1471
1472
add_shortcode('wp_caption', 'img_caption_shortcode');
1473
add_shortcode('caption', 'img_caption_shortcode');
1474
1475
/**
1476
 * Builds the Caption shortcode output.
1477
 *
1478
 * Allows a plugin to replace the content that would otherwise be returned. The
1479
 * filter is {@see 'img_caption_shortcode'} and passes an empty string, the attr
1480
 * parameter and the content parameter values.
1481
 *
1482
 * The supported attributes for the shortcode are 'id', 'align', 'width', and
1483
 * 'caption'.
1484
 *
1485
 * @since 2.6.0
1486
 *
1487
 * @param array  $attr {
1488
 *     Attributes of the caption shortcode.
1489
 *
1490
 *     @type string $id      ID of the div element for the caption.
1491
 *     @type string $align   Class name that aligns the caption. Default 'alignnone'. Accepts 'alignleft',
1492
 *                           'aligncenter', alignright', 'alignnone'.
1493
 *     @type int    $width   The width of the caption, in pixels.
1494
 *     @type string $caption The caption text.
1495
 *     @type string $class   Additional class name(s) added to the caption container.
1496
 * }
1497
 * @param string $content Shortcode content.
1498
 * @return string HTML content to display the caption.
1499
 */
1500
function img_caption_shortcode( $attr, $content = null ) {
1501
	// New-style shortcode with the caption inside the shortcode with the link and image tags.
1502
	if ( ! isset( $attr['caption'] ) ) {
1503
		if ( preg_match( '#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches ) ) {
1504
			$content = $matches[1];
1505
			$attr['caption'] = trim( $matches[2] );
1506
		}
1507
	} elseif ( strpos( $attr['caption'], '<' ) !== false ) {
1508
		$attr['caption'] = wp_kses( $attr['caption'], 'post' );
0 ignored issues
show
'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...
1509
	}
1510
1511
	/**
1512
	 * Filters the default caption shortcode output.
1513
	 *
1514
	 * If the filtered output isn't empty, it will be used instead of generating
1515
	 * the default caption template.
1516
	 *
1517
	 * @since 2.6.0
1518
	 *
1519
	 * @see img_caption_shortcode()
1520
	 *
1521
	 * @param string $output  The caption output. Default empty.
1522
	 * @param array  $attr    Attributes of the caption shortcode.
1523
	 * @param string $content The image element, possibly wrapped in a hyperlink.
1524
	 */
1525
	$output = apply_filters( 'img_caption_shortcode', '', $attr, $content );
1526
	if ( $output != '' )
1527
		return $output;
1528
1529
	$atts = shortcode_atts( array(
1530
		'id'	  => '',
1531
		'align'	  => 'alignnone',
1532
		'width'	  => '',
1533
		'caption' => '',
1534
		'class'   => '',
1535
	), $attr, 'caption' );
1536
1537
	$atts['width'] = (int) $atts['width'];
1538
	if ( $atts['width'] < 1 || empty( $atts['caption'] ) )
1539
		return $content;
1540
1541 View Code Duplication
	if ( ! empty( $atts['id'] ) )
1542
		$atts['id'] = 'id="' . esc_attr( sanitize_html_class( $atts['id'] ) ) . '" ';
1543
1544
	$class = trim( 'wp-caption ' . $atts['align'] . ' ' . $atts['class'] );
1545
1546
	$html5 = current_theme_supports( 'html5', 'caption' );
1547
	// HTML5 captions never added the extra 10px to the image width
1548
	$width = $html5 ? $atts['width'] : ( 10 + $atts['width'] );
1549
1550
	/**
1551
	 * Filters the width of an image's caption.
1552
	 *
1553
	 * By default, the caption is 10 pixels greater than the width of the image,
1554
	 * to prevent post content from running up against a floated image.
1555
	 *
1556
	 * @since 3.7.0
1557
	 *
1558
	 * @see img_caption_shortcode()
1559
	 *
1560
	 * @param int    $width    Width of the caption in pixels. To remove this inline style,
1561
	 *                         return zero.
1562
	 * @param array  $atts     Attributes of the caption shortcode.
1563
	 * @param string $content  The image element, possibly wrapped in a hyperlink.
1564
	 */
1565
	$caption_width = apply_filters( 'img_caption_shortcode_width', $width, $atts, $content );
1566
1567
	$style = '';
1568
	if ( $caption_width ) {
1569
		$style = 'style="width: ' . (int) $caption_width . 'px" ';
1570
	}
1571
1572
	if ( $html5 ) {
1573
		$html = '<figure ' . $atts['id'] . $style . 'class="' . esc_attr( $class ) . '">'
1574
		. do_shortcode( $content ) . '<figcaption class="wp-caption-text">' . $atts['caption'] . '</figcaption></figure>';
1575
	} else {
1576
		$html = '<div ' . $atts['id'] . $style . 'class="' . esc_attr( $class ) . '">'
1577
		. do_shortcode( $content ) . '<p class="wp-caption-text">' . $atts['caption'] . '</p></div>';
1578
	}
1579
1580
	return $html;
1581
}
1582
1583
add_shortcode('gallery', 'gallery_shortcode');
1584
1585
/**
1586
 * Builds the Gallery shortcode output.
1587
 *
1588
 * This implements the functionality of the Gallery Shortcode for displaying
1589
 * WordPress images on a post.
1590
 *
1591
 * @since 2.5.0
1592
 *
1593
 * @staticvar int $instance
1594
 *
1595
 * @param array $attr {
1596
 *     Attributes of the gallery shortcode.
1597
 *
1598
 *     @type string       $order      Order of the images in the gallery. Default 'ASC'. Accepts 'ASC', 'DESC'.
1599
 *     @type string       $orderby    The field to use when ordering the images. Default 'menu_order ID'.
1600
 *                                    Accepts any valid SQL ORDERBY statement.
1601
 *     @type int          $id         Post ID.
1602
 *     @type string       $itemtag    HTML tag to use for each image in the gallery.
1603
 *                                    Default 'dl', or 'figure' when the theme registers HTML5 gallery support.
1604
 *     @type string       $icontag    HTML tag to use for each image's icon.
1605
 *                                    Default 'dt', or 'div' when the theme registers HTML5 gallery support.
1606
 *     @type string       $captiontag HTML tag to use for each image's caption.
1607
 *                                    Default 'dd', or 'figcaption' when the theme registers HTML5 gallery support.
1608
 *     @type int          $columns    Number of columns of images to display. Default 3.
1609
 *     @type string|array $size       Size of the images to display. Accepts any valid image size, or an array of width
1610
 *                                    and height values in pixels (in that order). Default 'thumbnail'.
1611
 *     @type string       $ids        A comma-separated list of IDs of attachments to display. Default empty.
1612
 *     @type string       $include    A comma-separated list of IDs of attachments to include. Default empty.
1613
 *     @type string       $exclude    A comma-separated list of IDs of attachments to exclude. Default empty.
1614
 *     @type string       $link       What to link each image to. Default empty (links to the attachment page).
1615
 *                                    Accepts 'file', 'none'.
1616
 * }
1617
 * @return string HTML content to display gallery.
1618
 */
1619
function gallery_shortcode( $attr ) {
1620
	$post = get_post();
1621
1622
	static $instance = 0;
1623
	$instance++;
1624
1625 View Code Duplication
	if ( ! empty( $attr['ids'] ) ) {
1626
		// 'ids' is explicitly ordered, unless you specify otherwise.
1627
		if ( empty( $attr['orderby'] ) ) {
1628
			$attr['orderby'] = 'post__in';
1629
		}
1630
		$attr['include'] = $attr['ids'];
1631
	}
1632
1633
	/**
1634
	 * Filters the default gallery shortcode output.
1635
	 *
1636
	 * If the filtered output isn't empty, it will be used instead of generating
1637
	 * the default gallery template.
1638
	 *
1639
	 * @since 2.5.0
1640
	 * @since 4.2.0 The `$instance` parameter was added.
1641
	 *
1642
	 * @see gallery_shortcode()
1643
	 *
1644
	 * @param string $output   The gallery output. Default empty.
1645
	 * @param array  $attr     Attributes of the gallery shortcode.
1646
	 * @param int    $instance Unique numeric ID of this gallery shortcode instance.
1647
	 */
1648
	$output = apply_filters( 'post_gallery', '', $attr, $instance );
1649
	if ( $output != '' ) {
1650
		return $output;
1651
	}
1652
1653
	$html5 = current_theme_supports( 'html5', 'gallery' );
1654
	$atts = shortcode_atts( array(
1655
		'order'      => 'ASC',
1656
		'orderby'    => 'menu_order ID',
1657
		'id'         => $post ? $post->ID : 0,
1658
		'itemtag'    => $html5 ? 'figure'     : 'dl',
1659
		'icontag'    => $html5 ? 'div'        : 'dt',
1660
		'captiontag' => $html5 ? 'figcaption' : 'dd',
1661
		'columns'    => 3,
1662
		'size'       => 'thumbnail',
1663
		'include'    => '',
1664
		'exclude'    => '',
1665
		'link'       => ''
1666
	), $attr, 'gallery' );
1667
1668
	$id = intval( $atts['id'] );
1669
1670
	if ( ! empty( $atts['include'] ) ) {
1671
		$_attachments = get_posts( array( 'include' => $atts['include'], 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
1672
1673
		$attachments = array();
1674
		foreach ( $_attachments as $key => $val ) {
1675
			$attachments[$val->ID] = $_attachments[$key];
1676
		}
1677
	} elseif ( ! empty( $atts['exclude'] ) ) {
1678
		$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'] ) );
1679
	} else {
1680
		$attachments = get_children( array( 'post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
1681
	}
1682
1683
	if ( empty( $attachments ) ) {
1684
		return '';
1685
	}
1686
1687 View Code Duplication
	if ( is_feed() ) {
1688
		$output = "\n";
1689
		foreach ( $attachments as $att_id => $attachment ) {
1690
			$output .= wp_get_attachment_link( $att_id, $atts['size'], true ) . "\n";
1691
		}
1692
		return $output;
1693
	}
1694
1695
	$itemtag = tag_escape( $atts['itemtag'] );
1696
	$captiontag = tag_escape( $atts['captiontag'] );
1697
	$icontag = tag_escape( $atts['icontag'] );
1698
	$valid_tags = wp_kses_allowed_html( 'post' );
1699
	if ( ! isset( $valid_tags[ $itemtag ] ) ) {
1700
		$itemtag = 'dl';
1701
	}
1702
	if ( ! isset( $valid_tags[ $captiontag ] ) ) {
1703
		$captiontag = 'dd';
1704
	}
1705
	if ( ! isset( $valid_tags[ $icontag ] ) ) {
1706
		$icontag = 'dt';
1707
	}
1708
1709
	$columns = intval( $atts['columns'] );
1710
	$itemwidth = $columns > 0 ? floor(100/$columns) : 100;
1711
	$float = is_rtl() ? 'right' : 'left';
1712
1713
	$selector = "gallery-{$instance}";
1714
1715
	$gallery_style = '';
1716
1717
	/**
1718
	 * Filters whether to print default gallery styles.
1719
	 *
1720
	 * @since 3.1.0
1721
	 *
1722
	 * @param bool $print Whether to print default gallery styles.
1723
	 *                    Defaults to false if the theme supports HTML5 galleries.
1724
	 *                    Otherwise, defaults to true.
1725
	 */
1726
	if ( apply_filters( 'use_default_gallery_style', ! $html5 ) ) {
1727
		$gallery_style = "
1728
		<style type='text/css'>
1729
			#{$selector} {
1730
				margin: auto;
1731
			}
1732
			#{$selector} .gallery-item {
1733
				float: {$float};
1734
				margin-top: 10px;
1735
				text-align: center;
1736
				width: {$itemwidth}%;
1737
			}
1738
			#{$selector} img {
1739
				border: 2px solid #cfcfcf;
1740
			}
1741
			#{$selector} .gallery-caption {
1742
				margin-left: 0;
1743
			}
1744
			/* see gallery_shortcode() in wp-includes/media.php */
1745
		</style>\n\t\t";
1746
	}
1747
1748
	$size_class = sanitize_html_class( $atts['size'] );
1749
	$gallery_div = "<div id='$selector' class='gallery galleryid-{$id} gallery-columns-{$columns} gallery-size-{$size_class}'>";
1750
1751
	/**
1752
	 * Filters the default gallery shortcode CSS styles.
1753
	 *
1754
	 * @since 2.5.0
1755
	 *
1756
	 * @param string $gallery_style Default CSS styles and opening HTML div container
1757
	 *                              for the gallery shortcode output.
1758
	 */
1759
	$output = apply_filters( 'gallery_style', $gallery_style . $gallery_div );
1760
1761
	$i = 0;
1762
	foreach ( $attachments as $id => $attachment ) {
1763
1764
		$attr = ( trim( $attachment->post_excerpt ) ) ? array( 'aria-describedby' => "$selector-$id" ) : '';
1765
		if ( ! empty( $atts['link'] ) && 'file' === $atts['link'] ) {
1766
			$image_output = wp_get_attachment_link( $id, $atts['size'], false, false, false, $attr );
1767
		} elseif ( ! empty( $atts['link'] ) && 'none' === $atts['link'] ) {
1768
			$image_output = wp_get_attachment_image( $id, $atts['size'], false, $attr );
1769
		} else {
1770
			$image_output = wp_get_attachment_link( $id, $atts['size'], true, false, false, $attr );
1771
		}
1772
		$image_meta  = wp_get_attachment_metadata( $id );
1773
1774
		$orientation = '';
1775
		if ( isset( $image_meta['height'], $image_meta['width'] ) ) {
1776
			$orientation = ( $image_meta['height'] > $image_meta['width'] ) ? 'portrait' : 'landscape';
1777
		}
1778
		$output .= "<{$itemtag} class='gallery-item'>";
1779
		$output .= "
1780
			<{$icontag} class='gallery-icon {$orientation}'>
1781
				$image_output
1782
			</{$icontag}>";
1783
		if ( $captiontag && trim($attachment->post_excerpt) ) {
1784
			$output .= "
1785
				<{$captiontag} class='wp-caption-text gallery-caption' id='$selector-$id'>
1786
				" . wptexturize($attachment->post_excerpt) . "
1787
				</{$captiontag}>";
1788
		}
1789
		$output .= "</{$itemtag}>";
1790 View Code Duplication
		if ( ! $html5 && $columns > 0 && ++$i % $columns == 0 ) {
1791
			$output .= '<br style="clear: both" />';
1792
		}
1793
	}
1794
1795 View Code Duplication
	if ( ! $html5 && $columns > 0 && $i % $columns !== 0 ) {
1796
		$output .= "
1797
			<br style='clear: both' />";
1798
	}
1799
1800
	$output .= "
1801
		</div>\n";
1802
1803
	return $output;
1804
}
1805
1806
/**
1807
 * Outputs the templates used by playlists.
1808
 *
1809
 * @since 3.9.0
1810
 */
1811
function wp_underscore_playlist_templates() {
1812
?>
1813
<script type="text/html" id="tmpl-wp-playlist-current-item">
1814
	<# if ( data.image ) { #>
1815
	<img src="{{ data.thumb.src }}" alt="" />
1816
	<# } #>
1817
	<div class="wp-playlist-caption">
1818
		<span class="wp-playlist-item-meta wp-playlist-item-title"><?php
1819
			/* translators: playlist item title */
1820
			printf( _x( '&#8220;%s&#8221;', 'playlist item title' ), '{{ data.title }}' );
1821
		?></span>
1822
		<# if ( data.meta.album ) { #><span class="wp-playlist-item-meta wp-playlist-item-album">{{ data.meta.album }}</span><# } #>
1823
		<# if ( data.meta.artist ) { #><span class="wp-playlist-item-meta wp-playlist-item-artist">{{ data.meta.artist }}</span><# } #>
1824
	</div>
1825
</script>
1826
<script type="text/html" id="tmpl-wp-playlist-item">
1827
	<div class="wp-playlist-item">
1828
		<a class="wp-playlist-caption" href="{{ data.src }}">
1829
			{{ data.index ? ( data.index + '. ' ) : '' }}
1830
			<# if ( data.caption ) { #>
1831
				{{ data.caption }}
1832
			<# } else { #>
1833
				<span class="wp-playlist-item-title"><?php
1834
					/* translators: playlist item title */
1835
					printf( _x( '&#8220;%s&#8221;', 'playlist item title' ), '{{{ data.title }}}' );
1836
				?></span>
1837
				<# if ( data.artists && data.meta.artist ) { #>
1838
				<span class="wp-playlist-item-artist"> &mdash; {{ data.meta.artist }}</span>
1839
				<# } #>
1840
			<# } #>
1841
		</a>
1842
		<# if ( data.meta.length_formatted ) { #>
1843
		<div class="wp-playlist-item-length">{{ data.meta.length_formatted }}</div>
1844
		<# } #>
1845
	</div>
1846
</script>
1847
<?php
1848
}
1849
1850
/**
1851
 * Outputs and enqueue default scripts and styles for playlists.
1852
 *
1853
 * @since 3.9.0
1854
 *
1855
 * @param string $type Type of playlist. Accepts 'audio' or 'video'.
1856
 */
1857
function wp_playlist_scripts( $type ) {
1858
	wp_enqueue_style( 'wp-mediaelement' );
1859
	wp_enqueue_script( 'wp-playlist' );
1860
?>
1861
<!--[if lt IE 9]><script>document.createElement('<?php echo esc_js( $type ) ?>');</script><![endif]-->
1862
<?php
1863
	add_action( 'wp_footer', 'wp_underscore_playlist_templates', 0 );
1864
	add_action( 'admin_footer', 'wp_underscore_playlist_templates', 0 );
1865
}
1866
1867
/**
1868
 * Builds the Playlist shortcode output.
1869
 *
1870
 * This implements the functionality of the playlist shortcode for displaying
1871
 * a collection of WordPress audio or video files in a post.
1872
 *
1873
 * @since 3.9.0
1874
 *
1875
 * @global int $content_width
1876
 * @staticvar int $instance
1877
 *
1878
 * @param array $attr {
1879
 *     Array of default playlist attributes.
1880
 *
1881
 *     @type string  $type         Type of playlist to display. Accepts 'audio' or 'video'. Default 'audio'.
1882
 *     @type string  $order        Designates ascending or descending order of items in the playlist.
1883
 *                                 Accepts 'ASC', 'DESC'. Default 'ASC'.
1884
 *     @type string  $orderby      Any column, or columns, to sort the playlist. If $ids are
1885
 *                                 passed, this defaults to the order of the $ids array ('post__in').
1886
 *                                 Otherwise default is 'menu_order ID'.
1887
 *     @type int     $id           If an explicit $ids array is not present, this parameter
1888
 *                                 will determine which attachments are used for the playlist.
1889
 *                                 Default is the current post ID.
1890
 *     @type array   $ids          Create a playlist out of these explicit attachment IDs. If empty,
1891
 *                                 a playlist will be created from all $type attachments of $id.
1892
 *                                 Default empty.
1893
 *     @type array   $exclude      List of specific attachment IDs to exclude from the playlist. Default empty.
1894
 *     @type string  $style        Playlist style to use. Accepts 'light' or 'dark'. Default 'light'.
1895
 *     @type bool    $tracklist    Whether to show or hide the playlist. Default true.
1896
 *     @type bool    $tracknumbers Whether to show or hide the numbers next to entries in the playlist. Default true.
1897
 *     @type bool    $images       Show or hide the video or audio thumbnail (Featured Image/post
1898
 *                                 thumbnail). Default true.
1899
 *     @type bool    $artists      Whether to show or hide artist name in the playlist. Default true.
1900
 * }
1901
 *
1902
 * @return string Playlist output. Empty string if the passed type is unsupported.
1903
 */
1904
function wp_playlist_shortcode( $attr ) {
1905
	global $content_width;
1906
	$post = get_post();
1907
1908
	static $instance = 0;
1909
	$instance++;
1910
1911 View Code Duplication
	if ( ! empty( $attr['ids'] ) ) {
1912
		// 'ids' is explicitly ordered, unless you specify otherwise.
1913
		if ( empty( $attr['orderby'] ) ) {
1914
			$attr['orderby'] = 'post__in';
1915
		}
1916
		$attr['include'] = $attr['ids'];
1917
	}
1918
1919
	/**
1920
	 * Filters the playlist output.
1921
	 *
1922
	 * Passing a non-empty value to the filter will short-circuit generation
1923
	 * of the default playlist output, returning the passed value instead.
1924
	 *
1925
	 * @since 3.9.0
1926
	 * @since 4.2.0 The `$instance` parameter was added.
1927
	 *
1928
	 * @param string $output   Playlist output. Default empty.
1929
	 * @param array  $attr     An array of shortcode attributes.
1930
	 * @param int    $instance Unique numeric ID of this playlist shortcode instance.
1931
	 */
1932
	$output = apply_filters( 'post_playlist', '', $attr, $instance );
1933
	if ( $output != '' ) {
1934
		return $output;
1935
	}
1936
1937
	$atts = shortcode_atts( array(
1938
		'type'		=> 'audio',
1939
		'order'		=> 'ASC',
1940
		'orderby'	=> 'menu_order ID',
1941
		'id'		=> $post ? $post->ID : 0,
1942
		'include'	=> '',
1943
		'exclude'   => '',
1944
		'style'		=> 'light',
1945
		'tracklist' => true,
1946
		'tracknumbers' => true,
1947
		'images'	=> true,
1948
		'artists'	=> true
1949
	), $attr, 'playlist' );
1950
1951
	$id = intval( $atts['id'] );
1952
1953
	if ( $atts['type'] !== 'audio' ) {
1954
		$atts['type'] = 'video';
1955
	}
1956
1957
	$args = array(
1958
		'post_status' => 'inherit',
1959
		'post_type' => 'attachment',
1960
		'post_mime_type' => $atts['type'],
1961
		'order' => $atts['order'],
1962
		'orderby' => $atts['orderby']
1963
	);
1964
1965
	if ( ! empty( $atts['include'] ) ) {
1966
		$args['include'] = $atts['include'];
1967
		$_attachments = get_posts( $args );
1968
1969
		$attachments = array();
1970
		foreach ( $_attachments as $key => $val ) {
1971
			$attachments[$val->ID] = $_attachments[$key];
1972
		}
1973
	} elseif ( ! empty( $atts['exclude'] ) ) {
1974
		$args['post_parent'] = $id;
1975
		$args['exclude'] = $atts['exclude'];
1976
		$attachments = get_children( $args );
1977
	} else {
1978
		$args['post_parent'] = $id;
1979
		$attachments = get_children( $args );
1980
	}
1981
1982
	if ( empty( $attachments ) ) {
1983
		return '';
1984
	}
1985
1986 View Code Duplication
	if ( is_feed() ) {
1987
		$output = "\n";
1988
		foreach ( $attachments as $att_id => $attachment ) {
1989
			$output .= wp_get_attachment_link( $att_id ) . "\n";
1990
		}
1991
		return $output;
1992
	}
1993
1994
	$outer = 22; // default padding and border of wrapper
1995
1996
	$default_width = 640;
1997
	$default_height = 360;
1998
1999
	$theme_width = empty( $content_width ) ? $default_width : ( $content_width - $outer );
2000
	$theme_height = empty( $content_width ) ? $default_height : round( ( $default_height * $theme_width ) / $default_width );
2001
2002
	$data = array(
2003
		'type' => $atts['type'],
2004
		// don't pass strings to JSON, will be truthy in JS
2005
		'tracklist' => wp_validate_boolean( $atts['tracklist'] ),
2006
		'tracknumbers' => wp_validate_boolean( $atts['tracknumbers'] ),
2007
		'images' => wp_validate_boolean( $atts['images'] ),
2008
		'artists' => wp_validate_boolean( $atts['artists'] ),
2009
	);
2010
2011
	$tracks = array();
2012
	foreach ( $attachments as $attachment ) {
2013
		$url = wp_get_attachment_url( $attachment->ID );
2014
		$ftype = wp_check_filetype( $url, wp_get_mime_types() );
0 ignored issues
show
It seems like $url defined by wp_get_attachment_url($attachment->ID) on line 2013 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...
2015
		$track = array(
2016
			'src' => $url,
2017
			'type' => $ftype['type'],
2018
			'title' => $attachment->post_title,
2019
			'caption' => $attachment->post_excerpt,
2020
			'description' => $attachment->post_content
2021
		);
2022
2023
		$track['meta'] = array();
2024
		$meta = wp_get_attachment_metadata( $attachment->ID );
2025
		if ( ! empty( $meta ) ) {
2026
2027
			foreach ( wp_get_attachment_id3_keys( $attachment ) as $key => $label ) {
2028
				if ( ! empty( $meta[ $key ] ) ) {
2029
					$track['meta'][ $key ] = $meta[ $key ];
2030
				}
2031
			}
2032
2033
			if ( 'video' === $atts['type'] ) {
2034
				if ( ! empty( $meta['width'] ) && ! empty( $meta['height'] ) ) {
2035
					$width = $meta['width'];
2036
					$height = $meta['height'];
2037
					$theme_height = round( ( $height * $theme_width ) / $width );
2038
				} else {
2039
					$width = $default_width;
2040
					$height = $default_height;
2041
				}
2042
2043
				$track['dimensions'] = array(
2044
					'original' => compact( 'width', 'height' ),
2045
					'resized' => array(
2046
						'width' => $theme_width,
2047
						'height' => $theme_height
2048
					)
2049
				);
2050
			}
2051
		}
2052
2053
		if ( $atts['images'] ) {
2054
			$thumb_id = get_post_thumbnail_id( $attachment->ID );
2055 View Code Duplication
			if ( ! empty( $thumb_id ) ) {
2056
				list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'full' );
2057
				$track['image'] = compact( 'src', 'width', 'height' );
2058
				list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'thumbnail' );
2059
				$track['thumb'] = compact( 'src', 'width', 'height' );
2060
			} else {
2061
				$src = wp_mime_type_icon( $attachment->ID );
2062
				$width = 48;
2063
				$height = 64;
2064
				$track['image'] = compact( 'src', 'width', 'height' );
2065
				$track['thumb'] = compact( 'src', 'width', 'height' );
2066
			}
2067
		}
2068
2069
		$tracks[] = $track;
2070
	}
2071
	$data['tracks'] = $tracks;
2072
2073
	$safe_type = esc_attr( $atts['type'] );
2074
	$safe_style = esc_attr( $atts['style'] );
2075
2076
	ob_start();
2077
2078
	if ( 1 === $instance ) {
2079
		/**
2080
		 * Prints and enqueues playlist scripts, styles, and JavaScript templates.
2081
		 *
2082
		 * @since 3.9.0
2083
		 *
2084
		 * @param string $type  Type of playlist. Possible values are 'audio' or 'video'.
2085
		 * @param string $style The 'theme' for the playlist. Core provides 'light' and 'dark'.
2086
		 */
2087
		do_action( 'wp_playlist_scripts', $atts['type'], $atts['style'] );
2088
	} ?>
2089
<div class="wp-playlist wp-<?php echo $safe_type ?>-playlist wp-playlist-<?php echo $safe_style ?>">
2090
	<?php if ( 'audio' === $atts['type'] ): ?>
2091
	<div class="wp-playlist-current-item"></div>
2092
	<?php endif ?>
2093
	<<?php echo $safe_type ?> controls="controls" preload="none" width="<?php
2094
		echo (int) $theme_width;
2095
	?>"<?php if ( 'video' === $safe_type ):
2096
		echo ' height="', (int) $theme_height, '"';
2097
	endif; ?>></<?php echo $safe_type ?>>
2098
	<div class="wp-playlist-next"></div>
2099
	<div class="wp-playlist-prev"></div>
2100
	<noscript>
2101
	<ol><?php
2102
	foreach ( $attachments as $att_id => $attachment ) {
2103
		printf( '<li>%s</li>', wp_get_attachment_link( $att_id ) );
2104
	}
2105
	?></ol>
2106
	</noscript>
2107
	<script type="application/json" class="wp-playlist-script"><?php echo wp_json_encode( $data ) ?></script>
2108
</div>
2109
	<?php
2110
	return ob_get_clean();
2111
}
2112
add_shortcode( 'playlist', 'wp_playlist_shortcode' );
2113
2114
/**
2115
 * Provides a No-JS Flash fallback as a last resort for audio / video.
2116
 *
2117
 * @since 3.6.0
2118
 *
2119
 * @param string $url The media element URL.
2120
 * @return string Fallback HTML.
2121
 */
2122
function wp_mediaelement_fallback( $url ) {
2123
	/**
2124
	 * Filters the Mediaelement fallback output for no-JS.
2125
	 *
2126
	 * @since 3.6.0
2127
	 *
2128
	 * @param string $output Fallback output for no-JS.
2129
	 * @param string $url    Media file URL.
2130
	 */
2131
	return apply_filters( 'wp_mediaelement_fallback', sprintf( '<a href="%1$s">%1$s</a>', esc_url( $url ) ), $url );
2132
}
2133
2134
/**
2135
 * Returns a filtered list of WP-supported audio formats.
2136
 *
2137
 * @since 3.6.0
2138
 *
2139
 * @return array Supported audio formats.
2140
 */
2141
function wp_get_audio_extensions() {
2142
	/**
2143
	 * Filters the list of supported audio formats.
2144
	 *
2145
	 * @since 3.6.0
2146
	 *
2147
	 * @param array $extensions An array of support audio formats. Defaults are
2148
	 *                          'mp3', 'ogg', 'wma', 'm4a', 'wav'.
2149
	 */
2150
	return apply_filters( 'wp_audio_extensions', array( 'mp3', 'ogg', 'wma', 'm4a', 'wav' ) );
2151
}
2152
2153
/**
2154
 * Returns useful keys to use to lookup data from an attachment's stored metadata.
2155
 *
2156
 * @since 3.9.0
2157
 *
2158
 * @param WP_Post $attachment The current attachment, provided for context.
2159
 * @param string  $context    Optional. The context. Accepts 'edit', 'display'. Default 'display'.
2160
 * @return array Key/value pairs of field keys to labels.
2161
 */
2162
function wp_get_attachment_id3_keys( $attachment, $context = 'display' ) {
2163
	$fields = array(
2164
		'artist' => __( 'Artist' ),
2165
		'album' => __( 'Album' ),
2166
	);
2167
2168
	if ( 'display' === $context ) {
2169
		$fields['genre']            = __( 'Genre' );
2170
		$fields['year']             = __( 'Year' );
2171
		$fields['length_formatted'] = _x( 'Length', 'video or audio' );
2172
	} elseif ( 'js' === $context ) {
2173
		$fields['bitrate']          = __( 'Bitrate' );
2174
		$fields['bitrate_mode']     = __( 'Bitrate Mode' );
2175
	}
2176
2177
	/**
2178
	 * Filters the editable list of keys to look up data from an attachment's metadata.
2179
	 *
2180
	 * @since 3.9.0
2181
	 *
2182
	 * @param array   $fields     Key/value pairs of field keys to labels.
2183
	 * @param WP_Post $attachment Attachment object.
2184
	 * @param string  $context    The context. Accepts 'edit', 'display'. Default 'display'.
2185
	 */
2186
	return apply_filters( 'wp_get_attachment_id3_keys', $fields, $attachment, $context );
2187
}
2188
/**
2189
 * Builds the Audio shortcode output.
2190
 *
2191
 * This implements the functionality of the Audio Shortcode for displaying
2192
 * WordPress mp3s in a post.
2193
 *
2194
 * @since 3.6.0
2195
 *
2196
 * @staticvar int $instance
2197
 *
2198
 * @param array  $attr {
2199
 *     Attributes of the audio shortcode.
2200
 *
2201
 *     @type string $src      URL to the source of the audio file. Default empty.
2202
 *     @type string $loop     The 'loop' attribute for the `<audio>` element. Default empty.
2203
 *     @type string $autoplay The 'autoplay' attribute for the `<audio>` element. Default empty.
2204
 *     @type string $preload  The 'preload' attribute for the `<audio>` element. Default 'none'.
2205
 *     @type string $class    The 'class' attribute for the `<audio>` element. Default 'wp-audio-shortcode'.
2206
 *     @type string $style    The 'style' attribute for the `<audio>` element. Default 'width: 100%;'.
2207
 * }
2208
 * @param string $content Shortcode content.
2209
 * @return string|void HTML content to display audio.
2210
 */
2211
function wp_audio_shortcode( $attr, $content = '' ) {
2212
	$post_id = get_post() ? get_the_ID() : 0;
2213
2214
	static $instance = 0;
2215
	$instance++;
2216
2217
	/**
2218
	 * Filters the default audio shortcode output.
2219
	 *
2220
	 * If the filtered output isn't empty, it will be used instead of generating the default audio template.
2221
	 *
2222
	 * @since 3.6.0
2223
	 *
2224
	 * @param string $html     Empty variable to be replaced with shortcode markup.
2225
	 * @param array  $attr     Attributes of the shortcode. @see wp_audio_shortcode()
2226
	 * @param string $content  Shortcode content.
2227
	 * @param int    $instance Unique numeric ID of this audio shortcode instance.
2228
	 */
2229
	$override = apply_filters( 'wp_audio_shortcode_override', '', $attr, $content, $instance );
2230
	if ( '' !== $override ) {
2231
		return $override;
2232
	}
2233
2234
	$audio = null;
2235
2236
	$default_types = wp_get_audio_extensions();
2237
	$defaults_atts = array(
2238
		'src'      => '',
2239
		'loop'     => '',
2240
		'autoplay' => '',
2241
		'preload'  => 'none',
2242
		'class'    => 'wp-audio-shortcode',
2243
		'style'    => 'width: 100%;'
2244
	);
2245
	foreach ( $default_types as $type ) {
2246
		$defaults_atts[$type] = '';
2247
	}
2248
2249
	$atts = shortcode_atts( $defaults_atts, $attr, 'audio' );
2250
2251
	$primary = false;
2252
	if ( ! empty( $atts['src'] ) ) {
2253
		$type = wp_check_filetype( $atts['src'], wp_get_mime_types() );
2254 View Code Duplication
		if ( ! in_array( strtolower( $type['ext'] ), $default_types ) ) {
2255
			return sprintf( '<a class="wp-embedded-audio" href="%s">%s</a>', esc_url( $atts['src'] ), esc_html( $atts['src'] ) );
2256
		}
2257
		$primary = true;
2258
		array_unshift( $default_types, 'src' );
2259 View Code Duplication
	} else {
2260
		foreach ( $default_types as $ext ) {
2261
			if ( ! empty( $atts[ $ext ] ) ) {
2262
				$type = wp_check_filetype( $atts[ $ext ], wp_get_mime_types() );
2263
				if ( strtolower( $type['ext'] ) === $ext ) {
2264
					$primary = true;
2265
				}
2266
			}
2267
		}
2268
	}
2269
2270 View Code Duplication
	if ( ! $primary ) {
2271
		$audios = get_attached_media( 'audio', $post_id );
2272
		if ( empty( $audios ) ) {
2273
			return;
2274
		}
2275
2276
		$audio = reset( $audios );
2277
		$atts['src'] = wp_get_attachment_url( $audio->ID );
2278
		if ( empty( $atts['src'] ) ) {
2279
			return;
2280
		}
2281
2282
		array_unshift( $default_types, 'src' );
2283
	}
2284
2285
	/**
2286
	 * Filters the media library used for the audio shortcode.
2287
	 *
2288
	 * @since 3.6.0
2289
	 *
2290
	 * @param string $library Media library used for the audio shortcode.
2291
	 */
2292
	$library = apply_filters( 'wp_audio_shortcode_library', 'mediaelement' );
2293
	if ( 'mediaelement' === $library && did_action( 'init' ) ) {
2294
		wp_enqueue_style( 'wp-mediaelement' );
2295
		wp_enqueue_script( 'wp-mediaelement' );
2296
	}
2297
2298
	/**
2299
	 * Filters the class attribute for the audio shortcode output container.
2300
	 *
2301
	 * @since 3.6.0
2302
	 *
2303
	 * @param string $class CSS class or list of space-separated classes.
2304
	 */
2305
	$atts['class'] = apply_filters( 'wp_audio_shortcode_class', $atts['class'] );
2306
2307
	$html_atts = array(
2308
		'class'    => $atts['class'],
2309
		'id'       => sprintf( 'audio-%d-%d', $post_id, $instance ),
2310
		'loop'     => wp_validate_boolean( $atts['loop'] ),
2311
		'autoplay' => wp_validate_boolean( $atts['autoplay'] ),
2312
		'preload'  => $atts['preload'],
2313
		'style'    => $atts['style'],
2314
	);
2315
2316
	// These ones should just be omitted altogether if they are blank
2317 View Code Duplication
	foreach ( array( 'loop', 'autoplay', 'preload' ) as $a ) {
2318
		if ( empty( $html_atts[$a] ) ) {
2319
			unset( $html_atts[$a] );
2320
		}
2321
	}
2322
2323
	$attr_strings = array();
2324 View Code Duplication
	foreach ( $html_atts as $k => $v ) {
2325
		$attr_strings[] = $k . '="' . esc_attr( $v ) . '"';
2326
	}
2327
2328
	$html = '';
2329
	if ( 'mediaelement' === $library && 1 === $instance ) {
2330
		$html .= "<!--[if lt IE 9]><script>document.createElement('audio');</script><![endif]-->\n";
2331
	}
2332
	$html .= sprintf( '<audio %s controls="controls">', join( ' ', $attr_strings ) );
2333
2334
	$fileurl = '';
2335
	$source = '<source type="%s" src="%s" />';
2336
	foreach ( $default_types as $fallback ) {
2337
		if ( ! empty( $atts[ $fallback ] ) ) {
2338
			if ( empty( $fileurl ) ) {
2339
				$fileurl = $atts[ $fallback ];
2340
			}
2341
			$type = wp_check_filetype( $atts[ $fallback ], wp_get_mime_types() );
2342
			$url = add_query_arg( '_', $instance, $atts[ $fallback ] );
2343
			$html .= sprintf( $source, $type['type'], esc_url( $url ) );
2344
		}
2345
	}
2346
2347
	if ( 'mediaelement' === $library ) {
2348
		$html .= wp_mediaelement_fallback( $fileurl );
2349
	}
2350
	$html .= '</audio>';
2351
2352
	/**
2353
	 * Filters the audio shortcode output.
2354
	 *
2355
	 * @since 3.6.0
2356
	 *
2357
	 * @param string $html    Audio shortcode HTML output.
2358
	 * @param array  $atts    Array of audio shortcode attributes.
2359
	 * @param string $audio   Audio file.
2360
	 * @param int    $post_id Post ID.
2361
	 * @param string $library Media library used for the audio shortcode.
2362
	 */
2363
	return apply_filters( 'wp_audio_shortcode', $html, $atts, $audio, $post_id, $library );
2364
}
2365
add_shortcode( 'audio', 'wp_audio_shortcode' );
2366
2367
/**
2368
 * Returns a filtered list of WP-supported video formats.
2369
 *
2370
 * @since 3.6.0
2371
 *
2372
 * @return array List of supported video formats.
2373
 */
2374
function wp_get_video_extensions() {
2375
	/**
2376
	 * Filters the list of supported video formats.
2377
	 *
2378
	 * @since 3.6.0
2379
	 *
2380
	 * @param array $extensions An array of support video formats. Defaults are
2381
	 *                          'mp4', 'm4v', 'webm', 'ogv', 'wmv', 'flv'.
2382
	 */
2383
	return apply_filters( 'wp_video_extensions', array( 'mp4', 'm4v', 'webm', 'ogv', 'wmv', 'flv' ) );
2384
}
2385
2386
/**
2387
 * Builds the Video shortcode output.
2388
 *
2389
 * This implements the functionality of the Video Shortcode for displaying
2390
 * WordPress mp4s in a post.
2391
 *
2392
 * @since 3.6.0
2393
 *
2394
 * @global int $content_width
2395
 * @staticvar int $instance
2396
 *
2397
 * @param array  $attr {
2398
 *     Attributes of the shortcode.
2399
 *
2400
 *     @type string $src      URL to the source of the video file. Default empty.
2401
 *     @type int    $height   Height of the video embed in pixels. Default 360.
2402
 *     @type int    $width    Width of the video embed in pixels. Default $content_width or 640.
2403
 *     @type string $poster   The 'poster' attribute for the `<video>` element. Default empty.
2404
 *     @type string $loop     The 'loop' attribute for the `<video>` element. Default empty.
2405
 *     @type string $autoplay The 'autoplay' attribute for the `<video>` element. Default empty.
2406
 *     @type string $preload  The 'preload' attribute for the `<video>` element.
2407
 *                            Default 'metadata'.
2408
 *     @type string $class    The 'class' attribute for the `<video>` element.
2409
 *                            Default 'wp-video-shortcode'.
2410
 * }
2411
 * @param string $content Shortcode content.
2412
 * @return string|void HTML content to display video.
2413
 */
2414
function wp_video_shortcode( $attr, $content = '' ) {
2415
	global $content_width;
2416
	$post_id = get_post() ? get_the_ID() : 0;
2417
2418
	static $instance = 0;
2419
	$instance++;
2420
2421
	/**
2422
	 * Filters the default video shortcode output.
2423
	 *
2424
	 * If the filtered output isn't empty, it will be used instead of generating
2425
	 * the default video template.
2426
	 *
2427
	 * @since 3.6.0
2428
	 *
2429
	 * @see wp_video_shortcode()
2430
	 *
2431
	 * @param string $html     Empty variable to be replaced with shortcode markup.
2432
	 * @param array  $attr     Attributes of the video shortcode.
2433
	 * @param string $content  Video shortcode content.
2434
	 * @param int    $instance Unique numeric ID of this video shortcode instance.
2435
	 */
2436
	$override = apply_filters( 'wp_video_shortcode_override', '', $attr, $content, $instance );
2437
	if ( '' !== $override ) {
2438
		return $override;
2439
	}
2440
2441
	$video = null;
2442
2443
	$default_types = wp_get_video_extensions();
2444
	$defaults_atts = array(
2445
		'src'      => '',
2446
		'poster'   => '',
2447
		'loop'     => '',
2448
		'autoplay' => '',
2449
		'preload'  => 'metadata',
2450
		'width'    => 640,
2451
		'height'   => 360,
2452
		'class'    => 'wp-video-shortcode',
2453
	);
2454
2455
	foreach ( $default_types as $type ) {
2456
		$defaults_atts[$type] = '';
2457
	}
2458
2459
	$atts = shortcode_atts( $defaults_atts, $attr, 'video' );
2460
2461
	if ( is_admin() ) {
2462
		// shrink the video so it isn't huge in the admin
2463
		if ( $atts['width'] > $defaults_atts['width'] ) {
2464
			$atts['height'] = round( ( $atts['height'] * $defaults_atts['width'] ) / $atts['width'] );
2465
			$atts['width'] = $defaults_atts['width'];
2466
		}
2467
	} else {
2468
		// if the video is bigger than the theme
2469
		if ( ! empty( $content_width ) && $atts['width'] > $content_width ) {
2470
			$atts['height'] = round( ( $atts['height'] * $content_width ) / $atts['width'] );
2471
			$atts['width'] = $content_width;
2472
		}
2473
	}
2474
2475
	$is_vimeo = $is_youtube = false;
2476
	$yt_pattern = '#^https?://(?:www\.)?(?:youtube\.com/watch|youtu\.be/)#';
2477
	$vimeo_pattern = '#^https?://(.+\.)?vimeo\.com/.*#';
2478
2479
	$primary = false;
2480
	if ( ! empty( $atts['src'] ) ) {
2481
		$is_vimeo = ( preg_match( $vimeo_pattern, $atts['src'] ) );
2482
		$is_youtube = (  preg_match( $yt_pattern, $atts['src'] ) );
2483
		if ( ! $is_youtube && ! $is_vimeo ) {
2484
			$type = wp_check_filetype( $atts['src'], wp_get_mime_types() );
2485 View Code Duplication
			if ( ! in_array( strtolower( $type['ext'] ), $default_types ) ) {
2486
				return sprintf( '<a class="wp-embedded-video" href="%s">%s</a>', esc_url( $atts['src'] ), esc_html( $atts['src'] ) );
2487
			}
2488
		}
2489
2490
		if ( $is_vimeo ) {
2491
			wp_enqueue_script( 'froogaloop' );
2492
		}
2493
2494
		$primary = true;
2495
		array_unshift( $default_types, 'src' );
2496 View Code Duplication
	} else {
2497
		foreach ( $default_types as $ext ) {
2498
			if ( ! empty( $atts[ $ext ] ) ) {
2499
				$type = wp_check_filetype( $atts[ $ext ], wp_get_mime_types() );
2500
				if ( strtolower( $type['ext'] ) === $ext ) {
2501
					$primary = true;
2502
				}
2503
			}
2504
		}
2505
	}
2506
2507 View Code Duplication
	if ( ! $primary ) {
2508
		$videos = get_attached_media( 'video', $post_id );
2509
		if ( empty( $videos ) ) {
2510
			return;
2511
		}
2512
2513
		$video = reset( $videos );
2514
		$atts['src'] = wp_get_attachment_url( $video->ID );
2515
		if ( empty( $atts['src'] ) ) {
2516
			return;
2517
		}
2518
2519
		array_unshift( $default_types, 'src' );
2520
	}
2521
2522
	/**
2523
	 * Filters the media library used for the video shortcode.
2524
	 *
2525
	 * @since 3.6.0
2526
	 *
2527
	 * @param string $library Media library used for the video shortcode.
2528
	 */
2529
	$library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' );
2530
	if ( 'mediaelement' === $library && did_action( 'init' ) ) {
2531
		wp_enqueue_style( 'wp-mediaelement' );
2532
		wp_enqueue_script( 'wp-mediaelement' );
2533
	}
2534
2535
	/**
2536
	 * Filters the class attribute for the video shortcode output container.
2537
	 *
2538
	 * @since 3.6.0
2539
	 *
2540
	 * @param string $class CSS class or list of space-separated classes.
2541
	 */
2542
	$atts['class'] = apply_filters( 'wp_video_shortcode_class', $atts['class'] );
2543
2544
	$html_atts = array(
2545
		'class'    => $atts['class'],
2546
		'id'       => sprintf( 'video-%d-%d', $post_id, $instance ),
2547
		'width'    => absint( $atts['width'] ),
2548
		'height'   => absint( $atts['height'] ),
2549
		'poster'   => esc_url( $atts['poster'] ),
2550
		'loop'     => wp_validate_boolean( $atts['loop'] ),
2551
		'autoplay' => wp_validate_boolean( $atts['autoplay'] ),
2552
		'preload'  => $atts['preload'],
2553
	);
2554
2555
	// These ones should just be omitted altogether if they are blank
2556 View Code Duplication
	foreach ( array( 'poster', 'loop', 'autoplay', 'preload' ) as $a ) {
2557
		if ( empty( $html_atts[$a] ) ) {
2558
			unset( $html_atts[$a] );
2559
		}
2560
	}
2561
2562
	$attr_strings = array();
2563 View Code Duplication
	foreach ( $html_atts as $k => $v ) {
2564
		$attr_strings[] = $k . '="' . esc_attr( $v ) . '"';
2565
	}
2566
2567
	$html = '';
2568
	if ( 'mediaelement' === $library && 1 === $instance ) {
2569
		$html .= "<!--[if lt IE 9]><script>document.createElement('video');</script><![endif]-->\n";
2570
	}
2571
	$html .= sprintf( '<video %s controls="controls">', join( ' ', $attr_strings ) );
2572
2573
	$fileurl = '';
2574
	$source = '<source type="%s" src="%s" />';
2575
	foreach ( $default_types as $fallback ) {
2576
		if ( ! empty( $atts[ $fallback ] ) ) {
2577
			if ( empty( $fileurl ) ) {
2578
				$fileurl = $atts[ $fallback ];
2579
			}
2580
			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...
2581
				$type = array( 'type' => 'video/youtube' );
2582
			} 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...
2583
				$type = array( 'type' => 'video/vimeo' );
2584
			} else {
2585
				$type = wp_check_filetype( $atts[ $fallback ], wp_get_mime_types() );
2586
			}
2587
			$url = add_query_arg( '_', $instance, $atts[ $fallback ] );
2588
			$html .= sprintf( $source, $type['type'], esc_url( $url ) );
2589
		}
2590
	}
2591
2592
	if ( ! empty( $content ) ) {
2593 View Code Duplication
		if ( false !== strpos( $content, "\n" ) ) {
2594
			$content = str_replace( array( "\r\n", "\n", "\t" ), '', $content );
2595
		}
2596
		$html .= trim( $content );
2597
	}
2598
2599
	if ( 'mediaelement' === $library ) {
2600
		$html .= wp_mediaelement_fallback( $fileurl );
2601
	}
2602
	$html .= '</video>';
2603
2604
	$width_rule = '';
2605
	if ( ! empty( $atts['width'] ) ) {
2606
		$width_rule = sprintf( 'width: %dpx; ', $atts['width'] );
2607
	}
2608
	$output = sprintf( '<div style="%s" class="wp-video">%s</div>', $width_rule, $html );
2609
2610
	/**
2611
	 * Filters the output of the video shortcode.
2612
	 *
2613
	 * @since 3.6.0
2614
	 *
2615
	 * @param string $output  Video shortcode HTML output.
2616
	 * @param array  $atts    Array of video shortcode attributes.
2617
	 * @param string $video   Video file.
2618
	 * @param int    $post_id Post ID.
2619
	 * @param string $library Media library used for the video shortcode.
2620
	 */
2621
	return apply_filters( 'wp_video_shortcode', $output, $atts, $video, $post_id, $library );
2622
}
2623
add_shortcode( 'video', 'wp_video_shortcode' );
2624
2625
/**
2626
 * Displays previous 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 previous_image_link( $size = 'thumbnail', $text = false ) {
2638
	adjacent_image_link(true, $size, $text);
0 ignored issues
show
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 image link that has the same post parent.
2643
 *
2644
 * @since 2.5.0
2645
 *
2646
 * @see adjacent_image_link()
2647
 *
2648
 * @param string|array $size Optional. Image size. Accepts any valid image size, an array of width and
2649
 *                           height values in pixels (in that order), 0, or 'none'. 0 or 'none' will
2650
 *                           default to 'post_title' or `$text`. Default 'thumbnail'.
2651
 * @param string       $text Optional. Link text. Default false.
2652
 */
2653
function next_image_link( $size = 'thumbnail', $text = false ) {
2654
	adjacent_image_link(false, $size, $text);
0 ignored issues
show
It seems like $text defined by parameter $text on line 2653 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...
2655
}
2656
2657
/**
2658
 * Displays next or previous image link that has the same post parent.
2659
 *
2660
 * Retrieves the current attachment object from the $post global.
2661
 *
2662
 * @since 2.5.0
2663
 *
2664
 * @param bool         $prev Optional. Whether to display the next (false) or previous (true) link. Default true.
2665
 * @param string|array $size Optional. Image size. Accepts any valid image size, or an array of width and height
2666
 *                           values in pixels (in that order). Default 'thumbnail'.
2667
 * @param bool         $text Optional. Link text. Default false.
2668
 */
2669
function adjacent_image_link( $prev = true, $size = 'thumbnail', $text = false ) {
2670
	$post = get_post();
2671
	$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' ) ) );
2672
2673
	foreach ( $attachments as $k => $attachment ) {
2674
		if ( $attachment->ID == $post->ID ) {
2675
			break;
2676
		}
2677
	}
2678
2679
	$output = '';
2680
	$attachment_id = 0;
2681
2682
	if ( $attachments ) {
2683
		$k = $prev ? $k - 1 : $k + 1;
0 ignored issues
show
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...
2684
2685
		if ( isset( $attachments[ $k ] ) ) {
2686
			$attachment_id = $attachments[ $k ]->ID;
2687
			$output = wp_get_attachment_link( $attachment_id, $size, true, false, $text );
0 ignored issues
show
$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...
2688
		}
2689
	}
2690
2691
	$adjacent = $prev ? 'previous' : 'next';
2692
2693
	/**
2694
	 * Filters the adjacent image link.
2695
	 *
2696
	 * The dynamic portion of the hook name, `$adjacent`, refers to the type of adjacency,
2697
	 * either 'next', or 'previous'.
2698
	 *
2699
	 * @since 3.5.0
2700
	 *
2701
	 * @param string $output        Adjacent image HTML markup.
2702
	 * @param int    $attachment_id Attachment ID
2703
	 * @param string $size          Image size.
2704
	 * @param string $text          Link text.
2705
	 */
2706
	echo apply_filters( "{$adjacent}_image_link", $output, $attachment_id, $size, $text );
2707
}
2708
2709
/**
2710
 * Retrieves taxonomies attached to given the attachment.
2711
 *
2712
 * @since 2.5.0
2713
 * @since 4.7.0 Introduced the `$output` parameter.
2714
 *
2715
 * @param int|array|object $attachment Attachment ID, data array, or data object.
2716
 * @param string           $output     Output type. 'names' to return an array of taxonomy names,
2717
 *                                     or 'objects' to return an array of taxonomy objects.
2718
 *                                     Default is 'names'.
2719
 * @return array Empty array on failure. List of taxonomies on success.
2720
 */
2721
function get_attachment_taxonomies( $attachment, $output = 'names' ) {
2722
	if ( is_int( $attachment ) ) {
2723
		$attachment = get_post( $attachment );
2724
	} elseif ( is_array( $attachment ) ) {
2725
		$attachment = (object) $attachment;
2726
	}
2727
	if ( ! is_object($attachment) )
2728
		return array();
2729
2730
	$file = get_attached_file( $attachment->ID );
2731
	$filename = basename( $file );
2732
2733
	$objects = array('attachment');
2734
2735
	if ( false !== strpos($filename, '.') )
2736
		$objects[] = 'attachment:' . substr($filename, strrpos($filename, '.') + 1);
2737
	if ( !empty($attachment->post_mime_type) ) {
2738
		$objects[] = 'attachment:' . $attachment->post_mime_type;
2739
		if ( false !== strpos($attachment->post_mime_type, '/') )
2740
			foreach ( explode('/', $attachment->post_mime_type) as $token )
2741
				if ( !empty($token) )
2742
					$objects[] = "attachment:$token";
2743
	}
2744
2745
	$taxonomies = array();
2746
	foreach ( $objects as $object ) {
2747
		if ( $taxes = get_object_taxonomies( $object, $output ) ) {
2748
			$taxonomies = array_merge( $taxonomies, $taxes );
2749
		}
2750
	}
2751
2752
	return array_unique($taxonomies);
2753
}
2754
2755
/**
2756
 * Retrieves all of the taxonomy names that are registered for attachments.
2757
 *
2758
 * Handles mime-type-specific taxonomies such as attachment:image and attachment:video.
2759
 *
2760
 * @since 3.5.0
2761
 *
2762
 * @see get_taxonomies()
2763
 *
2764
 * @param string $output Optional. The type of taxonomy output to return. Accepts 'names' or 'objects'.
2765
 *                       Default 'names'.
2766
 * @return array The names of all taxonomy of $object_type.
2767
 */
2768
function get_taxonomies_for_attachments( $output = 'names' ) {
2769
	$taxonomies = array();
2770
	foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy ) {
2771
		foreach ( $taxonomy->object_type as $object_type ) {
2772
			if ( 'attachment' == $object_type || 0 === strpos( $object_type, 'attachment:' ) ) {
2773
				if ( 'names' == $output )
2774
					$taxonomies[] = $taxonomy->name;
2775
				else
2776
					$taxonomies[ $taxonomy->name ] = $taxonomy;
2777
				break;
2778
			}
2779
		}
2780
	}
2781
2782
	return $taxonomies;
2783
}
2784
2785
/**
2786
 * Create new GD image resource with transparency support
2787
 *
2788
 * @todo: Deprecate if possible.
2789
 *
2790
 * @since 2.9.0
2791
 *
2792
 * @param int $width  Image width in pixels.
2793
 * @param int $height Image height in pixels..
2794
 * @return resource The GD image resource.
2795
 */
2796
function wp_imagecreatetruecolor($width, $height) {
2797
	$img = imagecreatetruecolor($width, $height);
2798
	if ( is_resource($img) && function_exists('imagealphablending') && function_exists('imagesavealpha') ) {
2799
		imagealphablending($img, false);
2800
		imagesavealpha($img, true);
2801
	}
2802
	return $img;
2803
}
2804
2805
/**
2806
 * Based on a supplied width/height example, return the biggest possible dimensions based on the max width/height.
2807
 *
2808
 * @since 2.9.0
2809
 *
2810
 * @see wp_constrain_dimensions()
2811
 *
2812
 * @param int $example_width  The width of an example embed.
2813
 * @param int $example_height The height of an example embed.
2814
 * @param int $max_width      The maximum allowed width.
2815
 * @param int $max_height     The maximum allowed height.
2816
 * @return array The maximum possible width and height based on the example ratio.
2817
 */
2818
function wp_expand_dimensions( $example_width, $example_height, $max_width, $max_height ) {
2819
	$example_width  = (int) $example_width;
2820
	$example_height = (int) $example_height;
2821
	$max_width      = (int) $max_width;
2822
	$max_height     = (int) $max_height;
2823
2824
	return wp_constrain_dimensions( $example_width * 1000000, $example_height * 1000000, $max_width, $max_height );
2825
}
2826
2827
/**
2828
 * Determines the maximum upload size allowed in php.ini.
2829
 *
2830
 * @since 2.5.0
2831
 *
2832
 * @return int Allowed upload size.
2833
 */
2834
function wp_max_upload_size() {
2835
	$u_bytes = wp_convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) );
2836
	$p_bytes = wp_convert_hr_to_bytes( ini_get( 'post_max_size' ) );
2837
2838
	/**
2839
	 * Filters the maximum upload size allowed in php.ini.
2840
	 *
2841
	 * @since 2.5.0
2842
	 *
2843
	 * @param int $size    Max upload size limit in bytes.
2844
	 * @param int $u_bytes Maximum upload filesize in bytes.
2845
	 * @param int $p_bytes Maximum size of POST data in bytes.
2846
	 */
2847
	return apply_filters( 'upload_size_limit', min( $u_bytes, $p_bytes ), $u_bytes, $p_bytes );
2848
}
2849
2850
/**
2851
 * Returns a WP_Image_Editor instance and loads file into it.
2852
 *
2853
 * @since 3.5.0
2854
 *
2855
 * @param string $path Path to the file to load.
2856
 * @param array  $args Optional. Additional arguments for retrieving the image editor.
2857
 *                     Default empty array.
2858
 * @return WP_Image_Editor|WP_Error The WP_Image_Editor object if successful, an WP_Error
2859
 *                                  object otherwise.
2860
 */
2861
function wp_get_image_editor( $path, $args = array() ) {
2862
	$args['path'] = $path;
2863
2864
	if ( ! isset( $args['mime_type'] ) ) {
2865
		$file_info = wp_check_filetype( $args['path'] );
2866
2867
		// If $file_info['type'] is false, then we let the editor attempt to
2868
		// figure out the file type, rather than forcing a failure based on extension.
2869
		if ( isset( $file_info ) && $file_info['type'] )
2870
			$args['mime_type'] = $file_info['type'];
2871
	}
2872
2873
	$implementation = _wp_image_editor_choose( $args );
2874
2875
	if ( $implementation ) {
2876
		$editor = new $implementation( $path );
2877
		$loaded = $editor->load();
2878
2879
		if ( is_wp_error( $loaded ) )
2880
			return $loaded;
2881
2882
		return $editor;
2883
	}
2884
2885
	return new WP_Error( 'image_no_editor', __('No editor could be selected.') );
2886
}
2887
2888
/**
2889
 * Tests whether there is an editor that supports a given mime type or methods.
2890
 *
2891
 * @since 3.5.0
2892
 *
2893
 * @param string|array $args Optional. Array of arguments to retrieve the image editor supports.
2894
 *                           Default empty array.
2895
 * @return bool True if an eligible editor is found; false otherwise.
2896
 */
2897
function wp_image_editor_supports( $args = array() ) {
2898
	return (bool) _wp_image_editor_choose( $args );
0 ignored issues
show
It seems like $args defined by parameter $args on line 2897 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...
2899
}
2900
2901
/**
2902
 * Tests which editors are capable of supporting the request.
2903
 *
2904
 * @ignore
2905
 * @since 3.5.0
2906
 *
2907
 * @param array $args Optional. Array of arguments for choosing a capable editor. Default empty array.
2908
 * @return string|false Class name for the first editor that claims to support the request. False if no
2909
 *                     editor claims to support the request.
2910
 */
2911
function _wp_image_editor_choose( $args = array() ) {
2912
	require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
2913
	require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';
2914
	require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php';
2915
2916
	/**
2917
	 * Filters the list of image editing library classes.
2918
	 *
2919
	 * @since 3.5.0
2920
	 *
2921
	 * @param array $image_editors List of available image editors. Defaults are
2922
	 *                             'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD'.
2923
	 */
2924
	$implementations = apply_filters( 'wp_image_editors', array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) );
2925
2926
	foreach ( $implementations as $implementation ) {
2927
		if ( ! call_user_func( array( $implementation, 'test' ), $args ) )
2928
			continue;
2929
2930
		if ( isset( $args['mime_type'] ) &&
2931
			! call_user_func(
2932
				array( $implementation, 'supports_mime_type' ),
2933
				$args['mime_type'] ) ) {
2934
			continue;
2935
		}
2936
2937
		if ( isset( $args['methods'] ) &&
2938
			 array_diff( $args['methods'], get_class_methods( $implementation ) ) ) {
2939
			continue;
2940
		}
2941
2942
		return $implementation;
2943
	}
2944
2945
	return false;
2946
}
2947
2948
/**
2949
 * Prints default Plupload arguments.
2950
 *
2951
 * @since 3.4.0
2952
 */
2953
function wp_plupload_default_settings() {
2954
	$wp_scripts = wp_scripts();
2955
2956
	$data = $wp_scripts->get_data( 'wp-plupload', 'data' );
2957
	if ( $data && false !== strpos( $data, '_wpPluploadSettings' ) )
2958
		return;
2959
2960
	$max_upload_size = wp_max_upload_size();
2961
	$allowed_extensions = array_keys( get_allowed_mime_types() );
2962
	$extensions = array();
2963
	foreach ( $allowed_extensions as $extension ) {
2964
		$extensions = array_merge( $extensions, explode( '|', $extension ) );
2965
	}
2966
2967
	$defaults = array(
2968
		'runtimes'            => 'html5,flash,silverlight,html4',
2969
		'file_data_name'      => 'async-upload', // key passed to $_FILE.
2970
		'url'                 => admin_url( 'async-upload.php', 'relative' ),
2971
		'flash_swf_url'       => includes_url( 'js/plupload/plupload.flash.swf' ),
2972
		'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
2973
		'filters' => array(
2974
			'max_file_size'   => $max_upload_size . 'b',
2975
			'mime_types'      => array( array( 'extensions' => implode( ',', $extensions ) ) ),
2976
		),
2977
	);
2978
2979
	// Currently only iOS Safari supports multiple files uploading but iOS 7.x has a bug that prevents uploading of videos
2980
	// when enabled. See #29602.
2981 View Code Duplication
	if ( wp_is_mobile() && strpos( $_SERVER['HTTP_USER_AGENT'], 'OS 7_' ) !== false &&
2982
		strpos( $_SERVER['HTTP_USER_AGENT'], 'like Mac OS X' ) !== false ) {
2983
2984
		$defaults['multi_selection'] = false;
2985
	}
2986
2987
	/**
2988
	 * Filters the Plupload default settings.
2989
	 *
2990
	 * @since 3.4.0
2991
	 *
2992
	 * @param array $defaults Default Plupload settings array.
2993
	 */
2994
	$defaults = apply_filters( 'plupload_default_settings', $defaults );
2995
2996
	$params = array(
2997
		'action' => 'upload-attachment',
2998
	);
2999
3000
	/**
3001
	 * Filters the Plupload default parameters.
3002
	 *
3003
	 * @since 3.4.0
3004
	 *
3005
	 * @param array $params Default Plupload parameters array.
3006
	 */
3007
	$params = apply_filters( 'plupload_default_params', $params );
3008
	$params['_wpnonce'] = wp_create_nonce( 'media-form' );
3009
	$defaults['multipart_params'] = $params;
3010
3011
	$settings = array(
3012
		'defaults' => $defaults,
3013
		'browser'  => array(
3014
			'mobile'    => wp_is_mobile(),
3015
			'supported' => _device_can_upload(),
3016
		),
3017
		'limitExceeded' => is_multisite() && ! is_upload_space_available()
3018
	);
3019
3020
	$script = 'var _wpPluploadSettings = ' . wp_json_encode( $settings ) . ';';
3021
3022
	if ( $data )
3023
		$script = "$data\n$script";
3024
3025
	$wp_scripts->add_data( 'wp-plupload', 'data', $script );
3026
}
3027
3028
/**
3029
 * Prepares an attachment post object for JS, where it is expected
3030
 * to be JSON-encoded and fit into an Attachment model.
3031
 *
3032
 * @since 3.5.0
3033
 *
3034
 * @param mixed $attachment Attachment ID or object.
3035
 * @return array|void Array of attachment details.
3036
 */
3037
function wp_prepare_attachment_for_js( $attachment ) {
3038
	if ( ! $attachment = get_post( $attachment ) )
3039
		return;
3040
3041
	if ( 'attachment' != $attachment->post_type )
3042
		return;
3043
3044
	$meta = wp_get_attachment_metadata( $attachment->ID );
3045 View Code Duplication
	if ( false !== strpos( $attachment->post_mime_type, '/' ) )
3046
		list( $type, $subtype ) = explode( '/', $attachment->post_mime_type );
3047
	else
3048
		list( $type, $subtype ) = array( $attachment->post_mime_type, '' );
3049
3050
	$attachment_url = wp_get_attachment_url( $attachment->ID );
3051
3052
	$response = array(
3053
		'id'          => $attachment->ID,
3054
		'title'       => $attachment->post_title,
3055
		'filename'    => wp_basename( get_attached_file( $attachment->ID ) ),
0 ignored issues
show
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...
3056
		'url'         => $attachment_url,
3057
		'link'        => get_attachment_link( $attachment->ID ),
3058
		'alt'         => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ),
3059
		'author'      => $attachment->post_author,
3060
		'description' => $attachment->post_content,
3061
		'caption'     => $attachment->post_excerpt,
3062
		'name'        => $attachment->post_name,
3063
		'status'      => $attachment->post_status,
3064
		'uploadedTo'  => $attachment->post_parent,
3065
		'date'        => strtotime( $attachment->post_date_gmt ) * 1000,
3066
		'modified'    => strtotime( $attachment->post_modified_gmt ) * 1000,
3067
		'menuOrder'   => $attachment->menu_order,
3068
		'mime'        => $attachment->post_mime_type,
3069
		'type'        => $type,
3070
		'subtype'     => $subtype,
3071
		'icon'        => wp_mime_type_icon( $attachment->ID ),
3072
		'dateFormatted' => mysql2date( __( 'F j, Y' ), $attachment->post_date ),
3073
		'nonces'      => array(
3074
			'update' => false,
3075
			'delete' => false,
3076
			'edit'   => false
3077
		),
3078
		'editLink'   => false,
3079
		'meta'       => false,
3080
	);
3081
3082
	$author = new WP_User( $attachment->post_author );
3083
	$response['authorName'] = $author->display_name;
3084
3085
	if ( $attachment->post_parent ) {
3086
		$post_parent = get_post( $attachment->post_parent );
3087
	} else {
3088
		$post_parent = false;
3089
	}
3090
3091
	if ( $post_parent ) {
3092
		$parent_type = get_post_type_object( $post_parent->post_type );
3093
3094
		if ( $parent_type && $parent_type->show_ui && current_user_can( 'edit_post', $attachment->post_parent ) ) {
3095
			$response['uploadedToLink'] = get_edit_post_link( $attachment->post_parent, 'raw' );
3096
		}
3097
3098
		if ( $parent_type && current_user_can( 'read_post', $attachment->post_parent ) ) {
3099
			$response['uploadedToTitle'] = $post_parent->post_title ? $post_parent->post_title : __( '(no title)' );
3100
		}
3101
	}
3102
3103
	$attached_file = get_attached_file( $attachment->ID );
3104
3105
	if ( isset( $meta['filesize'] ) ) {
3106
		$bytes = $meta['filesize'];
3107
	} elseif ( file_exists( $attached_file ) ) {
3108
		$bytes = filesize( $attached_file );
3109
	} else {
3110
		$bytes = '';
3111
	}
3112
3113
	if ( $bytes ) {
3114
		$response['filesizeInBytes'] = $bytes;
3115
		$response['filesizeHumanReadable'] = size_format( $bytes );
3116
	}
3117
3118
	if ( current_user_can( 'edit_post', $attachment->ID ) ) {
3119
		$response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID );
3120
		$response['nonces']['edit'] = wp_create_nonce( 'image_editor-' . $attachment->ID );
3121
		$response['editLink'] = get_edit_post_link( $attachment->ID, 'raw' );
3122
	}
3123
3124
	if ( current_user_can( 'delete_post', $attachment->ID ) )
3125
		$response['nonces']['delete'] = wp_create_nonce( 'delete-post_' . $attachment->ID );
3126
3127
	if ( $meta && 'image' === $type ) {
3128
		$sizes = array();
3129
3130
		/** This filter is documented in wp-admin/includes/media.php */
3131
		$possible_sizes = apply_filters( 'image_size_names_choose', array(
3132
			'thumbnail' => __('Thumbnail'),
3133
			'medium'    => __('Medium'),
3134
			'large'     => __('Large'),
3135
			'full'      => __('Full Size'),
3136
		) );
3137
		unset( $possible_sizes['full'] );
3138
3139
		// Loop through all potential sizes that may be chosen. Try to do this with some efficiency.
3140
		// First: run the image_downsize filter. If it returns something, we can use its data.
3141
		// If the filter does not return something, then image_downsize() is just an expensive
3142
		// way to check the image metadata, which we do second.
3143
		foreach ( $possible_sizes as $size => $label ) {
3144
3145
			/** This filter is documented in wp-includes/media.php */
3146
			if ( $downsize = apply_filters( 'image_downsize', false, $attachment->ID, $size ) ) {
3147
				if ( ! $downsize[3] )
3148
					continue;
3149
				$sizes[ $size ] = array(
3150
					'height'      => $downsize[2],
3151
					'width'       => $downsize[1],
3152
					'url'         => $downsize[0],
3153
					'orientation' => $downsize[2] > $downsize[1] ? 'portrait' : 'landscape',
3154
				);
3155
			} elseif ( isset( $meta['sizes'][ $size ] ) ) {
3156
				if ( ! isset( $base_url ) )
3157
					$base_url = str_replace( wp_basename( $attachment_url ), '', $attachment_url );
0 ignored issues
show
It seems like $attachment_url defined by wp_get_attachment_url($attachment->ID) on line 3050 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...
3158
3159
				// Nothing from the filter, so consult image metadata if we have it.
3160
				$size_meta = $meta['sizes'][ $size ];
3161
3162
				// We have the actual image size, but might need to further constrain it if content_width is narrower.
3163
				// Thumbnail, medium, and full sizes are also checked against the site's height/width options.
3164
				list( $width, $height ) = image_constrain_size_for_editor( $size_meta['width'], $size_meta['height'], $size, 'edit' );
3165
3166
				$sizes[ $size ] = array(
3167
					'height'      => $height,
3168
					'width'       => $width,
3169
					'url'         => $base_url . $size_meta['file'],
3170
					'orientation' => $height > $width ? 'portrait' : 'landscape',
3171
				);
3172
			}
3173
		}
3174
3175
		$sizes['full'] = array( 'url' => $attachment_url );
3176
3177
		if ( isset( $meta['height'], $meta['width'] ) ) {
3178
			$sizes['full']['height'] = $meta['height'];
3179
			$sizes['full']['width'] = $meta['width'];
3180
			$sizes['full']['orientation'] = $meta['height'] > $meta['width'] ? 'portrait' : 'landscape';
3181
		}
3182
3183
		$response = array_merge( $response, array( 'sizes' => $sizes ), $sizes['full'] );
3184
	} elseif ( $meta && 'video' === $type ) {
3185
		if ( isset( $meta['width'] ) )
3186
			$response['width'] = (int) $meta['width'];
3187
		if ( isset( $meta['height'] ) )
3188
			$response['height'] = (int) $meta['height'];
3189
	}
3190
3191
	if ( $meta && ( 'audio' === $type || 'video' === $type ) ) {
3192
		if ( isset( $meta['length_formatted'] ) )
3193
			$response['fileLength'] = $meta['length_formatted'];
3194
3195
		$response['meta'] = array();
3196
		foreach ( wp_get_attachment_id3_keys( $attachment, 'js' ) as $key => $label ) {
0 ignored issues
show
It seems like $attachment defined by get_post($attachment) on line 3038 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...
3197
			$response['meta'][ $key ] = false;
3198
3199
			if ( ! empty( $meta[ $key ] ) ) {
3200
				$response['meta'][ $key ] = $meta[ $key ];
3201
			}
3202
		}
3203
3204
		$id = get_post_thumbnail_id( $attachment->ID );
3205 View Code Duplication
		if ( ! empty( $id ) ) {
3206
			list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' );
3207
			$response['image'] = compact( 'src', 'width', 'height' );
3208
			list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumbnail' );
3209
			$response['thumb'] = compact( 'src', 'width', 'height' );
3210
		} else {
3211
			$src = wp_mime_type_icon( $attachment->ID );
3212
			$width = 48;
3213
			$height = 64;
3214
			$response['image'] = compact( 'src', 'width', 'height' );
3215
			$response['thumb'] = compact( 'src', 'width', 'height' );
3216
		}
3217
	}
3218
3219
	if ( function_exists('get_compat_media_markup') )
3220
		$response['compat'] = get_compat_media_markup( $attachment->ID, array( 'in_modal' => true ) );
3221
3222
	/**
3223
	 * Filters the attachment data prepared for JavaScript.
3224
	 *
3225
	 * @since 3.5.0
3226
	 *
3227
	 * @param array      $response   Array of prepared attachment data.
3228
	 * @param int|object $attachment Attachment ID or object.
3229
	 * @param array      $meta       Array of attachment meta data.
3230
	 */
3231
	return apply_filters( 'wp_prepare_attachment_for_js', $response, $attachment, $meta );
3232
}
3233
3234
/**
3235
 * Enqueues all scripts, styles, settings, and templates necessary to use
3236
 * all media JS APIs.
3237
 *
3238
 * @since 3.5.0
3239
 *
3240
 * @global int       $content_width
3241
 * @global wpdb      $wpdb
3242
 * @global WP_Locale $wp_locale
3243
 *
3244
 * @param array $args {
3245
 *     Arguments for enqueuing media scripts.
3246
 *
3247
 *     @type int|WP_Post A post object or ID.
3248
 * }
3249
 */
3250
function wp_enqueue_media( $args = array() ) {
3251
	// Enqueue me just once per page, please.
3252
	if ( did_action( 'wp_enqueue_media' ) )
3253
		return;
3254
3255
	global $content_width, $wpdb, $wp_locale;
3256
3257
	$defaults = array(
3258
		'post' => null,
3259
	);
3260
	$args = wp_parse_args( $args, $defaults );
3261
3262
	// We're going to pass the old thickbox media tabs to `media_upload_tabs`
3263
	// to ensure plugins will work. We will then unset those tabs.
3264
	$tabs = array(
3265
		// handler action suffix => tab label
3266
		'type'     => '',
3267
		'type_url' => '',
3268
		'gallery'  => '',
3269
		'library'  => '',
3270
	);
3271
3272
	/** This filter is documented in wp-admin/includes/media.php */
3273
	$tabs = apply_filters( 'media_upload_tabs', $tabs );
3274
	unset( $tabs['type'], $tabs['type_url'], $tabs['gallery'], $tabs['library'] );
3275
3276
	$props = array(
3277
		'link'  => get_option( 'image_default_link_type' ), // db default is 'file'
3278
		'align' => get_option( 'image_default_align' ), // empty default
3279
		'size'  => get_option( 'image_default_size' ),  // empty default
3280
	);
3281
3282
	$exts = array_merge( wp_get_audio_extensions(), wp_get_video_extensions() );
3283
	$mimes = get_allowed_mime_types();
3284
	$ext_mimes = array();
3285 View Code Duplication
	foreach ( $exts as $ext ) {
3286
		foreach ( $mimes as $ext_preg => $mime_match ) {
3287
			if ( preg_match( '#' . $ext . '#i', $ext_preg ) ) {
3288
				$ext_mimes[ $ext ] = $mime_match;
3289
				break;
3290
			}
3291
		}
3292
	}
3293
3294
	$has_audio = $wpdb->get_var( "
3295
		SELECT ID
3296
		FROM $wpdb->posts
3297
		WHERE post_type = 'attachment'
3298
		AND post_mime_type LIKE 'audio%'
3299
		LIMIT 1
3300
	" );
3301
	$has_video = $wpdb->get_var( "
3302
		SELECT ID
3303
		FROM $wpdb->posts
3304
		WHERE post_type = 'attachment'
3305
		AND post_mime_type LIKE 'video%'
3306
		LIMIT 1
3307
	" );
3308
	$months = $wpdb->get_results( $wpdb->prepare( "
3309
		SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
3310
		FROM $wpdb->posts
3311
		WHERE post_type = %s
3312
		ORDER BY post_date DESC
3313
	", 'attachment' ) );
3314
	foreach ( $months as $month_year ) {
3315
		$month_year->text = sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month_year->month ), $month_year->year );
3316
	}
3317
3318
	$settings = array(
3319
		'tabs'      => $tabs,
3320
		'tabUrl'    => add_query_arg( array( 'chromeless' => true ), admin_url('media-upload.php') ),
3321
		'mimeTypes' => wp_list_pluck( get_post_mime_types(), 0 ),
3322
		/** This filter is documented in wp-admin/includes/media.php */
3323
		'captions'  => ! apply_filters( 'disable_captions', '' ),
3324
		'nonce'     => array(
3325
			'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
3326
		),
3327
		'post'    => array(
3328
			'id' => 0,
3329
		),
3330
		'defaultProps' => $props,
3331
		'attachmentCounts' => array(
3332
			'audio' => ( $has_audio ) ? 1 : 0,
3333
			'video' => ( $has_video ) ? 1 : 0
3334
		),
3335
		'embedExts'    => $exts,
3336
		'embedMimes'   => $ext_mimes,
3337
		'contentWidth' => $content_width,
3338
		'months'       => $months,
3339
		'mediaTrash'   => MEDIA_TRASH ? 1 : 0
3340
	);
3341
3342
	$post = null;
3343
	if ( isset( $args['post'] ) ) {
3344
		$post = get_post( $args['post'] );
3345
		$settings['post'] = array(
3346
			'id' => $post->ID,
3347
			'nonce' => wp_create_nonce( 'update-post_' . $post->ID ),
3348
		);
3349
3350
		$thumbnail_support = current_theme_supports( 'post-thumbnails', $post->post_type ) && post_type_supports( $post->post_type, 'thumbnail' );
3351 View Code Duplication
		if ( ! $thumbnail_support && 'attachment' === $post->post_type && $post->post_mime_type ) {
3352
			if ( wp_attachment_is( 'audio', $post ) ) {
0 ignored issues
show
It seems like $post defined by get_post($args['post']) on line 3344 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...
3353
				$thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' );
3354
			} elseif ( wp_attachment_is( 'video', $post ) ) {
0 ignored issues
show
It seems like $post defined by get_post($args['post']) on line 3344 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...
3355
				$thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' );
3356
			}
3357
		}
3358
3359
		if ( $thumbnail_support ) {
3360
			$featured_image_id = get_post_meta( $post->ID, '_thumbnail_id', true );
3361
			$settings['post']['featuredImageId'] = $featured_image_id ? $featured_image_id : -1;
3362
		}
3363
	}
3364
3365
	if ( $post ) {
3366
		$post_type_object = get_post_type_object( $post->post_type );
3367
	} else {
3368
		$post_type_object = get_post_type_object( 'post' );
3369
	}
3370
3371
	$strings = array(
3372
		// Generic
3373
		'url'         => __( 'URL' ),
3374
		'addMedia'    => __( 'Add Media' ),
3375
		'search'      => __( 'Search' ),
3376
		'select'      => __( 'Select' ),
3377
		'cancel'      => __( 'Cancel' ),
3378
		'update'      => __( 'Update' ),
3379
		'replace'     => __( 'Replace' ),
3380
		'remove'      => __( 'Remove' ),
3381
		'back'        => __( 'Back' ),
3382
		/* translators: This is a would-be plural string used in the media manager.
3383
		   If there is not a word you can use in your language to avoid issues with the
3384
		   lack of plural support here, turn it into "selected: %d" then translate it.
3385
		 */
3386
		'selected'    => __( '%d selected' ),
3387
		'dragInfo'    => __( 'Drag and drop to reorder media files.' ),
3388
3389
		// Upload
3390
		'uploadFilesTitle'  => __( 'Upload Files' ),
3391
		'uploadImagesTitle' => __( 'Upload Images' ),
3392
3393
		// Library
3394
		'mediaLibraryTitle'      => __( 'Media Library' ),
3395
		'insertMediaTitle'       => __( 'Insert Media' ),
3396
		'createNewGallery'       => __( 'Create a new gallery' ),
3397
		'createNewPlaylist'      => __( 'Create a new playlist' ),
3398
		'createNewVideoPlaylist' => __( 'Create a new video playlist' ),
3399
		'returnToLibrary'        => __( '&#8592; Return to library' ),
3400
		'allMediaItems'          => __( 'All media items' ),
3401
		'allDates'               => __( 'All dates' ),
3402
		'noItemsFound'           => __( 'No items found.' ),
3403
		'insertIntoPost'         => $post_type_object->labels->insert_into_item,
3404
		'unattached'             => __( 'Unattached' ),
3405
		'trash'                  => _x( 'Trash', 'noun' ),
3406
		'uploadedToThisPost'     => $post_type_object->labels->uploaded_to_this_item,
3407
		'warnDelete'             => __( "You are about to permanently delete this item.\n  'Cancel' to stop, 'OK' to delete." ),
3408
		'warnBulkDelete'         => __( "You are about to permanently delete these items.\n  'Cancel' to stop, 'OK' to delete." ),
3409
		'warnBulkTrash'          => __( "You are about to trash these items.\n  'Cancel' to stop, 'OK' to delete." ),
3410
		'bulkSelect'             => __( 'Bulk Select' ),
3411
		'cancelSelection'        => __( 'Cancel Selection' ),
3412
		'trashSelected'          => __( 'Trash Selected' ),
3413
		'untrashSelected'        => __( 'Untrash Selected' ),
3414
		'deleteSelected'         => __( 'Delete Selected' ),
3415
		'deletePermanently'      => __( 'Delete Permanently' ),
3416
		'apply'                  => __( 'Apply' ),
3417
		'filterByDate'           => __( 'Filter by date' ),
3418
		'filterByType'           => __( 'Filter by type' ),
3419
		'searchMediaLabel'       => __( 'Search Media' ),
3420
		'noMedia'                => __( 'No media files found.' ),
3421
3422
		// Library Details
3423
		'attachmentDetails'  => __( 'Attachment Details' ),
3424
3425
		// From URL
3426
		'insertFromUrlTitle' => __( 'Insert from URL' ),
3427
3428
		// Featured Images
3429
		'setFeaturedImageTitle' => $post_type_object->labels->featured_image,
3430
		'setFeaturedImage'      => $post_type_object->labels->set_featured_image,
3431
3432
		// Gallery
3433
		'createGalleryTitle' => __( 'Create Gallery' ),
3434
		'editGalleryTitle'   => __( 'Edit Gallery' ),
3435
		'cancelGalleryTitle' => __( '&#8592; Cancel Gallery' ),
3436
		'insertGallery'      => __( 'Insert gallery' ),
3437
		'updateGallery'      => __( 'Update gallery' ),
3438
		'addToGallery'       => __( 'Add to gallery' ),
3439
		'addToGalleryTitle'  => __( 'Add to Gallery' ),
3440
		'reverseOrder'       => __( 'Reverse order' ),
3441
3442
		// Edit Image
3443
		'imageDetailsTitle'     => __( 'Image Details' ),
3444
		'imageReplaceTitle'     => __( 'Replace Image' ),
3445
		'imageDetailsCancel'    => __( 'Cancel Edit' ),
3446
		'editImage'             => __( 'Edit Image' ),
3447
3448
		// Crop Image
3449
		'chooseImage' => __( 'Choose Image' ),
3450
		'selectAndCrop' => __( 'Select and Crop' ),
3451
		'skipCropping' => __( 'Skip Cropping' ),
3452
		'cropImage' => __( 'Crop Image' ),
3453
		'cropYourImage' => __( 'Crop your image' ),
3454
		'cropping' => __( 'Cropping&hellip;' ),
3455
		'suggestedDimensions' => __( 'Suggested image dimensions:' ),
3456
		'cropError' => __( 'There has been an error cropping your image.' ),
3457
3458
		// Edit Audio
3459
		'audioDetailsTitle'     => __( 'Audio Details' ),
3460
		'audioReplaceTitle'     => __( 'Replace Audio' ),
3461
		'audioAddSourceTitle'   => __( 'Add Audio Source' ),
3462
		'audioDetailsCancel'    => __( 'Cancel Edit' ),
3463
3464
		// Edit Video
3465
		'videoDetailsTitle'     => __( 'Video Details' ),
3466
		'videoReplaceTitle'     => __( 'Replace Video' ),
3467
		'videoAddSourceTitle'   => __( 'Add Video Source' ),
3468
		'videoDetailsCancel'    => __( 'Cancel Edit' ),
3469
		'videoSelectPosterImageTitle' => __( 'Select Poster Image' ),
3470
		'videoAddTrackTitle'	=> __( 'Add Subtitles' ),
3471
3472
 		// Playlist
3473
 		'playlistDragInfo'    => __( 'Drag and drop to reorder tracks.' ),
3474
 		'createPlaylistTitle' => __( 'Create Audio Playlist' ),
3475
 		'editPlaylistTitle'   => __( 'Edit Audio Playlist' ),
3476
 		'cancelPlaylistTitle' => __( '&#8592; Cancel Audio Playlist' ),
3477
 		'insertPlaylist'      => __( 'Insert audio playlist' ),
3478
 		'updatePlaylist'      => __( 'Update audio playlist' ),
3479
 		'addToPlaylist'       => __( 'Add to audio playlist' ),
3480
 		'addToPlaylistTitle'  => __( 'Add to Audio Playlist' ),
3481
3482
 		// Video Playlist
3483
 		'videoPlaylistDragInfo'    => __( 'Drag and drop to reorder videos.' ),
3484
 		'createVideoPlaylistTitle' => __( 'Create Video Playlist' ),
3485
 		'editVideoPlaylistTitle'   => __( 'Edit Video Playlist' ),
3486
 		'cancelVideoPlaylistTitle' => __( '&#8592; Cancel Video Playlist' ),
3487
 		'insertVideoPlaylist'      => __( 'Insert video playlist' ),
3488
 		'updateVideoPlaylist'      => __( 'Update video playlist' ),
3489
 		'addToVideoPlaylist'       => __( 'Add to video playlist' ),
3490
 		'addToVideoPlaylistTitle'  => __( 'Add to Video Playlist' ),
3491
	);
3492
3493
	/**
3494
	 * Filters the media view settings.
3495
	 *
3496
	 * @since 3.5.0
3497
	 *
3498
	 * @param array   $settings List of media view settings.
3499
	 * @param WP_Post $post     Post object.
3500
	 */
3501
	$settings = apply_filters( 'media_view_settings', $settings, $post );
3502
3503
	/**
3504
	 * Filters the media view strings.
3505
	 *
3506
	 * @since 3.5.0
3507
	 *
3508
	 * @param array   $strings List of media view strings.
3509
	 * @param WP_Post $post    Post object.
3510
	 */
3511
	$strings = apply_filters( 'media_view_strings', $strings,  $post );
3512
3513
	$strings['settings'] = $settings;
3514
3515
	// Ensure we enqueue media-editor first, that way media-views is
3516
	// registered internally before we try to localize it. see #24724.
3517
	wp_enqueue_script( 'media-editor' );
3518
	wp_localize_script( 'media-views', '_wpMediaViewsL10n', $strings );
3519
3520
	wp_enqueue_script( 'media-audiovideo' );
3521
	wp_enqueue_style( 'media-views' );
3522
	if ( is_admin() ) {
3523
		wp_enqueue_script( 'mce-view' );
3524
		wp_enqueue_script( 'image-edit' );
3525
	}
3526
	wp_enqueue_style( 'imgareaselect' );
3527
	wp_plupload_default_settings();
3528
3529
	require_once ABSPATH . WPINC . '/media-template.php';
3530
	add_action( 'admin_footer', 'wp_print_media_templates' );
3531
	add_action( 'wp_footer', 'wp_print_media_templates' );
3532
	add_action( 'customize_controls_print_footer_scripts', 'wp_print_media_templates' );
3533
3534
	/**
3535
	 * Fires at the conclusion of wp_enqueue_media().
3536
	 *
3537
	 * @since 3.5.0
3538
	 */
3539
	do_action( 'wp_enqueue_media' );
3540
}
3541
3542
/**
3543
 * Retrieves media attached to the passed post.
3544
 *
3545
 * @since 3.6.0
3546
 *
3547
 * @param string      $type Mime type.
3548
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
3549
 * @return array Found attachments.
3550
 */
3551
function get_attached_media( $type, $post = 0 ) {
3552
	if ( ! $post = get_post( $post ) )
3553
		return array();
3554
3555
	$args = array(
3556
		'post_parent' => $post->ID,
3557
		'post_type' => 'attachment',
3558
		'post_mime_type' => $type,
3559
		'posts_per_page' => -1,
3560
		'orderby' => 'menu_order',
3561
		'order' => 'ASC',
3562
	);
3563
3564
	/**
3565
	 * Filters arguments used to retrieve media attached to the given post.
3566
	 *
3567
	 * @since 3.6.0
3568
	 *
3569
	 * @param array  $args Post query arguments.
3570
	 * @param string $type Mime type of the desired media.
3571
	 * @param mixed  $post Post ID or object.
3572
	 */
3573
	$args = apply_filters( 'get_attached_media_args', $args, $type, $post );
3574
3575
	$children = get_children( $args );
3576
3577
	/**
3578
	 * Filters the list of media attached to the given post.
3579
	 *
3580
	 * @since 3.6.0
3581
	 *
3582
	 * @param array  $children Associative array of media attached to the given post.
3583
	 * @param string $type     Mime type of the media desired.
3584
	 * @param mixed  $post     Post ID or object.
3585
	 */
3586
	return (array) apply_filters( 'get_attached_media', $children, $type, $post );
3587
}
3588
3589
/**
3590
 * Check the content blob for an audio, video, object, embed, or iframe tags.
3591
 *
3592
 * @since 3.6.0
3593
 *
3594
 * @param string $content A string which might contain media data.
3595
 * @param array  $types   An array of media types: 'audio', 'video', 'object', 'embed', or 'iframe'.
3596
 * @return array A list of found HTML media embeds.
3597
 */
3598
function get_media_embedded_in_content( $content, $types = null ) {
3599
	$html = array();
3600
3601
	/**
3602
	 * Filters the embedded media types that are allowed to be returned from the content blob.
3603
	 *
3604
	 * @since 4.2.0
3605
	 *
3606
	 * @param array $allowed_media_types An array of allowed media types. Default media types are
3607
	 *                                   'audio', 'video', 'object', 'embed', and 'iframe'.
3608
	 */
3609
	$allowed_media_types = apply_filters( 'media_embedded_in_content_allowed_types', array( 'audio', 'video', 'object', 'embed', 'iframe' ) );
3610
3611
	if ( ! empty( $types ) ) {
3612
		if ( ! is_array( $types ) ) {
3613
			$types = array( $types );
3614
		}
3615
3616
		$allowed_media_types = array_intersect( $allowed_media_types, $types );
3617
	}
3618
3619
	$tags = implode( '|', $allowed_media_types );
3620
3621
	if ( preg_match_all( '#<(?P<tag>' . $tags . ')[^<]*?(?:>[\s\S]*?<\/(?P=tag)>|\s*\/>)#', $content, $matches ) ) {
3622
		foreach ( $matches[0] as $match ) {
3623
			$html[] = $match;
3624
		}
3625
	}
3626
3627
	return $html;
3628
}
3629
3630
/**
3631
 * Retrieves galleries from the passed post's content.
3632
 *
3633
 * @since 3.6.0
3634
 *
3635
 * @param int|WP_Post $post Post ID or object.
3636
 * @param bool        $html Optional. Whether to return HTML or data in the array. Default true.
3637
 * @return array A list of arrays, each containing gallery data and srcs parsed
3638
 *               from the expanded shortcode.
3639
 */
3640
function get_post_galleries( $post, $html = true ) {
3641
	if ( ! $post = get_post( $post ) )
3642
		return array();
3643
3644
	if ( ! has_shortcode( $post->post_content, 'gallery' ) )
3645
		return array();
3646
3647
	$galleries = array();
3648
	if ( preg_match_all( '/' . get_shortcode_regex() . '/s', $post->post_content, $matches, PREG_SET_ORDER ) ) {
3649
		foreach ( $matches as $shortcode ) {
3650
			if ( 'gallery' === $shortcode[2] ) {
3651
				$srcs = array();
3652
3653
				$gallery = do_shortcode_tag( $shortcode );
3654
				if ( $html ) {
3655
					$galleries[] = $gallery;
3656
				} else {
3657
					preg_match_all( '#src=([\'"])(.+?)\1#is', $gallery, $src, PREG_SET_ORDER );
3658
					if ( ! empty( $src ) ) {
3659
						foreach ( $src as $s )
3660
							$srcs[] = $s[2];
3661
					}
3662
3663
					$data = shortcode_parse_atts( $shortcode[3] );
3664
					$data['src'] = array_values( array_unique( $srcs ) );
3665
					$galleries[] = $data;
3666
				}
3667
			}
3668
		}
3669
	}
3670
3671
	/**
3672
	 * Filters the list of all found galleries in the given post.
3673
	 *
3674
	 * @since 3.6.0
3675
	 *
3676
	 * @param array   $galleries Associative array of all found post galleries.
3677
	 * @param WP_Post $post      Post object.
3678
	 */
3679
	return apply_filters( 'get_post_galleries', $galleries, $post );
3680
}
3681
3682
/**
3683
 * Check a specified post's content for gallery and, if present, return the first
3684
 *
3685
 * @since 3.6.0
3686
 *
3687
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
3688
 * @param bool        $html Optional. Whether to return HTML or data. Default is true.
3689
 * @return string|array Gallery data and srcs parsed from the expanded shortcode.
3690
 */
3691
function get_post_gallery( $post = 0, $html = true ) {
3692
	$galleries = get_post_galleries( $post, $html );
3693
	$gallery = reset( $galleries );
3694
3695
	/**
3696
	 * Filters the first-found post gallery.
3697
	 *
3698
	 * @since 3.6.0
3699
	 *
3700
	 * @param array       $gallery   The first-found post gallery.
3701
	 * @param int|WP_Post $post      Post ID or object.
3702
	 * @param array       $galleries Associative array of all found post galleries.
3703
	 */
3704
	return apply_filters( 'get_post_gallery', $gallery, $post, $galleries );
3705
}
3706
3707
/**
3708
 * Retrieve the image srcs from galleries from a post's content, if present
3709
 *
3710
 * @since 3.6.0
3711
 *
3712
 * @see get_post_galleries()
3713
 *
3714
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global `$post`.
3715
 * @return array A list of lists, each containing image srcs parsed.
3716
 *               from an expanded shortcode
3717
 */
3718
function get_post_galleries_images( $post = 0 ) {
3719
	$galleries = get_post_galleries( $post, false );
3720
	return wp_list_pluck( $galleries, 'src' );
3721
}
3722
3723
/**
3724
 * Checks a post's content for galleries and return the image srcs for the first found gallery
3725
 *
3726
 * @since 3.6.0
3727
 *
3728
 * @see get_post_gallery()
3729
 *
3730
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global `$post`.
3731
 * @return array A list of a gallery's image srcs in order.
3732
 */
3733
function get_post_gallery_images( $post = 0 ) {
3734
	$gallery = get_post_gallery( $post, false );
3735
	return empty( $gallery['src'] ) ? array() : $gallery['src'];
3736
}
3737
3738
/**
3739
 * Maybe attempts to generate attachment metadata, if missing.
3740
 *
3741
 * @since 3.9.0
3742
 *
3743
 * @param WP_Post $attachment Attachment object.
3744
 */
3745
function wp_maybe_generate_attachment_metadata( $attachment ) {
3746
	if ( empty( $attachment ) || ( empty( $attachment->ID ) || ! $attachment_id = (int) $attachment->ID ) ) {
3747
		return;
3748
	}
3749
3750
	$file = get_attached_file( $attachment_id );
3751
	$meta = wp_get_attachment_metadata( $attachment_id );
3752
	if ( empty( $meta ) && file_exists( $file ) ) {
3753
		$_meta = get_post_meta( $attachment_id );
3754
		$regeneration_lock = 'wp_generating_att_' . $attachment_id;
3755
		if ( ! array_key_exists( '_wp_attachment_metadata', $_meta ) && ! get_transient( $regeneration_lock ) ) {
3756
			set_transient( $regeneration_lock, $file );
3757
			wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
0 ignored issues
show
It seems like $file defined by get_attached_file($attachment_id) on line 3750 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...
3758
			delete_transient( $regeneration_lock );
3759
		}
3760
	}
3761
}
3762
3763
/**
3764
 * Tries to convert an attachment URL into a post ID.
3765
 *
3766
 * @since 4.0.0
3767
 *
3768
 * @global wpdb $wpdb WordPress database abstraction object.
3769
 *
3770
 * @param string $url The URL to resolve.
3771
 * @return int The found post ID, or 0 on failure.
3772
 */
3773
function attachment_url_to_postid( $url ) {
3774
	global $wpdb;
3775
3776
	$dir = wp_get_upload_dir();
3777
	$path = $url;
3778
3779
	$site_url = parse_url( $dir['url'] );
3780
	$image_path = parse_url( $path );
3781
3782
	//force the protocols to match if needed
3783
	if ( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) {
3784
		$path = str_replace( $image_path['scheme'], $site_url['scheme'], $path );
3785
	}
3786
3787
	if ( 0 === strpos( $path, $dir['baseurl'] . '/' ) ) {
3788
		$path = substr( $path, strlen( $dir['baseurl'] . '/' ) );
3789
	}
3790
3791
	$sql = $wpdb->prepare(
3792
		"SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s",
3793
		$path
3794
	);
3795
	$post_id = $wpdb->get_var( $sql );
3796
3797
	/**
3798
	 * Filters an attachment id found by URL.
3799
	 *
3800
	 * @since 4.2.0
3801
	 *
3802
	 * @param int|null $post_id The post_id (if any) found by the function.
3803
	 * @param string   $url     The URL being looked up.
3804
	 */
3805
	return (int) apply_filters( 'attachment_url_to_postid', $post_id, $url );
3806
}
3807
3808
/**
3809
 * Returns the URLs for CSS files used in an iframe-sandbox'd TinyMCE media view.
3810
 *
3811
 * @since 4.0.0
3812
 *
3813
 * @global string $wp_version
3814
 *
3815
 * @return array The relevant CSS file URLs.
3816
 */
3817
function wpview_media_sandbox_styles() {
3818
 	$version = 'ver=' . $GLOBALS['wp_version'];
3819
 	$mediaelement = includes_url( "js/mediaelement/mediaelementplayer.min.css?$version" );
3820
 	$wpmediaelement = includes_url( "js/mediaelement/wp-mediaelement.css?$version" );
3821
3822
	return array( $mediaelement, $wpmediaelement );
3823
}
3824