changeset 21 | 48c4eec2b7e6 |
parent 19 | 3d72ae0968f4 |
child 22 | 8c2e4d02f4ef |
20:7b1b88e27a20 | 21:48c4eec2b7e6 |
---|---|
5 * @package WordPress |
5 * @package WordPress |
6 * @subpackage Media |
6 * @subpackage Media |
7 */ |
7 */ |
8 |
8 |
9 /** |
9 /** |
10 * Retrieve additional image sizes. |
10 * Retrieves additional image sizes. |
11 * |
11 * |
12 * @since 4.7.0 |
12 * @since 4.7.0 |
13 * |
13 * |
14 * @global array $_wp_additional_image_sizes |
14 * @global array $_wp_additional_image_sizes |
15 * |
15 * |
24 |
24 |
25 return $_wp_additional_image_sizes; |
25 return $_wp_additional_image_sizes; |
26 } |
26 } |
27 |
27 |
28 /** |
28 /** |
29 * Scale down the default size of an image. |
29 * Scales down the default size of an image. |
30 * |
30 * |
31 * This is so that the image is a better fit for the editor and theme. |
31 * This is so that the image is a better fit for the editor and theme. |
32 * |
32 * |
33 * The `$size` parameter accepts either an array or a string. The supported string |
33 * The `$size` parameter accepts either an array or a string. The supported string |
34 * values are 'thumb' or 'thumbnail' for the given thumbnail size or defaults at |
34 * values are 'thumb' or 'thumbnail' for the given thumbnail size or defaults at |
134 |
134 |
135 return wp_constrain_dimensions( $width, $height, $max_width, $max_height ); |
135 return wp_constrain_dimensions( $width, $height, $max_width, $max_height ); |
136 } |
136 } |
137 |
137 |
138 /** |
138 /** |
139 * Retrieve width and height attributes using given width and height values. |
139 * Retrieves width and height attributes using given width and height values. |
140 * |
140 * |
141 * Both attributes are required in the sense that both parameters must have a |
141 * Both attributes are required in the sense that both parameters must have a |
142 * value, but are optional in that if you set them to false or null, then they |
142 * value, but are optional in that if you set them to false or null, then they |
143 * will not be added to the returned string. |
143 * will not be added to the returned string. |
144 * |
144 * |
162 } |
162 } |
163 return $out; |
163 return $out; |
164 } |
164 } |
165 |
165 |
166 /** |
166 /** |
167 * Scale an image to fit a particular size (such as 'thumb' or 'medium'). |
167 * Scales an image to fit a particular size (such as 'thumb' or 'medium'). |
168 * |
168 * |
169 * The URL might be the original image, or it might be a resized version. This |
169 * The URL might be the original image, or it might be a resized version. This |
170 * function won't create a new resized copy, it will just return an already |
170 * function won't create a new resized copy, it will just return an already |
171 * resized one if it exists. |
171 * resized one if it exists. |
172 * |
172 * |
215 $width = 0; |
215 $width = 0; |
216 $height = 0; |
216 $height = 0; |
217 $is_intermediate = false; |
217 $is_intermediate = false; |
218 $img_url_basename = wp_basename( $img_url ); |
218 $img_url_basename = wp_basename( $img_url ); |
219 |
219 |
220 // If the file isn't an image, attempt to replace its URL with a rendered image from its meta. |
220 /* |
221 // Otherwise, a non-image type could be returned. |
221 * If the file isn't an image, attempt to replace its URL with a rendered image from its meta. |
222 * Otherwise, a non-image type could be returned. |
|
223 */ |
|
222 if ( ! $is_image ) { |
224 if ( ! $is_image ) { |
223 if ( ! empty( $meta['sizes']['full'] ) ) { |
225 if ( ! empty( $meta['sizes']['full'] ) ) { |
224 $img_url = str_replace( $img_url_basename, $meta['sizes']['full']['file'], $img_url ); |
226 $img_url = str_replace( $img_url_basename, $meta['sizes']['full']['file'], $img_url ); |
225 $img_url_basename = $meta['sizes']['full']['file']; |
227 $img_url_basename = $meta['sizes']['full']['file']; |
226 $width = $meta['sizes']['full']['width']; |
228 $width = $meta['sizes']['full']['width']; |
236 if ( $intermediate ) { |
238 if ( $intermediate ) { |
237 $img_url = str_replace( $img_url_basename, $intermediate['file'], $img_url ); |
239 $img_url = str_replace( $img_url_basename, $intermediate['file'], $img_url ); |
238 $width = $intermediate['width']; |
240 $width = $intermediate['width']; |
239 $height = $intermediate['height']; |
241 $height = $intermediate['height']; |
240 $is_intermediate = true; |
242 $is_intermediate = true; |
241 } elseif ( 'thumbnail' === $size ) { |
243 } elseif ( 'thumbnail' === $size && ! empty( $meta['thumb'] ) && is_string( $meta['thumb'] ) ) { |
242 // Fall back to the old thumbnail. |
244 // Fall back to the old thumbnail. |
243 $thumb_file = wp_get_attachment_thumb_file( $id ); |
245 $imagefile = get_attached_file( $id ); |
244 $info = null; |
246 $thumbfile = str_replace( wp_basename( $imagefile ), wp_basename( $meta['thumb'] ), $imagefile ); |
245 |
247 |
246 if ( $thumb_file ) { |
248 if ( file_exists( $thumbfile ) ) { |
247 $info = wp_getimagesize( $thumb_file ); |
249 $info = wp_getimagesize( $thumbfile ); |
248 } |
250 |
249 |
251 if ( $info ) { |
250 if ( $thumb_file && $info ) { |
252 $img_url = str_replace( $img_url_basename, wp_basename( $thumbfile ), $img_url ); |
251 $img_url = str_replace( $img_url_basename, wp_basename( $thumb_file ), $img_url ); |
253 $width = $info[0]; |
252 $width = $info[0]; |
254 $height = $info[1]; |
253 $height = $info[1]; |
255 $is_intermediate = true; |
254 $is_intermediate = true; |
256 } |
255 } |
257 } |
256 } |
258 } |
257 |
259 |
258 if ( ! $width && ! $height && isset( $meta['width'], $meta['height'] ) ) { |
260 if ( ! $width && ! $height && isset( $meta['width'], $meta['height'] ) ) { |
259 // Any other type: use the real image. |
261 // Any other type: use the real image. |
270 |
272 |
271 return false; |
273 return false; |
272 } |
274 } |
273 |
275 |
274 /** |
276 /** |
275 * Register a new image size. |
277 * Registers a new image size. |
276 * |
278 * |
277 * @since 2.9.0 |
279 * @since 2.9.0 |
278 * |
280 * |
279 * @global array $_wp_additional_image_sizes Associative array of additional image sizes. |
281 * @global array $_wp_additional_image_sizes Associative array of additional image sizes. |
280 * |
282 * |
281 * @param string $name Image size identifier. |
283 * @param string $name Image size identifier. |
282 * @param int $width Optional. Image width in pixels. Default 0. |
284 * @param int $width Optional. Image width in pixels. Default 0. |
283 * @param int $height Optional. Image height in pixels. Default 0. |
285 * @param int $height Optional. Image height in pixels. Default 0. |
284 * @param bool|array $crop Optional. Image cropping behavior. If false, the image will be scaled (default), |
286 * @param bool|array $crop { |
285 * If true, image will be cropped to the specified dimensions using center positions. |
287 * Optional. Image cropping behavior. If false, the image will be scaled (default). |
286 * If an array, the image will be cropped using the array to specify the crop location. |
288 * If true, image will be cropped to the specified dimensions using center positions. |
287 * Array values must be in the format: array( x_crop_position, y_crop_position ) where: |
289 * If an array, the image will be cropped using the array to specify the crop location: |
288 * - x_crop_position accepts: 'left', 'center', or 'right'. |
290 * |
289 * - y_crop_position accepts: 'top', 'center', or 'bottom'. |
291 * @type string $0 The x crop position. Accepts 'left' 'center', or 'right'. |
292 * @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'. |
|
293 * } |
|
290 */ |
294 */ |
291 function add_image_size( $name, $width = 0, $height = 0, $crop = false ) { |
295 function add_image_size( $name, $width = 0, $height = 0, $crop = false ) { |
292 global $_wp_additional_image_sizes; |
296 global $_wp_additional_image_sizes; |
293 |
297 |
294 $_wp_additional_image_sizes[ $name ] = array( |
298 $_wp_additional_image_sizes[ $name ] = array( |
297 'crop' => $crop, |
301 'crop' => $crop, |
298 ); |
302 ); |
299 } |
303 } |
300 |
304 |
301 /** |
305 /** |
302 * Check if an image size exists. |
306 * Checks if an image size exists. |
303 * |
307 * |
304 * @since 3.9.0 |
308 * @since 3.9.0 |
305 * |
309 * |
306 * @param string $name The image size to check. |
310 * @param string $name The image size to check. |
307 * @return bool True if the image size exists, false if not. |
311 * @return bool True if the image size exists, false if not. |
310 $sizes = wp_get_additional_image_sizes(); |
314 $sizes = wp_get_additional_image_sizes(); |
311 return isset( $sizes[ $name ] ); |
315 return isset( $sizes[ $name ] ); |
312 } |
316 } |
313 |
317 |
314 /** |
318 /** |
315 * Remove a new image size. |
319 * Removes a new image size. |
316 * |
320 * |
317 * @since 3.9.0 |
321 * @since 3.9.0 |
318 * |
322 * |
319 * @global array $_wp_additional_image_sizes |
323 * @global array $_wp_additional_image_sizes |
320 * |
324 * |
339 * |
343 * |
340 * @see add_image_size() for details on cropping behavior. |
344 * @see add_image_size() for details on cropping behavior. |
341 * |
345 * |
342 * @param int $width Image width in pixels. |
346 * @param int $width Image width in pixels. |
343 * @param int $height Image height in pixels. |
347 * @param int $height Image height in pixels. |
344 * @param bool|array $crop Optional. Whether to crop images to specified width and height or resize. |
348 * @param bool|array $crop { |
345 * An array can specify positioning of the crop area. Default false. |
349 * Optional. Image cropping behavior. If false, the image will be scaled (default). |
350 * If true, image will be cropped to the specified dimensions using center positions. |
|
351 * If an array, the image will be cropped using the array to specify the crop location: |
|
352 * |
|
353 * @type string $0 The x crop position. Accepts 'left' 'center', or 'right'. |
|
354 * @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'. |
|
355 * } |
|
346 */ |
356 */ |
347 function set_post_thumbnail_size( $width = 0, $height = 0, $crop = false ) { |
357 function set_post_thumbnail_size( $width = 0, $height = 0, $crop = false ) { |
348 add_image_size( 'post-thumbnail', $width, $height, $crop ); |
358 add_image_size( 'post-thumbnail', $width, $height, $crop ); |
349 } |
359 } |
350 |
360 |
366 * @param string $alt Image description for the alt attribute. |
376 * @param string $alt Image description for the alt attribute. |
367 * @param string $title Image description for the title attribute. |
377 * @param string $title Image description for the title attribute. |
368 * @param string $align Part of the class name for aligning the image. |
378 * @param string $align Part of the class name for aligning the image. |
369 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of |
379 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of |
370 * width and height values in pixels (in that order). Default 'medium'. |
380 * width and height values in pixels (in that order). Default 'medium'. |
371 * @return string HTML IMG element for given image attachment |
381 * @return string HTML IMG element for given image attachment. |
372 */ |
382 */ |
373 function get_image_tag( $id, $alt, $title, $align, $size = 'medium' ) { |
383 function get_image_tag( $id, $alt, $title, $align, $size = 'medium' ) { |
374 |
384 |
375 list( $img_src, $width, $height ) = image_downsize( $id, $size ); |
385 list( $img_src, $width, $height ) = image_downsize( $id, $size ); |
376 $hwstring = image_hwstring( $width, $height ); |
386 $hwstring = image_hwstring( $width, $height ); |
507 * Retrieves calculated resize dimensions for use in WP_Image_Editor. |
517 * Retrieves calculated resize dimensions for use in WP_Image_Editor. |
508 * |
518 * |
509 * Calculates dimensions and coordinates for a resized image that fits |
519 * Calculates dimensions and coordinates for a resized image that fits |
510 * within a specified width and height. |
520 * within a specified width and height. |
511 * |
521 * |
512 * Cropping behavior is dependent on the value of $crop: |
|
513 * 1. If false (default), images will not be cropped. |
|
514 * 2. If an array in the form of array( x_crop_position, y_crop_position ): |
|
515 * - x_crop_position accepts 'left' 'center', or 'right'. |
|
516 * - y_crop_position accepts 'top', 'center', or 'bottom'. |
|
517 * Images will be cropped to the specified dimensions within the defined crop area. |
|
518 * 3. If true, images will be cropped to the specified dimensions using center positions. |
|
519 * |
|
520 * @since 2.5.0 |
522 * @since 2.5.0 |
521 * |
523 * |
522 * @param int $orig_w Original width in pixels. |
524 * @param int $orig_w Original width in pixels. |
523 * @param int $orig_h Original height in pixels. |
525 * @param int $orig_h Original height in pixels. |
524 * @param int $dest_w New width in pixels. |
526 * @param int $dest_w New width in pixels. |
525 * @param int $dest_h New height in pixels. |
527 * @param int $dest_h New height in pixels. |
526 * @param bool|array $crop Optional. Whether to crop image to specified width and height or resize. |
528 * @param bool|array $crop { |
527 * An array can specify positioning of the crop area. Default false. |
529 * Optional. Image cropping behavior. If false, the image will be scaled (default). |
530 * If true, image will be cropped to the specified dimensions using center positions. |
|
531 * If an array, the image will be cropped using the array to specify the crop location: |
|
532 * |
|
533 * @type string $0 The x crop position. Accepts 'left' 'center', or 'right'. |
|
534 * @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'. |
|
535 * } |
|
528 * @return array|false Returned array matches parameters for `imagecopyresampled()`. False on failure. |
536 * @return array|false Returned array matches parameters for `imagecopyresampled()`. False on failure. |
529 */ |
537 */ |
530 function image_resize_dimensions( $orig_w, $orig_h, $dest_w, $dest_h, $crop = false ) { |
538 function image_resize_dimensions( $orig_w, $orig_h, $dest_w, $dest_h, $crop = false ) { |
531 |
539 |
532 if ( $orig_w <= 0 || $orig_h <= 0 ) { |
540 if ( $orig_w <= 0 || $orig_h <= 0 ) { |
650 if ( ! $proceed ) { |
658 if ( ! $proceed ) { |
651 return false; |
659 return false; |
652 } |
660 } |
653 } |
661 } |
654 |
662 |
655 // The return array matches the parameters to imagecopyresampled(). |
663 /* |
656 // int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h |
664 * The return array matches the parameters to imagecopyresampled(). |
665 * int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h |
|
666 */ |
|
657 return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h ); |
667 return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h ); |
658 } |
668 } |
659 |
669 |
660 /** |
670 /** |
661 * Resizes an image to make a thumbnail or intermediate size. |
671 * Resizes an image to make a thumbnail or intermediate size. |
664 * {@see 'image_make_intermediate_size'} filter can be used to hook in and change the |
674 * {@see 'image_make_intermediate_size'} filter can be used to hook in and change the |
665 * values of the returned array. The only parameter is the resized file path. |
675 * values of the returned array. The only parameter is the resized file path. |
666 * |
676 * |
667 * @since 2.5.0 |
677 * @since 2.5.0 |
668 * |
678 * |
669 * @param string $file File path. |
679 * @param string $file File path. |
670 * @param int $width Image width. |
680 * @param int $width Image width. |
671 * @param int $height Image height. |
681 * @param int $height Image height. |
672 * @param bool $crop Optional. Whether to crop image to specified width and height or resize. |
682 * @param bool|array $crop { |
673 * Default false. |
683 * Optional. Image cropping behavior. If false, the image will be scaled (default). |
684 * If true, image will be cropped to the specified dimensions using center positions. |
|
685 * If an array, the image will be cropped using the array to specify the crop location: |
|
686 * |
|
687 * @type string $0 The x crop position. Accepts 'left' 'center', or 'right'. |
|
688 * @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'. |
|
689 * } |
|
674 * @return array|false Metadata array on success. False if no image was created. |
690 * @return array|false Metadata array on success. False if no image was created. |
675 */ |
691 */ |
676 function image_make_intermediate_size( $file, $width, $height, $crop = false ) { |
692 function image_make_intermediate_size( $file, $width, $height, $crop = false ) { |
677 if ( $width || $height ) { |
693 if ( $width || $height ) { |
678 $editor = wp_get_image_editor( $file ); |
694 $editor = wp_get_image_editor( $file ); |
747 * of width and height values in pixels (in that order). Default 'thumbnail'. |
763 * of width and height values in pixels (in that order). Default 'thumbnail'. |
748 * @return array|false { |
764 * @return array|false { |
749 * Array of file relative path, width, and height on success. Additionally includes absolute |
765 * Array of file relative path, width, and height on success. Additionally includes absolute |
750 * path and URL if registered size is passed to `$size` parameter. False on failure. |
766 * path and URL if registered size is passed to `$size` parameter. False on failure. |
751 * |
767 * |
752 * @type string $file Path of image relative to uploads directory. |
768 * @type string $file Filename of image. |
753 * @type int $width Width of image in pixels. |
769 * @type int $width Width of image in pixels. |
754 * @type int $height Height of image in pixels. |
770 * @type int $height Height of image in pixels. |
755 * @type string $path Absolute filesystem path of image. |
771 * @type string $path Path of image relative to uploads directory. |
756 * @type string $url URL of image. |
772 * @type string $url URL of image. |
757 * } |
773 * } |
758 */ |
774 */ |
759 function image_get_intermediate_size( $post_id, $size = 'thumbnail' ) { |
775 function image_get_intermediate_size( $post_id, $size = 'thumbnail' ) { |
760 $imagedata = wp_get_attachment_metadata( $post_id ); |
776 $imagedata = wp_get_attachment_metadata( $post_id ); |
954 $image = image_downsize( $attachment_id, $size ); |
970 $image = image_downsize( $attachment_id, $size ); |
955 if ( ! $image ) { |
971 if ( ! $image ) { |
956 $src = false; |
972 $src = false; |
957 |
973 |
958 if ( $icon ) { |
974 if ( $icon ) { |
959 $src = wp_mime_type_icon( $attachment_id ); |
975 $src = wp_mime_type_icon( $attachment_id, '.svg' ); |
960 |
976 |
961 if ( $src ) { |
977 if ( $src ) { |
962 /** This filter is documented in wp-includes/post.php */ |
978 /** This filter is documented in wp-includes/post.php */ |
963 $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' ); |
979 $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' ); |
964 |
980 |
965 $src_file = $icon_dir . '/' . wp_basename( $src ); |
981 $src_file = $icon_dir . '/' . wp_basename( $src ); |
982 |
|
966 list( $width, $height ) = wp_getimagesize( $src_file ); |
983 list( $width, $height ) = wp_getimagesize( $src_file ); |
984 |
|
985 $ext = strtolower( substr( $src_file, -4 ) ); |
|
986 |
|
987 if ( '.svg' === $ext ) { |
|
988 // SVG does not have true dimensions, so this assigns width and height directly. |
|
989 $width = 48; |
|
990 $height = 64; |
|
991 } else { |
|
992 list( $width, $height ) = wp_getimagesize( $src_file ); |
|
993 } |
|
967 } |
994 } |
968 } |
995 } |
969 |
996 |
970 if ( $src && $width && $height ) { |
997 if ( $src && $width && $height ) { |
971 $image = array( $src, $width, $height, false ); |
998 $image = array( $src, $width, $height, false ); |
991 */ |
1018 */ |
992 return apply_filters( 'wp_get_attachment_image_src', $image, $attachment_id, $size, $icon ); |
1019 return apply_filters( 'wp_get_attachment_image_src', $image, $attachment_id, $size, $icon ); |
993 } |
1020 } |
994 |
1021 |
995 /** |
1022 /** |
996 * Get an HTML img element representing an image attachment. |
1023 * Gets an HTML img element representing an image attachment. |
997 * |
1024 * |
998 * While `$size` will accept an array, it is better to register a size with |
1025 * While `$size` will accept an array, it is better to register a size with |
999 * add_image_size() so that a cropped version is generated. It's much more |
1026 * add_image_size() so that a cropped version is generated. It's much more |
1000 * efficient than having to find the closest-sized image and then having the |
1027 * efficient than having to find the closest-sized image and then having the |
1001 * browser scale down the image. |
1028 * browser scale down the image. |
1002 * |
1029 * |
1003 * @since 2.5.0 |
1030 * @since 2.5.0 |
1004 * @since 4.4.0 The `$srcset` and `$sizes` attributes were added. |
1031 * @since 4.4.0 The `$srcset` and `$sizes` attributes were added. |
1005 * @since 5.5.0 The `$loading` attribute was added. |
1032 * @since 5.5.0 The `$loading` attribute was added. |
1033 * @since 6.1.0 The `$decoding` attribute was added. |
|
1006 * |
1034 * |
1007 * @param int $attachment_id Image attachment ID. |
1035 * @param int $attachment_id Image attachment ID. |
1008 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array |
1036 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array |
1009 * of width and height values in pixels (in that order). Default 'thumbnail'. |
1037 * of width and height values in pixels (in that order). Default 'thumbnail'. |
1010 * @param bool $icon Optional. Whether the image should be treated as an icon. Default false. |
1038 * @param bool $icon Optional. Whether the image should be treated as an icon. Default false. |
1011 * @param string|array $attr { |
1039 * @param string|array $attr { |
1012 * Optional. Attributes for the image markup. |
1040 * Optional. Attributes for the image markup. |
1013 * |
1041 * |
1014 * @type string $src Image attachment URL. |
1042 * @type string $src Image attachment URL. |
1015 * @type string $class CSS class name or space-separated list of classes. |
1043 * @type string $class CSS class name or space-separated list of classes. |
1016 * Default `attachment-$size_class size-$size_class`, |
1044 * Default `attachment-$size_class size-$size_class`, |
1017 * where `$size_class` is the image size being requested. |
1045 * where `$size_class` is the image size being requested. |
1018 * @type string $alt Image description for the alt attribute. |
1046 * @type string $alt Image description for the alt attribute. |
1019 * @type string $srcset The 'srcset' attribute value. |
1047 * @type string $srcset The 'srcset' attribute value. |
1020 * @type string $sizes The 'sizes' attribute value. |
1048 * @type string $sizes The 'sizes' attribute value. |
1021 * @type string|false $loading The 'loading' attribute value. Passing a value of false |
1049 * @type string|false $loading The 'loading' attribute value. Passing a value of false |
1022 * will result in the attribute being omitted for the image. |
1050 * will result in the attribute being omitted for the image. |
1023 * Defaults to 'lazy', depending on wp_lazy_loading_enabled(). |
1051 * Default determined by {@see wp_get_loading_optimization_attributes()}. |
1052 * @type string $decoding The 'decoding' attribute value. Possible values are |
|
1053 * 'async' (default), 'sync', or 'auto'. Passing false or an empty |
|
1054 * string will result in the attribute being omitted. |
|
1055 * @type string $fetchpriority The 'fetchpriority' attribute value, whether `high`, `low`, or `auto`. |
|
1056 * Default determined by {@see wp_get_loading_optimization_attributes()}. |
|
1024 * } |
1057 * } |
1025 * @return string HTML img element or empty string on failure. |
1058 * @return string HTML img element or empty string on failure. |
1026 */ |
1059 */ |
1027 function wp_get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = false, $attr = '' ) { |
1060 function wp_get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = false, $attr = '' ) { |
1028 $html = ''; |
1061 $html = ''; |
1043 'src' => $src, |
1076 'src' => $src, |
1044 'class' => "attachment-$size_class size-$size_class", |
1077 'class' => "attachment-$size_class size-$size_class", |
1045 'alt' => trim( strip_tags( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) ), |
1078 'alt' => trim( strip_tags( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) ), |
1046 ); |
1079 ); |
1047 |
1080 |
1048 // Add `loading` attribute. |
1081 /** |
1049 if ( wp_lazy_loading_enabled( 'img', 'wp_get_attachment_image' ) ) { |
1082 * Filters the context in which wp_get_attachment_image() is used. |
1050 $default_attr['loading'] = wp_get_loading_attr_default( 'wp_get_attachment_image' ); |
1083 * |
1051 } |
1084 * @since 6.3.0 |
1052 |
1085 * |
1053 $attr = wp_parse_args( $attr, $default_attr ); |
1086 * @param string $context The context. Default 'wp_get_attachment_image'. |
1054 |
1087 */ |
1055 // If the default value of `lazy` for the `loading` attribute is overridden |
1088 $context = apply_filters( 'wp_get_attachment_image_context', 'wp_get_attachment_image' ); |
1056 // to omit the attribute for this image, ensure it is not included. |
1089 $attr = wp_parse_args( $attr, $default_attr ); |
1057 if ( array_key_exists( 'loading', $attr ) && ! $attr['loading'] ) { |
1090 |
1091 $loading_attr = $attr; |
|
1092 $loading_attr['width'] = $width; |
|
1093 $loading_attr['height'] = $height; |
|
1094 $loading_optimization_attr = wp_get_loading_optimization_attributes( |
|
1095 'img', |
|
1096 $loading_attr, |
|
1097 $context |
|
1098 ); |
|
1099 |
|
1100 // Add loading optimization attributes if not available. |
|
1101 $attr = array_merge( $attr, $loading_optimization_attr ); |
|
1102 |
|
1103 // Omit the `decoding` attribute if the value is invalid according to the spec. |
|
1104 if ( empty( $attr['decoding'] ) || ! in_array( $attr['decoding'], array( 'async', 'sync', 'auto' ), true ) ) { |
|
1105 unset( $attr['decoding'] ); |
|
1106 } |
|
1107 |
|
1108 /* |
|
1109 * If the default value of `lazy` for the `loading` attribute is overridden |
|
1110 * to omit the attribute for this image, ensure it is not included. |
|
1111 */ |
|
1112 if ( isset( $attr['loading'] ) && ! $attr['loading'] ) { |
|
1058 unset( $attr['loading'] ); |
1113 unset( $attr['loading'] ); |
1114 } |
|
1115 |
|
1116 // If the `fetchpriority` attribute is overridden and set to false or an empty string. |
|
1117 if ( isset( $attr['fetchpriority'] ) && ! $attr['fetchpriority'] ) { |
|
1118 unset( $attr['fetchpriority'] ); |
|
1059 } |
1119 } |
1060 |
1120 |
1061 // Generate 'srcset' and 'sizes' if not already present. |
1121 // Generate 'srcset' and 'sizes' if not already present. |
1062 if ( empty( $attr['srcset'] ) ) { |
1122 if ( empty( $attr['srcset'] ) ) { |
1063 $image_meta = wp_get_attachment_metadata( $attachment_id ); |
1123 $image_meta = wp_get_attachment_metadata( $attachment_id ); |
1099 |
1159 |
1100 $html .= ' />'; |
1160 $html .= ' />'; |
1101 } |
1161 } |
1102 |
1162 |
1103 /** |
1163 /** |
1104 * HTML img element representing an image attachment. |
1164 * Filters the HTML img element representing an image attachment. |
1105 * |
1165 * |
1106 * @since 5.6.0 |
1166 * @since 5.6.0 |
1107 * |
1167 * |
1108 * @param string $html HTML img element or empty string on failure. |
1168 * @param string $html HTML img element or empty string on failure. |
1109 * @param int $attachment_id Image attachment ID. |
1169 * @param int $attachment_id Image attachment ID. |
1115 */ |
1175 */ |
1116 return apply_filters( 'wp_get_attachment_image', $html, $attachment_id, $size, $icon, $attr ); |
1176 return apply_filters( 'wp_get_attachment_image', $html, $attachment_id, $size, $icon, $attr ); |
1117 } |
1177 } |
1118 |
1178 |
1119 /** |
1179 /** |
1120 * Get the URL of an image attachment. |
1180 * Gets the URL of an image attachment. |
1121 * |
1181 * |
1122 * @since 4.4.0 |
1182 * @since 4.4.0 |
1123 * |
1183 * |
1124 * @param int $attachment_id Image attachment ID. |
1184 * @param int $attachment_id Image attachment ID. |
1125 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of |
1185 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of |
1132 $image = wp_get_attachment_image_src( $attachment_id, $size, $icon ); |
1192 $image = wp_get_attachment_image_src( $attachment_id, $size, $icon ); |
1133 return isset( $image[0] ) ? $image[0] : false; |
1193 return isset( $image[0] ) ? $image[0] : false; |
1134 } |
1194 } |
1135 |
1195 |
1136 /** |
1196 /** |
1137 * Get the attachment path relative to the upload directory. |
1197 * Gets the attachment path relative to the upload directory. |
1138 * |
1198 * |
1139 * @since 4.4.1 |
1199 * @since 4.4.1 |
1140 * @access private |
1200 * @access private |
1141 * |
1201 * |
1142 * @param string $file Attachment file name. |
1202 * @param string $file Attachment file name. |
1147 |
1207 |
1148 if ( '.' === $dirname ) { |
1208 if ( '.' === $dirname ) { |
1149 return ''; |
1209 return ''; |
1150 } |
1210 } |
1151 |
1211 |
1152 if ( false !== strpos( $dirname, 'wp-content/uploads' ) ) { |
1212 if ( str_contains( $dirname, 'wp-content/uploads' ) ) { |
1153 // Get the directory name relative to the upload directory (back compat for pre-2.7 uploads). |
1213 // Get the directory name relative to the upload directory (back compat for pre-2.7 uploads). |
1154 $dirname = substr( $dirname, strpos( $dirname, 'wp-content/uploads' ) + 18 ); |
1214 $dirname = substr( $dirname, strpos( $dirname, 'wp-content/uploads' ) + 18 ); |
1155 $dirname = ltrim( $dirname, '/' ); |
1215 $dirname = ltrim( $dirname, '/' ); |
1156 } |
1216 } |
1157 |
1217 |
1158 return $dirname; |
1218 return $dirname; |
1159 } |
1219 } |
1160 |
1220 |
1161 /** |
1221 /** |
1162 * Get the image size as array from its meta data. |
1222 * Gets the image size as array from its meta data. |
1163 * |
1223 * |
1164 * Used for responsive images. |
1224 * Used for responsive images. |
1165 * |
1225 * |
1166 * @since 4.4.0 |
1226 * @since 4.4.0 |
1167 * @access private |
1227 * @access private |
1199 * @see wp_calculate_image_srcset() |
1259 * @see wp_calculate_image_srcset() |
1200 * |
1260 * |
1201 * @param int $attachment_id Image attachment ID. |
1261 * @param int $attachment_id Image attachment ID. |
1202 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of |
1262 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of |
1203 * width and height values in pixels (in that order). Default 'medium'. |
1263 * width and height values in pixels (in that order). Default 'medium'. |
1204 * @param array $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'. |
1264 * @param array|null $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'. |
1205 * Default null. |
1265 * Default null. |
1206 * @return string|false A 'srcset' value string or false. |
1266 * @return string|false A 'srcset' value string or false. |
1207 */ |
1267 */ |
1208 function wp_get_attachment_image_srcset( $attachment_id, $size = 'medium', $image_meta = null ) { |
1268 function wp_get_attachment_image_srcset( $attachment_id, $size = 'medium', $image_meta = null ) { |
1209 $image = wp_get_attachment_image_src( $attachment_id, $size ); |
1269 $image = wp_get_attachment_image_src( $attachment_id, $size ); |
1241 * @param int $attachment_id Optional. The image attachment ID. Default 0. |
1301 * @param int $attachment_id Optional. The image attachment ID. Default 0. |
1242 * @return string|false The 'srcset' attribute value. False on error or when only one source exists. |
1302 * @return string|false The 'srcset' attribute value. False on error or when only one source exists. |
1243 */ |
1303 */ |
1244 function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 ) { |
1304 function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 ) { |
1245 /** |
1305 /** |
1246 * Let plugins pre-filter the image meta to be able to fix inconsistencies in the stored data. |
1306 * Pre-filters the image meta to be able to fix inconsistencies in the stored data. |
1247 * |
1307 * |
1248 * @since 4.5.0 |
1308 * @since 4.5.0 |
1249 * |
1309 * |
1250 * @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'. |
1310 * @param array $image_meta The image meta data as returned by 'wp_get_attachment_metadata()'. |
1251 * @param int[] $size_array { |
1311 * @param int[] $size_array { |
1285 $image_sizes[] = array( |
1345 $image_sizes[] = array( |
1286 'width' => $image_meta['width'], |
1346 'width' => $image_meta['width'], |
1287 'height' => $image_meta['height'], |
1347 'height' => $image_meta['height'], |
1288 'file' => $image_basename, |
1348 'file' => $image_basename, |
1289 ); |
1349 ); |
1290 } elseif ( strpos( $image_src, $image_meta['file'] ) ) { |
1350 } elseif ( str_contains( $image_src, $image_meta['file'] ) ) { |
1291 return false; |
1351 return false; |
1292 } |
1352 } |
1293 |
1353 |
1294 // Retrieve the uploads sub-directory from the full size image. |
1354 // Retrieve the uploads sub-directory from the full size image. |
1295 $dirname = _wp_get_attachment_relative_path( $image_meta['file'] ); |
1355 $dirname = _wp_get_attachment_relative_path( $image_meta['file'] ); |
1303 |
1363 |
1304 /* |
1364 /* |
1305 * If currently on HTTPS, prefer HTTPS URLs when we know they're supported by the domain |
1365 * If currently on HTTPS, prefer HTTPS URLs when we know they're supported by the domain |
1306 * (which is to say, when they share the domain name of the current request). |
1366 * (which is to say, when they share the domain name of the current request). |
1307 */ |
1367 */ |
1308 if ( is_ssl() && 'https' !== substr( $image_baseurl, 0, 5 ) && parse_url( $image_baseurl, PHP_URL_HOST ) === $_SERVER['HTTP_HOST'] ) { |
1368 if ( is_ssl() && ! str_starts_with( $image_baseurl, 'https' ) ) { |
1309 $image_baseurl = set_url_scheme( $image_baseurl, 'https' ); |
1369 /* |
1370 * Since the `Host:` header might contain a port, it should |
|
1371 * be compared against the image URL using the same port. |
|
1372 */ |
|
1373 $parsed = parse_url( $image_baseurl ); |
|
1374 $domain = isset( $parsed['host'] ) ? $parsed['host'] : ''; |
|
1375 |
|
1376 if ( isset( $parsed['port'] ) ) { |
|
1377 $domain .= ':' . $parsed['port']; |
|
1378 } |
|
1379 |
|
1380 if ( $_SERVER['HTTP_HOST'] === $domain ) { |
|
1381 $image_baseurl = set_url_scheme( $image_baseurl, 'https' ); |
|
1382 } |
|
1310 } |
1383 } |
1311 |
1384 |
1312 /* |
1385 /* |
1313 * Images that have been edited in WordPress after being uploaded will |
1386 * Images that have been edited in WordPress after being uploaded will |
1314 * contain a unique hash. Look for that hash and use it later to filter |
1387 * contain a unique hash. Look for that hash and use it later to filter |
1352 if ( ! is_array( $image ) ) { |
1425 if ( ! is_array( $image ) ) { |
1353 continue; |
1426 continue; |
1354 } |
1427 } |
1355 |
1428 |
1356 // If the file name is part of the `src`, we've confirmed a match. |
1429 // If the file name is part of the `src`, we've confirmed a match. |
1357 if ( ! $src_matched && false !== strpos( $image_src, $dirname . $image['file'] ) ) { |
1430 if ( ! $src_matched && str_contains( $image_src, $dirname . $image['file'] ) ) { |
1358 $src_matched = true; |
1431 $src_matched = true; |
1359 $is_src = true; |
1432 $is_src = true; |
1360 } |
1433 } |
1361 |
1434 |
1362 // Filter out images that are from previous edits. |
1435 // Filter out images that are from previous edits. |
1440 * @see wp_calculate_image_sizes() |
1513 * @see wp_calculate_image_sizes() |
1441 * |
1514 * |
1442 * @param int $attachment_id Image attachment ID. |
1515 * @param int $attachment_id Image attachment ID. |
1443 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of |
1516 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of |
1444 * width and height values in pixels (in that order). Default 'medium'. |
1517 * width and height values in pixels (in that order). Default 'medium'. |
1445 * @param array $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'. |
1518 * @param array|null $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'. |
1446 * Default null. |
1519 * Default null. |
1447 * @return string|false A valid source size value for use in a 'sizes' attribute or false. |
1520 * @return string|false A valid source size value for use in a 'sizes' attribute or false. |
1448 */ |
1521 */ |
1449 function wp_get_attachment_image_sizes( $attachment_id, $size = 'medium', $image_meta = null ) { |
1522 function wp_get_attachment_image_sizes( $attachment_id, $size = 'medium', $image_meta = null ) { |
1450 $image = wp_get_attachment_image_src( $attachment_id, $size ); |
1523 $image = wp_get_attachment_image_src( $attachment_id, $size ); |
1471 * |
1544 * |
1472 * @since 4.4.0 |
1545 * @since 4.4.0 |
1473 * |
1546 * |
1474 * @param string|int[] $size Image size. Accepts any registered image size name, or an array of |
1547 * @param string|int[] $size Image size. Accepts any registered image size name, or an array of |
1475 * width and height values in pixels (in that order). |
1548 * width and height values in pixels (in that order). |
1476 * @param string $image_src Optional. The URL to the image file. Default null. |
1549 * @param string|null $image_src Optional. The URL to the image file. Default null. |
1477 * @param array $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'. |
1550 * @param array|null $image_meta Optional. The image meta data as returned by 'wp_get_attachment_metadata()'. |
1478 * Default null. |
1551 * Default null. |
1479 * @param int $attachment_id Optional. Image attachment ID. Either `$image_meta` or `$attachment_id` |
1552 * @param int $attachment_id Optional. Image attachment ID. Either `$image_meta` or `$attachment_id` |
1480 * is needed when using the image size name as argument for `$size`. Default 0. |
1553 * is needed when using the image size name as argument for `$size`. Default 0. |
1481 * @return string|false A valid source size value for use in a 'sizes' attribute or false. |
1554 * @return string|false A valid source size value for use in a 'sizes' attribute or false. |
1482 */ |
1555 */ |
1538 function wp_image_file_matches_image_meta( $image_location, $image_meta, $attachment_id = 0 ) { |
1611 function wp_image_file_matches_image_meta( $image_location, $image_meta, $attachment_id = 0 ) { |
1539 $match = false; |
1612 $match = false; |
1540 |
1613 |
1541 // Ensure the $image_meta is valid. |
1614 // Ensure the $image_meta is valid. |
1542 if ( isset( $image_meta['file'] ) && strlen( $image_meta['file'] ) > 4 ) { |
1615 if ( isset( $image_meta['file'] ) && strlen( $image_meta['file'] ) > 4 ) { |
1543 // Remove quiery args if image URI. |
1616 // Remove query args in image URI. |
1544 list( $image_location ) = explode( '?', $image_location ); |
1617 list( $image_location ) = explode( '?', $image_location ); |
1545 |
1618 |
1546 // Check if the relative image path from the image meta is at the end of $image_location. |
1619 // Check if the relative image path from the image meta is at the end of $image_location. |
1547 if ( strrpos( $image_location, $image_meta['file'] ) === strlen( $image_location ) - strlen( $image_meta['file'] ) ) { |
1620 if ( strrpos( $image_location, $image_meta['file'] ) === strlen( $image_location ) - strlen( $image_meta['file'] ) ) { |
1548 $match = true; |
1621 $match = true; |
1604 $dimensions = false; |
1677 $dimensions = false; |
1605 |
1678 |
1606 // Is it a full size image? |
1679 // Is it a full size image? |
1607 if ( |
1680 if ( |
1608 isset( $image_meta['file'] ) && |
1681 isset( $image_meta['file'] ) && |
1609 strpos( $image_src, wp_basename( $image_meta['file'] ) ) !== false |
1682 str_contains( $image_src, wp_basename( $image_meta['file'] ) ) |
1610 ) { |
1683 ) { |
1611 $dimensions = array( |
1684 $dimensions = array( |
1612 (int) $image_meta['width'], |
1685 (int) $image_meta['width'], |
1613 (int) $image_meta['height'], |
1686 (int) $image_meta['height'], |
1614 ); |
1687 ); |
1671 if ( ! $image_src ) { |
1744 if ( ! $image_src ) { |
1672 return $image; |
1745 return $image; |
1673 } |
1746 } |
1674 |
1747 |
1675 // Bail early if an image has been inserted and later edited. |
1748 // Bail early if an image has been inserted and later edited. |
1676 if ( preg_match( '/-e[0-9]{13}/', $image_meta['file'], $img_edit_hash ) && |
1749 if ( preg_match( '/-e[0-9]{13}/', $image_meta['file'], $img_edit_hash ) |
1677 strpos( wp_basename( $image_src ), $img_edit_hash[0] ) === false ) { |
1750 && ! str_contains( wp_basename( $image_src ), $img_edit_hash[0] ) |
1678 |
1751 ) { |
1679 return $image; |
1752 return $image; |
1680 } |
1753 } |
1681 |
1754 |
1682 $width = preg_match( '/ width="([0-9]+)"/', $image, $match_width ) ? (int) $match_width[1] : 0; |
1755 $width = preg_match( '/ width="([0-9]+)"/', $image, $match_width ) ? (int) $match_width[1] : 0; |
1683 $height = preg_match( '/ height="([0-9]+)"/', $image, $match_height ) ? (int) $match_height[1] : 0; |
1756 $height = preg_match( '/ height="([0-9]+)"/', $image, $match_height ) ? (int) $match_height[1] : 0; |
1727 * @param string $context Additional context, like the current filter name |
1800 * @param string $context Additional context, like the current filter name |
1728 * or the function name from where this was called. |
1801 * or the function name from where this was called. |
1729 * @return bool Whether to add the attribute. |
1802 * @return bool Whether to add the attribute. |
1730 */ |
1803 */ |
1731 function wp_lazy_loading_enabled( $tag_name, $context ) { |
1804 function wp_lazy_loading_enabled( $tag_name, $context ) { |
1732 // By default add to all 'img' and 'iframe' tags. |
1805 /* |
1733 // See https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-loading |
1806 * By default add to all 'img' and 'iframe' tags. |
1734 // See https://html.spec.whatwg.org/multipage/iframe-embed-object.html#attr-iframe-loading |
1807 * See https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-loading |
1808 * See https://html.spec.whatwg.org/multipage/iframe-embed-object.html#attr-iframe-loading |
|
1809 */ |
|
1735 $default = ( 'img' === $tag_name || 'iframe' === $tag_name ); |
1810 $default = ( 'img' === $tag_name || 'iframe' === $tag_name ); |
1736 |
1811 |
1737 /** |
1812 /** |
1738 * Filters whether to add the `loading` attribute to the specified tag in the specified context. |
1813 * Filters whether to add the `loading` attribute to the specified tag in the specified context. |
1739 * |
1814 * |
1759 * @since 5.5.0 |
1834 * @since 5.5.0 |
1760 * @since 5.7.0 Now supports adding `loading` attributes to `iframe` tags. |
1835 * @since 5.7.0 Now supports adding `loading` attributes to `iframe` tags. |
1761 * |
1836 * |
1762 * @see wp_img_tag_add_width_and_height_attr() |
1837 * @see wp_img_tag_add_width_and_height_attr() |
1763 * @see wp_img_tag_add_srcset_and_sizes_attr() |
1838 * @see wp_img_tag_add_srcset_and_sizes_attr() |
1764 * @see wp_img_tag_add_loading_attr() |
1839 * @see wp_img_tag_add_loading_optimization_attrs() |
1765 * @see wp_iframe_tag_add_loading_attr() |
1840 * @see wp_iframe_tag_add_loading_attr() |
1766 * |
1841 * |
1767 * @param string $content The HTML content to be filtered. |
1842 * @param string $content The HTML content to be filtered. |
1768 * @param string $context Optional. Additional context to pass to the filters. |
1843 * @param string $context Optional. Additional context to pass to the filters. |
1769 * Defaults to `current_filter()` when not set. |
1844 * Defaults to `current_filter()` when not set. |
1772 function wp_filter_content_tags( $content, $context = null ) { |
1847 function wp_filter_content_tags( $content, $context = null ) { |
1773 if ( null === $context ) { |
1848 if ( null === $context ) { |
1774 $context = current_filter(); |
1849 $context = current_filter(); |
1775 } |
1850 } |
1776 |
1851 |
1777 $add_img_loading_attr = wp_lazy_loading_enabled( 'img', $context ); |
|
1778 $add_iframe_loading_attr = wp_lazy_loading_enabled( 'iframe', $context ); |
1852 $add_iframe_loading_attr = wp_lazy_loading_enabled( 'iframe', $context ); |
1779 |
1853 |
1780 if ( ! preg_match_all( '/<(img|iframe)\s[^>]+>/', $content, $matches, PREG_SET_ORDER ) ) { |
1854 if ( ! preg_match_all( '/<(img|iframe)\s[^>]+>/', $content, $matches, PREG_SET_ORDER ) ) { |
1781 return $content; |
1855 return $content; |
1782 } |
1856 } |
1794 case 'img': |
1868 case 'img': |
1795 if ( preg_match( '/wp-image-([0-9]+)/i', $tag, $class_id ) ) { |
1869 if ( preg_match( '/wp-image-([0-9]+)/i', $tag, $class_id ) ) { |
1796 $attachment_id = absint( $class_id[1] ); |
1870 $attachment_id = absint( $class_id[1] ); |
1797 |
1871 |
1798 if ( $attachment_id ) { |
1872 if ( $attachment_id ) { |
1799 // If exactly the same image tag is used more than once, overwrite it. |
1873 /* |
1800 // All identical tags will be replaced later with 'str_replace()'. |
1874 * If exactly the same image tag is used more than once, overwrite it. |
1875 * All identical tags will be replaced later with 'str_replace()'. |
|
1876 */ |
|
1801 $images[ $tag ] = $attachment_id; |
1877 $images[ $tag ] = $attachment_id; |
1802 break; |
1878 break; |
1803 } |
1879 } |
1804 } |
1880 } |
1805 $images[ $tag ] = 0; |
1881 $images[ $tag ] = 0; |
1827 if ( isset( $images[ $match[0] ] ) ) { |
1903 if ( isset( $images[ $match[0] ] ) ) { |
1828 $filtered_image = $match[0]; |
1904 $filtered_image = $match[0]; |
1829 $attachment_id = $images[ $match[0] ]; |
1905 $attachment_id = $images[ $match[0] ]; |
1830 |
1906 |
1831 // Add 'width' and 'height' attributes if applicable. |
1907 // Add 'width' and 'height' attributes if applicable. |
1832 if ( $attachment_id > 0 && false === strpos( $filtered_image, ' width=' ) && false === strpos( $filtered_image, ' height=' ) ) { |
1908 if ( $attachment_id > 0 && ! str_contains( $filtered_image, ' width=' ) && ! str_contains( $filtered_image, ' height=' ) ) { |
1833 $filtered_image = wp_img_tag_add_width_and_height_attr( $filtered_image, $context, $attachment_id ); |
1909 $filtered_image = wp_img_tag_add_width_and_height_attr( $filtered_image, $context, $attachment_id ); |
1834 } |
1910 } |
1835 |
1911 |
1836 // Add 'srcset' and 'sizes' attributes if applicable. |
1912 // Add 'srcset' and 'sizes' attributes if applicable. |
1837 if ( $attachment_id > 0 && false === strpos( $filtered_image, ' srcset=' ) ) { |
1913 if ( $attachment_id > 0 && ! str_contains( $filtered_image, ' srcset=' ) ) { |
1838 $filtered_image = wp_img_tag_add_srcset_and_sizes_attr( $filtered_image, $context, $attachment_id ); |
1914 $filtered_image = wp_img_tag_add_srcset_and_sizes_attr( $filtered_image, $context, $attachment_id ); |
1839 } |
1915 } |
1840 |
1916 |
1841 // Add 'loading' attribute if applicable. |
1917 // Add loading optimization attributes if applicable. |
1842 if ( $add_img_loading_attr && false === strpos( $filtered_image, ' loading=' ) ) { |
1918 $filtered_image = wp_img_tag_add_loading_optimization_attrs( $filtered_image, $context ); |
1843 $filtered_image = wp_img_tag_add_loading_attr( $filtered_image, $context ); |
|
1844 } |
|
1845 |
1919 |
1846 /** |
1920 /** |
1847 * Filters an img tag within the content for a given context. |
1921 * Filters an img tag within the content for a given context. |
1848 * |
1922 * |
1849 * @since 6.0.0 |
1923 * @since 6.0.0 |
1868 // Filter an iframe match. |
1942 // Filter an iframe match. |
1869 if ( isset( $iframes[ $match[0] ] ) ) { |
1943 if ( isset( $iframes[ $match[0] ] ) ) { |
1870 $filtered_iframe = $match[0]; |
1944 $filtered_iframe = $match[0]; |
1871 |
1945 |
1872 // Add 'loading' attribute if applicable. |
1946 // Add 'loading' attribute if applicable. |
1873 if ( $add_iframe_loading_attr && false === strpos( $filtered_iframe, ' loading=' ) ) { |
1947 if ( $add_iframe_loading_attr && ! str_contains( $filtered_iframe, ' loading=' ) ) { |
1874 $filtered_iframe = wp_iframe_tag_add_loading_attr( $filtered_iframe, $context ); |
1948 $filtered_iframe = wp_iframe_tag_add_loading_attr( $filtered_iframe, $context ); |
1875 } |
1949 } |
1876 |
1950 |
1877 if ( $filtered_iframe !== $match[0] ) { |
1951 if ( $filtered_iframe !== $match[0] ) { |
1878 $content = str_replace( $match[0], $filtered_iframe, $content ); |
1952 $content = str_replace( $match[0], $filtered_iframe, $content ); |
1888 |
1962 |
1889 return $content; |
1963 return $content; |
1890 } |
1964 } |
1891 |
1965 |
1892 /** |
1966 /** |
1893 * Adds `loading` attribute to an `img` HTML tag. |
1967 * Adds optimization attributes to an `img` HTML tag. |
1894 * |
1968 * |
1895 * @since 5.5.0 |
1969 * @since 6.3.0 |
1896 * |
1970 * |
1897 * @param string $image The HTML `img` tag where the attribute should be added. |
1971 * @param string $image The HTML `img` tag where the attribute should be added. |
1898 * @param string $context Additional context to pass to the filters. |
1972 * @param string $context Additional context to pass to the filters. |
1899 * @return string Converted `img` tag with `loading` attribute added. |
1973 * @return string Converted `img` tag with optimization attributes added. |
1900 */ |
1974 */ |
1901 function wp_img_tag_add_loading_attr( $image, $context ) { |
1975 function wp_img_tag_add_loading_optimization_attrs( $image, $context ) { |
1902 // Get loading attribute value to use. This must occur before the conditional check below so that even images that |
1976 $width = preg_match( '/ width=["\']([0-9]+)["\']/', $image, $match_width ) ? (int) $match_width[1] : null; |
1903 // are ineligible for being lazy-loaded are considered. |
1977 $height = preg_match( '/ height=["\']([0-9]+)["\']/', $image, $match_height ) ? (int) $match_height[1] : null; |
1904 $value = wp_get_loading_attr_default( $context ); |
1978 $loading_val = preg_match( '/ loading=["\']([A-Za-z]+)["\']/', $image, $match_loading ) ? $match_loading[1] : null; |
1905 |
1979 $fetchpriority_val = preg_match( '/ fetchpriority=["\']([A-Za-z]+)["\']/', $image, $match_fetchpriority ) ? $match_fetchpriority[1] : null; |
1906 // Images should have source and dimension attributes for the `loading` attribute to be added. |
1980 $decoding_val = preg_match( '/ decoding=["\']([A-Za-z]+)["\']/', $image, $match_decoding ) ? $match_decoding[1] : null; |
1907 if ( false === strpos( $image, ' src="' ) || false === strpos( $image, ' width="' ) || false === strpos( $image, ' height="' ) ) { |
1981 |
1982 /* |
|
1983 * Get loading optimization attributes to use. |
|
1984 * This must occur before the conditional check below so that even images |
|
1985 * that are ineligible for being lazy-loaded are considered. |
|
1986 */ |
|
1987 $optimization_attrs = wp_get_loading_optimization_attributes( |
|
1988 'img', |
|
1989 array( |
|
1990 'width' => $width, |
|
1991 'height' => $height, |
|
1992 'loading' => $loading_val, |
|
1993 'fetchpriority' => $fetchpriority_val, |
|
1994 'decoding' => $decoding_val, |
|
1995 ), |
|
1996 $context |
|
1997 ); |
|
1998 |
|
1999 // Images should have source for the loading optimization attributes to be added. |
|
2000 if ( ! str_contains( $image, ' src="' ) ) { |
|
1908 return $image; |
2001 return $image; |
1909 } |
2002 } |
1910 |
2003 |
1911 /** |
2004 if ( empty( $decoding_val ) ) { |
1912 * Filters the `loading` attribute value to add to an image. Default `lazy`. |
2005 /** |
1913 * |
2006 * Filters the `decoding` attribute value to add to an image. Default `async`. |
1914 * Returning `false` or an empty string will not add the attribute. |
2007 * |
1915 * Returning `true` will add the default value. |
2008 * Returning a falsey value will omit the attribute. |
1916 * |
2009 * |
1917 * @since 5.5.0 |
2010 * @since 6.1.0 |
1918 * |
2011 * |
1919 * @param string|bool $value The `loading` attribute value. Returning a falsey value will result in |
2012 * @param string|false|null $value The `decoding` attribute value. Returning a falsey value |
1920 * the attribute being omitted for the image. |
2013 * will result in the attribute being omitted for the image. |
1921 * @param string $image The HTML `img` tag to be filtered. |
2014 * Otherwise, it may be: 'async', 'sync', or 'auto'. Defaults to false. |
1922 * @param string $context Additional context about how the function was called or where the img tag is. |
2015 * @param string $image The HTML `img` tag to be filtered. |
1923 */ |
2016 * @param string $context Additional context about how the function was called |
1924 $value = apply_filters( 'wp_img_tag_add_loading_attr', $value, $image, $context ); |
2017 * or where the img tag is. |
1925 |
2018 */ |
1926 if ( $value ) { |
2019 $filtered_decoding_attr = apply_filters( |
1927 if ( ! in_array( $value, array( 'lazy', 'eager' ), true ) ) { |
2020 'wp_img_tag_add_decoding_attr', |
1928 $value = 'lazy'; |
2021 isset( $optimization_attrs['decoding'] ) ? $optimization_attrs['decoding'] : false, |
1929 } |
2022 $image, |
1930 |
2023 $context |
1931 return str_replace( '<img', '<img loading="' . esc_attr( $value ) . '"', $image ); |
2024 ); |
2025 |
|
2026 // Validate the values after filtering. |
|
2027 if ( isset( $optimization_attrs['decoding'] ) && ! $filtered_decoding_attr ) { |
|
2028 // Unset `decoding` attribute if `$filtered_decoding_attr` is set to `false`. |
|
2029 unset( $optimization_attrs['decoding'] ); |
|
2030 } elseif ( in_array( $filtered_decoding_attr, array( 'async', 'sync', 'auto' ), true ) ) { |
|
2031 $optimization_attrs['decoding'] = $filtered_decoding_attr; |
|
2032 } |
|
2033 |
|
2034 if ( ! empty( $optimization_attrs['decoding'] ) ) { |
|
2035 $image = str_replace( '<img', '<img decoding="' . esc_attr( $optimization_attrs['decoding'] ) . '"', $image ); |
|
2036 } |
|
2037 } |
|
2038 |
|
2039 // Images should have dimension attributes for the 'loading' and 'fetchpriority' attributes to be added. |
|
2040 if ( ! str_contains( $image, ' width="' ) || ! str_contains( $image, ' height="' ) ) { |
|
2041 return $image; |
|
2042 } |
|
2043 |
|
2044 // Retained for backward compatibility. |
|
2045 $loading_attrs_enabled = wp_lazy_loading_enabled( 'img', $context ); |
|
2046 |
|
2047 if ( empty( $loading_val ) && $loading_attrs_enabled ) { |
|
2048 /** |
|
2049 * Filters the `loading` attribute value to add to an image. Default `lazy`. |
|
2050 * |
|
2051 * Returning `false` or an empty string will not add the attribute. |
|
2052 * Returning `true` will add the default value. |
|
2053 * |
|
2054 * @since 5.5.0 |
|
2055 * |
|
2056 * @param string|bool $value The `loading` attribute value. Returning a falsey value will result in |
|
2057 * the attribute being omitted for the image. |
|
2058 * @param string $image The HTML `img` tag to be filtered. |
|
2059 * @param string $context Additional context about how the function was called or where the img tag is. |
|
2060 */ |
|
2061 $filtered_loading_attr = apply_filters( |
|
2062 'wp_img_tag_add_loading_attr', |
|
2063 isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false, |
|
2064 $image, |
|
2065 $context |
|
2066 ); |
|
2067 |
|
2068 // Validate the values after filtering. |
|
2069 if ( isset( $optimization_attrs['loading'] ) && ! $filtered_loading_attr ) { |
|
2070 // Unset `loading` attributes if `$filtered_loading_attr` is set to `false`. |
|
2071 unset( $optimization_attrs['loading'] ); |
|
2072 } elseif ( in_array( $filtered_loading_attr, array( 'lazy', 'eager' ), true ) ) { |
|
2073 /* |
|
2074 * If the filter changed the loading attribute to "lazy" when a fetchpriority attribute |
|
2075 * with value "high" is already present, trigger a warning since those two attribute |
|
2076 * values should be mutually exclusive. |
|
2077 * |
|
2078 * The same warning is present in `wp_get_loading_optimization_attributes()`, and here it |
|
2079 * is only intended for the specific scenario where the above filtered caused the problem. |
|
2080 */ |
|
2081 if ( isset( $optimization_attrs['fetchpriority'] ) && 'high' === $optimization_attrs['fetchpriority'] && |
|
2082 ( isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false ) !== $filtered_loading_attr && |
|
2083 'lazy' === $filtered_loading_attr |
|
2084 ) { |
|
2085 _doing_it_wrong( |
|
2086 __FUNCTION__, |
|
2087 __( 'An image should not be lazy-loaded and marked as high priority at the same time.' ), |
|
2088 '6.3.0' |
|
2089 ); |
|
2090 } |
|
2091 |
|
2092 // The filtered value will still be respected. |
|
2093 $optimization_attrs['loading'] = $filtered_loading_attr; |
|
2094 } |
|
2095 |
|
2096 if ( ! empty( $optimization_attrs['loading'] ) ) { |
|
2097 $image = str_replace( '<img', '<img loading="' . esc_attr( $optimization_attrs['loading'] ) . '"', $image ); |
|
2098 } |
|
2099 } |
|
2100 |
|
2101 if ( empty( $fetchpriority_val ) && ! empty( $optimization_attrs['fetchpriority'] ) ) { |
|
2102 $image = str_replace( '<img', '<img fetchpriority="' . esc_attr( $optimization_attrs['fetchpriority'] ) . '"', $image ); |
|
1932 } |
2103 } |
1933 |
2104 |
1934 return $image; |
2105 return $image; |
1935 } |
2106 } |
1936 |
2107 |
1969 |
2140 |
1970 if ( true === $add ) { |
2141 if ( true === $add ) { |
1971 $image_meta = wp_get_attachment_metadata( $attachment_id ); |
2142 $image_meta = wp_get_attachment_metadata( $attachment_id ); |
1972 $size_array = wp_image_src_get_dimensions( $image_src, $image_meta, $attachment_id ); |
2143 $size_array = wp_image_src_get_dimensions( $image_src, $image_meta, $attachment_id ); |
1973 |
2144 |
1974 if ( $size_array ) { |
2145 if ( $size_array && $size_array[0] && $size_array[1] ) { |
2146 // If the width is enforced through style (e.g. in an inline image), calculate the dimension attributes. |
|
2147 $style_width = preg_match( '/style="width:\s*(\d+)px;"/', $image, $match_width ) ? (int) $match_width[1] : 0; |
|
2148 if ( $style_width ) { |
|
2149 $size_array[1] = (int) round( $size_array[1] * $style_width / $size_array[0] ); |
|
2150 $size_array[0] = $style_width; |
|
2151 } |
|
2152 |
|
1975 $hw = trim( image_hwstring( $size_array[0], $size_array[1] ) ); |
2153 $hw = trim( image_hwstring( $size_array[0], $size_array[1] ) ); |
1976 return str_replace( '<img', "<img {$hw}", $image ); |
2154 return str_replace( '<img', "<img {$hw}", $image ); |
1977 } |
2155 } |
1978 } |
2156 } |
1979 |
2157 |
2021 * @param string $iframe The HTML `iframe` tag where the attribute should be added. |
2199 * @param string $iframe The HTML `iframe` tag where the attribute should be added. |
2022 * @param string $context Additional context to pass to the filters. |
2200 * @param string $context Additional context to pass to the filters. |
2023 * @return string Converted `iframe` tag with `loading` attribute added. |
2201 * @return string Converted `iframe` tag with `loading` attribute added. |
2024 */ |
2202 */ |
2025 function wp_iframe_tag_add_loading_attr( $iframe, $context ) { |
2203 function wp_iframe_tag_add_loading_attr( $iframe, $context ) { |
2026 // Iframes with fallback content (see `wp_filter_oembed_result()`) should not be lazy-loaded because they are |
2204 /* |
2027 // visually hidden initially. |
2205 * Get loading attribute value to use. This must occur before the conditional check below so that even iframes that |
2028 if ( false !== strpos( $iframe, ' data-secret="' ) ) { |
2206 * are ineligible for being lazy-loaded are considered. |
2207 */ |
|
2208 $optimization_attrs = wp_get_loading_optimization_attributes( |
|
2209 'iframe', |
|
2210 array( |
|
2211 /* |
|
2212 * The concrete values for width and height are not important here for now |
|
2213 * since fetchpriority is not yet supported for iframes. |
|
2214 * TODO: Use WP_HTML_Tag_Processor to extract actual values once support is |
|
2215 * added. |
|
2216 */ |
|
2217 'width' => str_contains( $iframe, ' width="' ) ? 100 : null, |
|
2218 'height' => str_contains( $iframe, ' height="' ) ? 100 : null, |
|
2219 // This function is never called when a 'loading' attribute is already present. |
|
2220 'loading' => null, |
|
2221 ), |
|
2222 $context |
|
2223 ); |
|
2224 |
|
2225 // Iframes should have source and dimension attributes for the `loading` attribute to be added. |
|
2226 if ( ! str_contains( $iframe, ' src="' ) || ! str_contains( $iframe, ' width="' ) || ! str_contains( $iframe, ' height="' ) ) { |
|
2029 return $iframe; |
2227 return $iframe; |
2030 } |
2228 } |
2031 |
2229 |
2032 // Get loading attribute value to use. This must occur before the conditional check below so that even iframes that |
2230 $value = isset( $optimization_attrs['loading'] ) ? $optimization_attrs['loading'] : false; |
2033 // are ineligible for being lazy-loaded are considered. |
|
2034 $value = wp_get_loading_attr_default( $context ); |
|
2035 |
|
2036 // Iframes should have source and dimension attributes for the `loading` attribute to be added. |
|
2037 if ( false === strpos( $iframe, ' src="' ) || false === strpos( $iframe, ' width="' ) || false === strpos( $iframe, ' height="' ) ) { |
|
2038 return $iframe; |
|
2039 } |
|
2040 |
2231 |
2041 /** |
2232 /** |
2042 * Filters the `loading` attribute value to add to an iframe. Default `lazy`. |
2233 * Filters the `loading` attribute value to add to an iframe. Default `lazy`. |
2043 * |
2234 * |
2044 * Returning `false` or an empty string will not add the attribute. |
2235 * Returning `false` or an empty string will not add the attribute. |
2103 * |
2294 * |
2104 * @param string[] $attr Array of thumbnail attributes including src, class, alt, title, keyed by attribute name. |
2295 * @param string[] $attr Array of thumbnail attributes including src, class, alt, title, keyed by attribute name. |
2105 */ |
2296 */ |
2106 function _wp_post_thumbnail_class_filter_remove( $attr ) { |
2297 function _wp_post_thumbnail_class_filter_remove( $attr ) { |
2107 remove_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' ); |
2298 remove_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' ); |
2299 } |
|
2300 |
|
2301 /** |
|
2302 * Overrides the context used in {@see wp_get_attachment_image()}. Internal use only. |
|
2303 * |
|
2304 * Uses the {@see 'begin_fetch_post_thumbnail_html'} and {@see 'end_fetch_post_thumbnail_html'} |
|
2305 * action hooks to dynamically add/remove itself so as to only filter post thumbnails. |
|
2306 * |
|
2307 * @ignore |
|
2308 * @since 6.3.0 |
|
2309 * @access private |
|
2310 * |
|
2311 * @param string $context The context for rendering an attachment image. |
|
2312 * @return string Modified context set to 'the_post_thumbnail'. |
|
2313 */ |
|
2314 function _wp_post_thumbnail_context_filter( $context ) { |
|
2315 return 'the_post_thumbnail'; |
|
2316 } |
|
2317 |
|
2318 /** |
|
2319 * Adds the '_wp_post_thumbnail_context_filter' callback to the 'wp_get_attachment_image_context' |
|
2320 * filter hook. Internal use only. |
|
2321 * |
|
2322 * @ignore |
|
2323 * @since 6.3.0 |
|
2324 * @access private |
|
2325 */ |
|
2326 function _wp_post_thumbnail_context_filter_add() { |
|
2327 add_filter( 'wp_get_attachment_image_context', '_wp_post_thumbnail_context_filter' ); |
|
2328 } |
|
2329 |
|
2330 /** |
|
2331 * Removes the '_wp_post_thumbnail_context_filter' callback from the 'wp_get_attachment_image_context' |
|
2332 * filter hook. Internal use only. |
|
2333 * |
|
2334 * @ignore |
|
2335 * @since 6.3.0 |
|
2336 * @access private |
|
2337 */ |
|
2338 function _wp_post_thumbnail_context_filter_remove() { |
|
2339 remove_filter( 'wp_get_attachment_image_context', '_wp_post_thumbnail_context_filter' ); |
|
2108 } |
2340 } |
2109 |
2341 |
2110 add_shortcode( 'wp_caption', 'img_caption_shortcode' ); |
2342 add_shortcode( 'wp_caption', 'img_caption_shortcode' ); |
2111 add_shortcode( 'caption', 'img_caption_shortcode' ); |
2343 add_shortcode( 'caption', 'img_caption_shortcode' ); |
2112 |
2344 |
2144 if ( ! isset( $attr['caption'] ) ) { |
2376 if ( ! isset( $attr['caption'] ) ) { |
2145 if ( preg_match( '#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches ) ) { |
2377 if ( preg_match( '#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches ) ) { |
2146 $content = $matches[1]; |
2378 $content = $matches[1]; |
2147 $attr['caption'] = trim( $matches[2] ); |
2379 $attr['caption'] = trim( $matches[2] ); |
2148 } |
2380 } |
2149 } elseif ( strpos( $attr['caption'], '<' ) !== false ) { |
2381 } elseif ( str_contains( $attr['caption'], '<' ) ) { |
2150 $attr['caption'] = wp_kses( $attr['caption'], 'post' ); |
2382 $attr['caption'] = wp_kses( $attr['caption'], 'post' ); |
2151 } |
2383 } |
2152 |
2384 |
2153 /** |
2385 /** |
2154 * Filters the default caption shortcode output. |
2386 * Filters the default caption shortcode output. |
2277 * |
2509 * |
2278 * This implements the functionality of the Gallery Shortcode for displaying |
2510 * This implements the functionality of the Gallery Shortcode for displaying |
2279 * WordPress images on a post. |
2511 * WordPress images on a post. |
2280 * |
2512 * |
2281 * @since 2.5.0 |
2513 * @since 2.5.0 |
2514 * @since 2.8.0 Added the `$attr` parameter to set the shortcode output. New attributes included |
|
2515 * such as `size`, `itemtag`, `icontag`, `captiontag`, and columns. Changed markup from |
|
2516 * `div` tags to `dl`, `dt` and `dd` tags. Support more than one gallery on the |
|
2517 * same page. |
|
2518 * @since 2.9.0 Added support for `include` and `exclude` to shortcode. |
|
2519 * @since 3.5.0 Use get_post() instead of global `$post`. Handle mapping of `ids` to `include` |
|
2520 * and `orderby`. |
|
2521 * @since 3.6.0 Added validation for tags used in gallery shortcode. Add orientation information to items. |
|
2522 * @since 3.7.0 Introduced the `link` attribute. |
|
2523 * @since 3.9.0 `html5` gallery support, accepting 'itemtag', 'icontag', and 'captiontag' attributes. |
|
2524 * @since 4.0.0 Removed use of `extract()`. |
|
2525 * @since 4.1.0 Added attribute to `wp_get_attachment_link()` to output `aria-describedby`. |
|
2526 * @since 4.2.0 Passed the shortcode instance ID to `post_gallery` and `post_playlist` filters. |
|
2527 * @since 4.6.0 Standardized filter docs to match documentation standards for PHP. |
|
2528 * @since 5.1.0 Code cleanup for WPCS 1.0.0 coding standards. |
|
2529 * @since 5.3.0 Saved progress of intermediate image creation after upload. |
|
2530 * @since 5.5.0 Ensured that galleries can be output as a list of links in feeds. |
|
2531 * @since 5.6.0 Replaced order-style PHP type conversion functions with typecasts. Fix logic for |
|
2532 * an array of image dimensions. |
|
2282 * |
2533 * |
2283 * @param array $attr { |
2534 * @param array $attr { |
2284 * Attributes of the gallery shortcode. |
2535 * Attributes of the gallery shortcode. |
2285 * |
2536 * |
2286 * @type string $order Order of the images in the gallery. Default 'ASC'. Accepts 'ASC', 'DESC'. |
2537 * @type string $order Order of the images in the gallery. Default 'ASC'. Accepts 'ASC', 'DESC'. |
2306 */ |
2557 */ |
2307 function gallery_shortcode( $attr ) { |
2558 function gallery_shortcode( $attr ) { |
2308 $post = get_post(); |
2559 $post = get_post(); |
2309 |
2560 |
2310 static $instance = 0; |
2561 static $instance = 0; |
2311 $instance++; |
2562 ++$instance; |
2312 |
2563 |
2313 if ( ! empty( $attr['ids'] ) ) { |
2564 if ( ! empty( $attr['ids'] ) ) { |
2314 // 'ids' is explicitly ordered, unless you specify otherwise. |
2565 // 'ids' is explicitly ordered, unless you specify otherwise. |
2315 if ( empty( $attr['orderby'] ) ) { |
2566 if ( empty( $attr['orderby'] ) ) { |
2316 $attr['orderby'] = 'post__in'; |
2567 $attr['orderby'] = 'post__in'; |
2375 $attachments = array(); |
2626 $attachments = array(); |
2376 foreach ( $_attachments as $key => $val ) { |
2627 foreach ( $_attachments as $key => $val ) { |
2377 $attachments[ $val->ID ] = $_attachments[ $key ]; |
2628 $attachments[ $val->ID ] = $_attachments[ $key ]; |
2378 } |
2629 } |
2379 } elseif ( ! empty( $atts['exclude'] ) ) { |
2630 } elseif ( ! empty( $atts['exclude'] ) ) { |
2380 $attachments = get_children( |
2631 $post_parent_id = $id; |
2632 $attachments = get_children( |
|
2381 array( |
2633 array( |
2382 'post_parent' => $id, |
2634 'post_parent' => $id, |
2383 'exclude' => $atts['exclude'], |
2635 'exclude' => $atts['exclude'], |
2384 'post_status' => 'inherit', |
2636 'post_status' => 'inherit', |
2385 'post_type' => 'attachment', |
2637 'post_type' => 'attachment', |
2387 'order' => $atts['order'], |
2639 'order' => $atts['order'], |
2388 'orderby' => $atts['orderby'], |
2640 'orderby' => $atts['orderby'], |
2389 ) |
2641 ) |
2390 ); |
2642 ); |
2391 } else { |
2643 } else { |
2392 $attachments = get_children( |
2644 $post_parent_id = $id; |
2645 $attachments = get_children( |
|
2393 array( |
2646 array( |
2394 'post_parent' => $id, |
2647 'post_parent' => $id, |
2395 'post_status' => 'inherit', |
2648 'post_status' => 'inherit', |
2396 'post_type' => 'attachment', |
2649 'post_type' => 'attachment', |
2397 'post_mime_type' => 'image', |
2650 'post_mime_type' => 'image', |
2398 'order' => $atts['order'], |
2651 'order' => $atts['order'], |
2399 'orderby' => $atts['orderby'], |
2652 'orderby' => $atts['orderby'], |
2400 ) |
2653 ) |
2401 ); |
2654 ); |
2655 } |
|
2656 |
|
2657 if ( ! empty( $post_parent_id ) ) { |
|
2658 $post_parent = get_post( $post_parent_id ); |
|
2659 |
|
2660 // Terminate the shortcode execution if the user cannot read the post or it is password-protected. |
|
2661 if ( ! is_post_publicly_viewable( $post_parent->ID ) && ! current_user_can( 'read_post', $post_parent->ID ) |
|
2662 || post_password_required( $post_parent ) |
|
2663 ) { |
|
2664 return ''; |
|
2665 } |
|
2402 } |
2666 } |
2403 |
2667 |
2404 if ( empty( $attachments ) ) { |
2668 if ( empty( $attachments ) ) { |
2405 return ''; |
2669 return ''; |
2406 } |
2670 } |
2554 <# if ( data.thumb && data.thumb.src ) { #> |
2818 <# if ( data.thumb && data.thumb.src ) { #> |
2555 <img src="{{ data.thumb.src }}" alt="" /> |
2819 <img src="{{ data.thumb.src }}" alt="" /> |
2556 <# } #> |
2820 <# } #> |
2557 <div class="wp-playlist-caption"> |
2821 <div class="wp-playlist-caption"> |
2558 <span class="wp-playlist-item-meta wp-playlist-item-title"> |
2822 <span class="wp-playlist-item-meta wp-playlist-item-title"> |
2559 <?php |
2823 <# if ( data.meta.album || data.meta.artist ) { #> |
2560 /* translators: %s: Playlist item title. */ |
2824 <?php |
2561 printf( _x( '“%s”', 'playlist item title' ), '{{ data.title }}' ); |
2825 /* translators: %s: Playlist item title. */ |
2562 ?> |
2826 printf( _x( '“%s”', 'playlist item title' ), '{{ data.title }}' ); |
2827 ?> |
|
2828 <# } else { #> |
|
2829 {{ data.title }} |
|
2830 <# } #> |
|
2563 </span> |
2831 </span> |
2564 <# if ( data.meta.album ) { #><span class="wp-playlist-item-meta wp-playlist-item-album">{{ data.meta.album }}</span><# } #> |
2832 <# if ( data.meta.album ) { #><span class="wp-playlist-item-meta wp-playlist-item-album">{{ data.meta.album }}</span><# } #> |
2565 <# if ( data.meta.artist ) { #><span class="wp-playlist-item-meta wp-playlist-item-artist">{{ data.meta.artist }}</span><# } #> |
2833 <# if ( data.meta.artist ) { #><span class="wp-playlist-item-meta wp-playlist-item-artist">{{ data.meta.artist }}</span><# } #> |
2566 </div> |
2834 </div> |
2567 </script> |
2835 </script> |
2570 <a class="wp-playlist-caption" href="{{ data.src }}"> |
2838 <a class="wp-playlist-caption" href="{{ data.src }}"> |
2571 {{ data.index ? ( data.index + '. ' ) : '' }} |
2839 {{ data.index ? ( data.index + '. ' ) : '' }} |
2572 <# if ( data.caption ) { #> |
2840 <# if ( data.caption ) { #> |
2573 {{ data.caption }} |
2841 {{ data.caption }} |
2574 <# } else { #> |
2842 <# } else { #> |
2575 <span class="wp-playlist-item-title"> |
|
2576 <?php |
|
2577 /* translators: %s: Playlist item title. */ |
|
2578 printf( _x( '“%s”', 'playlist item title' ), '{{{ data.title }}}' ); |
|
2579 ?> |
|
2580 </span> |
|
2581 <# if ( data.artists && data.meta.artist ) { #> |
2843 <# if ( data.artists && data.meta.artist ) { #> |
2582 <span class="wp-playlist-item-artist"> — {{ data.meta.artist }}</span> |
2844 <span class="wp-playlist-item-title"> |
2845 <?php |
|
2846 /* translators: %s: Playlist item title. */ |
|
2847 printf( _x( '“%s”', 'playlist item title' ), '{{{ data.title }}}' ); |
|
2848 ?> |
|
2849 </span> |
|
2850 <span class="wp-playlist-item-artist"> — {{ data.meta.artist }}</span> |
|
2851 <# } else { #> |
|
2852 <span class="wp-playlist-item-title">{{{ data.title }}}</span> |
|
2583 <# } #> |
2853 <# } #> |
2584 <# } #> |
2854 <# } #> |
2585 </a> |
2855 </a> |
2586 <# if ( data.meta.length_formatted ) { #> |
2856 <# if ( data.meta.length_formatted ) { #> |
2587 <div class="wp-playlist-item-length">{{ data.meta.length_formatted }}</div> |
2857 <div class="wp-playlist-item-length">{{ data.meta.length_formatted }}</div> |
2590 </script> |
2860 </script> |
2591 <?php |
2861 <?php |
2592 } |
2862 } |
2593 |
2863 |
2594 /** |
2864 /** |
2595 * Outputs and enqueue default scripts and styles for playlists. |
2865 * Outputs and enqueues default scripts and styles for playlists. |
2596 * |
2866 * |
2597 * @since 3.9.0 |
2867 * @since 3.9.0 |
2598 * |
2868 * |
2599 * @param string $type Type of playlist. Accepts 'audio' or 'video'. |
2869 * @param string $type Type of playlist. Accepts 'audio' or 'video'. |
2600 */ |
2870 */ |
2647 function wp_playlist_shortcode( $attr ) { |
2917 function wp_playlist_shortcode( $attr ) { |
2648 global $content_width; |
2918 global $content_width; |
2649 $post = get_post(); |
2919 $post = get_post(); |
2650 |
2920 |
2651 static $instance = 0; |
2921 static $instance = 0; |
2652 $instance++; |
2922 ++$instance; |
2653 |
2923 |
2654 if ( ! empty( $attr['ids'] ) ) { |
2924 if ( ! empty( $attr['ids'] ) ) { |
2655 // 'ids' is explicitly ordered, unless you specify otherwise. |
2925 // 'ids' is explicitly ordered, unless you specify otherwise. |
2656 if ( empty( $attr['orderby'] ) ) { |
2926 if ( empty( $attr['orderby'] ) ) { |
2657 $attr['orderby'] = 'post__in'; |
2927 $attr['orderby'] = 'post__in'; |
2725 } else { |
2995 } else { |
2726 $args['post_parent'] = $id; |
2996 $args['post_parent'] = $id; |
2727 $attachments = get_children( $args ); |
2997 $attachments = get_children( $args ); |
2728 } |
2998 } |
2729 |
2999 |
3000 if ( ! empty( $args['post_parent'] ) ) { |
|
3001 $post_parent = get_post( $id ); |
|
3002 |
|
3003 // Terminate the shortcode execution if the user cannot read the post or it is password-protected. |
|
3004 if ( ! current_user_can( 'read_post', $post_parent->ID ) || post_password_required( $post_parent ) ) { |
|
3005 return ''; |
|
3006 } |
|
3007 } |
|
3008 |
|
2730 if ( empty( $attachments ) ) { |
3009 if ( empty( $attachments ) ) { |
2731 return ''; |
3010 return ''; |
2732 } |
3011 } |
2733 |
3012 |
2734 if ( is_feed() ) { |
3013 if ( is_feed() ) { |
2804 list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'full' ); |
3083 list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'full' ); |
2805 $track['image'] = compact( 'src', 'width', 'height' ); |
3084 $track['image'] = compact( 'src', 'width', 'height' ); |
2806 list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'thumbnail' ); |
3085 list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'thumbnail' ); |
2807 $track['thumb'] = compact( 'src', 'width', 'height' ); |
3086 $track['thumb'] = compact( 'src', 'width', 'height' ); |
2808 } else { |
3087 } else { |
2809 $src = wp_mime_type_icon( $attachment->ID ); |
3088 $src = wp_mime_type_icon( $attachment->ID, '.svg' ); |
2810 $width = 48; |
3089 $width = 48; |
2811 $height = 64; |
3090 $height = 64; |
2812 $track['image'] = compact( 'src', 'width', 'height' ); |
3091 $track['image'] = compact( 'src', 'width', 'height' ); |
2813 $track['thumb'] = compact( 'src', 'width', 'height' ); |
3092 $track['thumb'] = compact( 'src', 'width', 'height' ); |
2814 } |
3093 } |
2872 * @param string $url The media element URL. |
3151 * @param string $url The media element URL. |
2873 * @return string Fallback HTML. |
3152 * @return string Fallback HTML. |
2874 */ |
3153 */ |
2875 function wp_mediaelement_fallback( $url ) { |
3154 function wp_mediaelement_fallback( $url ) { |
2876 /** |
3155 /** |
2877 * Filters the Mediaelement fallback output for no-JS. |
3156 * Filters the MediaElement fallback output for no-JS. |
2878 * |
3157 * |
2879 * @since 3.6.0 |
3158 * @since 3.6.0 |
2880 * |
3159 * |
2881 * @param string $output Fallback output for no-JS. |
3160 * @param string $output Fallback output for no-JS. |
2882 * @param string $url Media file URL. |
3161 * @param string $url Media file URL. |
2961 */ |
3240 */ |
2962 function wp_audio_shortcode( $attr, $content = '' ) { |
3241 function wp_audio_shortcode( $attr, $content = '' ) { |
2963 $post_id = get_post() ? get_the_ID() : 0; |
3242 $post_id = get_post() ? get_the_ID() : 0; |
2964 |
3243 |
2965 static $instance = 0; |
3244 static $instance = 0; |
2966 $instance++; |
3245 ++$instance; |
2967 |
3246 |
2968 /** |
3247 /** |
2969 * Filters the default audio shortcode output. |
3248 * Filters the default audio shortcode output. |
2970 * |
3249 * |
2971 * If the filtered output isn't empty, it will be used instead of generating the default audio template. |
3250 * If the filtered output isn't empty, it will be used instead of generating the default audio template. |
2972 * |
3251 * |
2973 * @since 3.6.0 |
3252 * @since 3.6.0 |
2974 * |
3253 * |
2975 * @param string $html Empty variable to be replaced with shortcode markup. |
3254 * @param string $html Empty variable to be replaced with shortcode markup. |
2976 * @param array $attr Attributes of the shortcode. @see wp_audio_shortcode() |
3255 * @param array $attr Attributes of the shortcode. See {@see wp_audio_shortcode()}. |
2977 * @param string $content Shortcode content. |
3256 * @param string $content Shortcode content. |
2978 * @param int $instance Unique numeric ID of this audio shortcode instance. |
3257 * @param int $instance Unique numeric ID of this audio shortcode instance. |
2979 */ |
3258 */ |
2980 $override = apply_filters( 'wp_audio_shortcode_override', '', $attr, $content, $instance ); |
3259 $override = apply_filters( 'wp_audio_shortcode_override', '', $attr, $content, $instance ); |
2981 |
3260 |
3166 * @type int $height Height of the video embed in pixels. Default 360. |
3445 * @type int $height Height of the video embed in pixels. Default 360. |
3167 * @type int $width Width of the video embed in pixels. Default $content_width or 640. |
3446 * @type int $width Width of the video embed in pixels. Default $content_width or 640. |
3168 * @type string $poster The 'poster' attribute for the `<video>` element. Default empty. |
3447 * @type string $poster The 'poster' attribute for the `<video>` element. Default empty. |
3169 * @type string $loop The 'loop' attribute for the `<video>` element. Default empty. |
3448 * @type string $loop The 'loop' attribute for the `<video>` element. Default empty. |
3170 * @type string $autoplay The 'autoplay' attribute for the `<video>` element. Default empty. |
3449 * @type string $autoplay The 'autoplay' attribute for the `<video>` element. Default empty. |
3450 * @type string $muted The 'muted' attribute for the `<video>` element. Default false. |
|
3171 * @type string $preload The 'preload' attribute for the `<video>` element. |
3451 * @type string $preload The 'preload' attribute for the `<video>` element. |
3172 * Default 'metadata'. |
3452 * Default 'metadata'. |
3173 * @type string $class The 'class' attribute for the `<video>` element. |
3453 * @type string $class The 'class' attribute for the `<video>` element. |
3174 * Default 'wp-video-shortcode'. |
3454 * Default 'wp-video-shortcode'. |
3175 * } |
3455 * } |
3179 function wp_video_shortcode( $attr, $content = '' ) { |
3459 function wp_video_shortcode( $attr, $content = '' ) { |
3180 global $content_width; |
3460 global $content_width; |
3181 $post_id = get_post() ? get_the_ID() : 0; |
3461 $post_id = get_post() ? get_the_ID() : 0; |
3182 |
3462 |
3183 static $instance = 0; |
3463 static $instance = 0; |
3184 $instance++; |
3464 ++$instance; |
3185 |
3465 |
3186 /** |
3466 /** |
3187 * Filters the default video shortcode output. |
3467 * Filters the default video shortcode output. |
3188 * |
3468 * |
3189 * If the filtered output isn't empty, it will be used instead of generating |
3469 * If the filtered output isn't empty, it will be used instead of generating |
3192 * @since 3.6.0 |
3472 * @since 3.6.0 |
3193 * |
3473 * |
3194 * @see wp_video_shortcode() |
3474 * @see wp_video_shortcode() |
3195 * |
3475 * |
3196 * @param string $html Empty variable to be replaced with shortcode markup. |
3476 * @param string $html Empty variable to be replaced with shortcode markup. |
3197 * @param array $attr Attributes of the shortcode. @see wp_video_shortcode() |
3477 * @param array $attr Attributes of the shortcode. See {@see wp_video_shortcode()}. |
3198 * @param string $content Video shortcode content. |
3478 * @param string $content Video shortcode content. |
3199 * @param int $instance Unique numeric ID of this video shortcode instance. |
3479 * @param int $instance Unique numeric ID of this video shortcode instance. |
3200 */ |
3480 */ |
3201 $override = apply_filters( 'wp_video_shortcode_override', '', $attr, $content, $instance ); |
3481 $override = apply_filters( 'wp_video_shortcode_override', '', $attr, $content, $instance ); |
3202 |
3482 |
3210 $defaults_atts = array( |
3490 $defaults_atts = array( |
3211 'src' => '', |
3491 'src' => '', |
3212 'poster' => '', |
3492 'poster' => '', |
3213 'loop' => '', |
3493 'loop' => '', |
3214 'autoplay' => '', |
3494 'autoplay' => '', |
3495 'muted' => 'false', |
|
3215 'preload' => 'metadata', |
3496 'preload' => 'metadata', |
3216 'width' => 640, |
3497 'width' => 640, |
3217 'height' => 360, |
3498 'height' => 360, |
3218 'class' => 'wp-video-shortcode', |
3499 'class' => 'wp-video-shortcode', |
3219 ); |
3500 ); |
3300 wp_enqueue_style( 'wp-mediaelement' ); |
3581 wp_enqueue_style( 'wp-mediaelement' ); |
3301 wp_enqueue_script( 'wp-mediaelement' ); |
3582 wp_enqueue_script( 'wp-mediaelement' ); |
3302 wp_enqueue_script( 'mediaelement-vimeo' ); |
3583 wp_enqueue_script( 'mediaelement-vimeo' ); |
3303 } |
3584 } |
3304 |
3585 |
3305 // MediaElement.js has issues with some URL formats for Vimeo and YouTube, |
3586 /* |
3306 // so update the URL to prevent the ME.js player from breaking. |
3587 * MediaElement.js has issues with some URL formats for Vimeo and YouTube, |
3588 * so update the URL to prevent the ME.js player from breaking. |
|
3589 */ |
|
3307 if ( 'mediaelement' === $library ) { |
3590 if ( 'mediaelement' === $library ) { |
3308 if ( $is_youtube ) { |
3591 if ( $is_youtube ) { |
3309 // Remove `feature` query arg and force SSL - see #40866. |
3592 // Remove `feature` query arg and force SSL - see #40866. |
3310 $atts['src'] = remove_query_arg( 'feature', $atts['src'] ); |
3593 $atts['src'] = remove_query_arg( 'feature', $atts['src'] ); |
3311 $atts['src'] = set_url_scheme( $atts['src'], 'https' ); |
3594 $atts['src'] = set_url_scheme( $atts['src'], 'https' ); |
3337 'width' => absint( $atts['width'] ), |
3620 'width' => absint( $atts['width'] ), |
3338 'height' => absint( $atts['height'] ), |
3621 'height' => absint( $atts['height'] ), |
3339 'poster' => esc_url( $atts['poster'] ), |
3622 'poster' => esc_url( $atts['poster'] ), |
3340 'loop' => wp_validate_boolean( $atts['loop'] ), |
3623 'loop' => wp_validate_boolean( $atts['loop'] ), |
3341 'autoplay' => wp_validate_boolean( $atts['autoplay'] ), |
3624 'autoplay' => wp_validate_boolean( $atts['autoplay'] ), |
3625 'muted' => wp_validate_boolean( $atts['muted'] ), |
|
3342 'preload' => $atts['preload'], |
3626 'preload' => $atts['preload'], |
3343 ); |
3627 ); |
3344 |
3628 |
3345 // These ones should just be omitted altogether if they are blank. |
3629 // These ones should just be omitted altogether if they are blank. |
3346 foreach ( array( 'poster', 'loop', 'autoplay', 'preload' ) as $a ) { |
3630 foreach ( array( 'poster', 'loop', 'autoplay', 'preload', 'muted' ) as $a ) { |
3347 if ( empty( $html_atts[ $a ] ) ) { |
3631 if ( empty( $html_atts[ $a ] ) ) { |
3348 unset( $html_atts[ $a ] ); |
3632 unset( $html_atts[ $a ] ); |
3349 } |
3633 } |
3350 } |
3634 } |
3351 |
3635 |
3381 $html .= sprintf( $source, $type['type'], esc_url( $url ) ); |
3665 $html .= sprintf( $source, $type['type'], esc_url( $url ) ); |
3382 } |
3666 } |
3383 } |
3667 } |
3384 |
3668 |
3385 if ( ! empty( $content ) ) { |
3669 if ( ! empty( $content ) ) { |
3386 if ( false !== strpos( $content, "\n" ) ) { |
3670 if ( str_contains( $content, "\n" ) ) { |
3387 $content = str_replace( array( "\r\n", "\n", "\t" ), '', $content ); |
3671 $content = str_replace( array( "\r\n", "\n", "\t" ), '', $content ); |
3388 } |
3672 } |
3389 $html .= trim( $content ); |
3673 $html .= trim( $content ); |
3390 } |
3674 } |
3391 |
3675 |
3586 $file = get_attached_file( $attachment->ID ); |
3870 $file = get_attached_file( $attachment->ID ); |
3587 $filename = wp_basename( $file ); |
3871 $filename = wp_basename( $file ); |
3588 |
3872 |
3589 $objects = array( 'attachment' ); |
3873 $objects = array( 'attachment' ); |
3590 |
3874 |
3591 if ( false !== strpos( $filename, '.' ) ) { |
3875 if ( str_contains( $filename, '.' ) ) { |
3592 $objects[] = 'attachment:' . substr( $filename, strrpos( $filename, '.' ) + 1 ); |
3876 $objects[] = 'attachment:' . substr( $filename, strrpos( $filename, '.' ) + 1 ); |
3593 } |
3877 } |
3594 |
3878 |
3595 if ( ! empty( $attachment->post_mime_type ) ) { |
3879 if ( ! empty( $attachment->post_mime_type ) ) { |
3596 $objects[] = 'attachment:' . $attachment->post_mime_type; |
3880 $objects[] = 'attachment:' . $attachment->post_mime_type; |
3597 |
3881 |
3598 if ( false !== strpos( $attachment->post_mime_type, '/' ) ) { |
3882 if ( str_contains( $attachment->post_mime_type, '/' ) ) { |
3599 foreach ( explode( '/', $attachment->post_mime_type ) as $token ) { |
3883 foreach ( explode( '/', $attachment->post_mime_type ) as $token ) { |
3600 if ( ! empty( $token ) ) { |
3884 if ( ! empty( $token ) ) { |
3601 $objects[] = "attachment:$token"; |
3885 $objects[] = "attachment:$token"; |
3602 } |
3886 } |
3603 } |
3887 } |
3637 function get_taxonomies_for_attachments( $output = 'names' ) { |
3921 function get_taxonomies_for_attachments( $output = 'names' ) { |
3638 $taxonomies = array(); |
3922 $taxonomies = array(); |
3639 |
3923 |
3640 foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy ) { |
3924 foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy ) { |
3641 foreach ( $taxonomy->object_type as $object_type ) { |
3925 foreach ( $taxonomy->object_type as $object_type ) { |
3642 if ( 'attachment' === $object_type || 0 === strpos( $object_type, 'attachment:' ) ) { |
3926 if ( 'attachment' === $object_type || str_starts_with( $object_type, 'attachment:' ) ) { |
3643 if ( 'names' === $output ) { |
3927 if ( 'names' === $output ) { |
3644 $taxonomies[] = $taxonomy->name; |
3928 $taxonomies[] = $taxonomy->name; |
3645 } else { |
3929 } else { |
3646 $taxonomies[ $taxonomy->name ] = $taxonomy; |
3930 $taxonomies[ $taxonomy->name ] = $taxonomy; |
3647 } |
3931 } |
3655 |
3939 |
3656 /** |
3940 /** |
3657 * Determines whether the value is an acceptable type for GD image functions. |
3941 * Determines whether the value is an acceptable type for GD image functions. |
3658 * |
3942 * |
3659 * In PHP 8.0, the GD extension uses GdImage objects for its data structures. |
3943 * In PHP 8.0, the GD extension uses GdImage objects for its data structures. |
3660 * This function checks if the passed value is either a resource of type `gd` |
3944 * This function checks if the passed value is either a GdImage object instance |
3661 * or a GdImage object instance. Any other type will return false. |
3945 * or a resource of type `gd`. Any other type will return false. |
3662 * |
3946 * |
3663 * @since 5.6.0 |
3947 * @since 5.6.0 |
3664 * |
3948 * |
3665 * @param resource|GdImage|false $image A value to check the type for. |
3949 * @param resource|GdImage|false $image A value to check the type for. |
3666 * @return bool True if $image is either a GD image resource or GdImage instance, |
3950 * @return bool True if `$image` is either a GD image resource or a GdImage instance, |
3667 * false otherwise. |
3951 * false otherwise. |
3668 */ |
3952 */ |
3669 function is_gd_image( $image ) { |
3953 function is_gd_image( $image ) { |
3670 if ( is_resource( $image ) && 'gd' === get_resource_type( $image ) |
3954 if ( $image instanceof GdImage |
3671 || is_object( $image ) && $image instanceof GdImage |
3955 || is_resource( $image ) && 'gd' === get_resource_type( $image ) |
3672 ) { |
3956 ) { |
3673 return true; |
3957 return true; |
3674 } |
3958 } |
3675 |
3959 |
3676 return false; |
3960 return false; |
3677 } |
3961 } |
3678 |
3962 |
3679 /** |
3963 /** |
3680 * Create new GD image resource with transparency support |
3964 * Creates a new GD image resource with transparency support. |
3681 * |
3965 * |
3682 * @todo Deprecate if possible. |
3966 * @todo Deprecate if possible. |
3683 * |
3967 * |
3684 * @since 2.9.0 |
3968 * @since 2.9.0 |
3685 * |
3969 * |
3700 |
3984 |
3701 return $img; |
3985 return $img; |
3702 } |
3986 } |
3703 |
3987 |
3704 /** |
3988 /** |
3705 * Based on a supplied width/height example, return the biggest possible dimensions based on the max width/height. |
3989 * Based on a supplied width/height example, returns the biggest possible dimensions based on the max width/height. |
3706 * |
3990 * |
3707 * @since 2.9.0 |
3991 * @since 2.9.0 |
3708 * |
3992 * |
3709 * @see wp_constrain_dimensions() |
3993 * @see wp_constrain_dimensions() |
3710 * |
3994 * |
3763 * a WP_Error object otherwise. |
4047 * a WP_Error object otherwise. |
3764 */ |
4048 */ |
3765 function wp_get_image_editor( $path, $args = array() ) { |
4049 function wp_get_image_editor( $path, $args = array() ) { |
3766 $args['path'] = $path; |
4050 $args['path'] = $path; |
3767 |
4051 |
4052 // If the mime type is not set in args, try to extract and set it from the file. |
|
3768 if ( ! isset( $args['mime_type'] ) ) { |
4053 if ( ! isset( $args['mime_type'] ) ) { |
3769 $file_info = wp_check_filetype( $args['path'] ); |
4054 $file_info = wp_check_filetype( $args['path'] ); |
3770 |
4055 |
3771 // If $file_info['type'] is false, then we let the editor attempt to |
4056 /* |
3772 // figure out the file type, rather than forcing a failure based on extension. |
4057 * If $file_info['type'] is false, then we let the editor attempt to |
4058 * figure out the file type, rather than forcing a failure based on extension. |
|
4059 */ |
|
3773 if ( isset( $file_info ) && $file_info['type'] ) { |
4060 if ( isset( $file_info ) && $file_info['type'] ) { |
3774 $args['mime_type'] = $file_info['type']; |
4061 $args['mime_type'] = $file_info['type']; |
4062 } |
|
4063 } |
|
4064 |
|
4065 // Check and set the output mime type mapped to the input type. |
|
4066 if ( isset( $args['mime_type'] ) ) { |
|
4067 /** This filter is documented in wp-includes/class-wp-image-editor.php */ |
|
4068 $output_format = apply_filters( 'image_editor_output_format', array(), $path, $args['mime_type'] ); |
|
4069 if ( isset( $output_format[ $args['mime_type'] ] ) ) { |
|
4070 $args['output_mime_type'] = $output_format[ $args['mime_type'] ]; |
|
3775 } |
4071 } |
3776 } |
4072 } |
3777 |
4073 |
3778 $implementation = _wp_image_editor_choose( $args ); |
4074 $implementation = _wp_image_editor_choose( $args ); |
3779 |
4075 |
3816 */ |
4112 */ |
3817 function _wp_image_editor_choose( $args = array() ) { |
4113 function _wp_image_editor_choose( $args = array() ) { |
3818 require_once ABSPATH . WPINC . '/class-wp-image-editor.php'; |
4114 require_once ABSPATH . WPINC . '/class-wp-image-editor.php'; |
3819 require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php'; |
4115 require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php'; |
3820 require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php'; |
4116 require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php'; |
4117 require_once ABSPATH . WPINC . '/class-avif-info.php'; |
|
3821 /** |
4118 /** |
3822 * Filters the list of image editing library classes. |
4119 * Filters the list of image editing library classes. |
3823 * |
4120 * |
3824 * @since 3.5.0 |
4121 * @since 3.5.0 |
3825 * |
4122 * |
3826 * @param string[] $image_editors Array of available image editor class names. Defaults are |
4123 * @param string[] $image_editors Array of available image editor class names. Defaults are |
3827 * 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD'. |
4124 * 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD'. |
3828 */ |
4125 */ |
3829 $implementations = apply_filters( 'wp_image_editors', array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) ); |
4126 $implementations = apply_filters( 'wp_image_editors', array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) ); |
4127 $supports_input = false; |
|
3830 |
4128 |
3831 foreach ( $implementations as $implementation ) { |
4129 foreach ( $implementations as $implementation ) { |
3832 if ( ! call_user_func( array( $implementation, 'test' ), $args ) ) { |
4130 if ( ! call_user_func( array( $implementation, 'test' ), $args ) ) { |
3833 continue; |
4131 continue; |
3834 } |
4132 } |
3835 |
4133 |
4134 // Implementation should support the passed mime type. |
|
3836 if ( isset( $args['mime_type'] ) && |
4135 if ( isset( $args['mime_type'] ) && |
3837 ! call_user_func( |
4136 ! call_user_func( |
3838 array( $implementation, 'supports_mime_type' ), |
4137 array( $implementation, 'supports_mime_type' ), |
3839 $args['mime_type'] |
4138 $args['mime_type'] |
3840 ) ) { |
4139 ) ) { |
3841 continue; |
4140 continue; |
3842 } |
4141 } |
3843 |
4142 |
4143 // Implementation should support requested methods. |
|
3844 if ( isset( $args['methods'] ) && |
4144 if ( isset( $args['methods'] ) && |
3845 array_diff( $args['methods'], get_class_methods( $implementation ) ) ) { |
4145 array_diff( $args['methods'], get_class_methods( $implementation ) ) ) { |
3846 |
4146 |
3847 continue; |
4147 continue; |
3848 } |
4148 } |
3849 |
4149 |
4150 // Implementation should ideally support the output mime type as well if set and different than the passed type. |
|
4151 if ( |
|
4152 isset( $args['mime_type'] ) && |
|
4153 isset( $args['output_mime_type'] ) && |
|
4154 $args['mime_type'] !== $args['output_mime_type'] && |
|
4155 ! call_user_func( array( $implementation, 'supports_mime_type' ), $args['output_mime_type'] ) |
|
4156 ) { |
|
4157 /* |
|
4158 * This implementation supports the input type but not the output type. |
|
4159 * Keep looking to see if we can find an implementation that supports both. |
|
4160 */ |
|
4161 $supports_input = $implementation; |
|
4162 continue; |
|
4163 } |
|
4164 |
|
4165 // Favor the implementation that supports both input and output mime types. |
|
3850 return $implementation; |
4166 return $implementation; |
3851 } |
4167 } |
3852 |
4168 |
3853 return false; |
4169 return $supports_input; |
3854 } |
4170 } |
3855 |
4171 |
3856 /** |
4172 /** |
3857 * Prints default Plupload arguments. |
4173 * Prints default Plupload arguments. |
3858 * |
4174 * |
3860 */ |
4176 */ |
3861 function wp_plupload_default_settings() { |
4177 function wp_plupload_default_settings() { |
3862 $wp_scripts = wp_scripts(); |
4178 $wp_scripts = wp_scripts(); |
3863 |
4179 |
3864 $data = $wp_scripts->get_data( 'wp-plupload', 'data' ); |
4180 $data = $wp_scripts->get_data( 'wp-plupload', 'data' ); |
3865 if ( $data && false !== strpos( $data, '_wpPluploadSettings' ) ) { |
4181 if ( $data && str_contains( $data, '_wpPluploadSettings' ) ) { |
3866 return; |
4182 return; |
3867 } |
4183 } |
3868 |
4184 |
3869 $max_upload_size = wp_max_upload_size(); |
4185 $max_upload_size = wp_max_upload_size(); |
3870 $allowed_extensions = array_keys( get_allowed_mime_types() ); |
4186 $allowed_extensions = array_keys( get_allowed_mime_types() ); |
3889 /* |
4205 /* |
3890 * Currently only iOS Safari supports multiple files uploading, |
4206 * Currently only iOS Safari supports multiple files uploading, |
3891 * but iOS 7.x has a bug that prevents uploading of videos when enabled. |
4207 * but iOS 7.x has a bug that prevents uploading of videos when enabled. |
3892 * See #29602. |
4208 * See #29602. |
3893 */ |
4209 */ |
3894 if ( wp_is_mobile() && strpos( $_SERVER['HTTP_USER_AGENT'], 'OS 7_' ) !== false && |
4210 if ( wp_is_mobile() |
3895 strpos( $_SERVER['HTTP_USER_AGENT'], 'like Mac OS X' ) !== false ) { |
4211 && str_contains( $_SERVER['HTTP_USER_AGENT'], 'OS 7_' ) |
3896 |
4212 && str_contains( $_SERVER['HTTP_USER_AGENT'], 'like Mac OS X' ) |
4213 ) { |
|
3897 $defaults['multi_selection'] = false; |
4214 $defaults['multi_selection'] = false; |
3898 } |
4215 } |
3899 |
4216 |
3900 // Check if WebP images can be edited. |
4217 // Check if WebP images can be edited. |
3901 if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { |
4218 if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { |
3902 $defaults['webp_upload_error'] = true; |
4219 $defaults['webp_upload_error'] = true; |
4220 } |
|
4221 |
|
4222 // Check if AVIF images can be edited. |
|
4223 if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) { |
|
4224 $defaults['avif_upload_error'] = true; |
|
3903 } |
4225 } |
3904 |
4226 |
3905 /** |
4227 /** |
3906 * Filters the Plupload default settings. |
4228 * Filters the Plupload default settings. |
3907 * |
4229 * |
4005 if ( 'attachment' !== $attachment->post_type ) { |
4327 if ( 'attachment' !== $attachment->post_type ) { |
4006 return; |
4328 return; |
4007 } |
4329 } |
4008 |
4330 |
4009 $meta = wp_get_attachment_metadata( $attachment->ID ); |
4331 $meta = wp_get_attachment_metadata( $attachment->ID ); |
4010 if ( false !== strpos( $attachment->post_mime_type, '/' ) ) { |
4332 if ( str_contains( $attachment->post_mime_type, '/' ) ) { |
4011 list( $type, $subtype ) = explode( '/', $attachment->post_mime_type ); |
4333 list( $type, $subtype ) = explode( '/', $attachment->post_mime_type ); |
4012 } else { |
4334 } else { |
4013 list( $type, $subtype ) = array( $attachment->post_mime_type, '' ); |
4335 list( $type, $subtype ) = array( $attachment->post_mime_type, '' ); |
4014 } |
4336 } |
4015 |
4337 |
4033 'modified' => strtotime( $attachment->post_modified_gmt ) * 1000, |
4355 'modified' => strtotime( $attachment->post_modified_gmt ) * 1000, |
4034 'menuOrder' => $attachment->menu_order, |
4356 'menuOrder' => $attachment->menu_order, |
4035 'mime' => $attachment->post_mime_type, |
4357 'mime' => $attachment->post_mime_type, |
4036 'type' => $type, |
4358 'type' => $type, |
4037 'subtype' => $subtype, |
4359 'subtype' => $subtype, |
4038 'icon' => wp_mime_type_icon( $attachment->ID ), |
4360 'icon' => wp_mime_type_icon( $attachment->ID, '.svg' ), |
4039 'dateFormatted' => mysql2date( __( 'F j, Y' ), $attachment->post_date ), |
4361 'dateFormatted' => mysql2date( __( 'F j, Y' ), $attachment->post_date ), |
4040 'nonces' => array( |
4362 'nonces' => array( |
4041 'update' => false, |
4363 'update' => false, |
4042 'delete' => false, |
4364 'delete' => false, |
4043 'edit' => false, |
4365 'edit' => false, |
4131 ); |
4453 ); |
4132 } elseif ( isset( $meta['sizes'][ $size ] ) ) { |
4454 } elseif ( isset( $meta['sizes'][ $size ] ) ) { |
4133 // Nothing from the filter, so consult image metadata if we have it. |
4455 // Nothing from the filter, so consult image metadata if we have it. |
4134 $size_meta = $meta['sizes'][ $size ]; |
4456 $size_meta = $meta['sizes'][ $size ]; |
4135 |
4457 |
4136 // We have the actual image size, but might need to further constrain it if content_width is narrower. |
4458 /* |
4137 // Thumbnail, medium, and full sizes are also checked against the site's height/width options. |
4459 * We have the actual image size, but might need to further constrain it if content_width is narrower. |
4460 * Thumbnail, medium, and full sizes are also checked against the site's height/width options. |
|
4461 */ |
|
4138 list( $width, $height ) = image_constrain_size_for_editor( $size_meta['width'], $size_meta['height'], $size, 'edit' ); |
4462 list( $width, $height ) = image_constrain_size_for_editor( $size_meta['width'], $size_meta['height'], $size, 'edit' ); |
4139 |
4463 |
4140 $sizes[ $size ] = array( |
4464 $sizes[ $size ] = array( |
4141 'height' => $height, |
4465 'height' => $height, |
4142 'width' => $width, |
4466 'width' => $width, |
4202 list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' ); |
4526 list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' ); |
4203 $response['image'] = compact( 'src', 'width', 'height' ); |
4527 $response['image'] = compact( 'src', 'width', 'height' ); |
4204 list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumbnail' ); |
4528 list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumbnail' ); |
4205 $response['thumb'] = compact( 'src', 'width', 'height' ); |
4529 $response['thumb'] = compact( 'src', 'width', 'height' ); |
4206 } else { |
4530 } else { |
4207 $src = wp_mime_type_icon( $attachment->ID ); |
4531 $src = wp_mime_type_icon( $attachment->ID, '.svg' ); |
4208 $width = 48; |
4532 $width = 48; |
4209 $height = 64; |
4533 $height = 64; |
4210 $response['image'] = compact( 'src', 'width', 'height' ); |
4534 $response['image'] = compact( 'src', 'width', 'height' ); |
4211 $response['thumb'] = compact( 'src', 'width', 'height' ); |
4535 $response['thumb'] = compact( 'src', 'width', 'height' ); |
4212 } |
4536 } |
4226 /** |
4550 /** |
4227 * Filters the attachment data prepared for JavaScript. |
4551 * Filters the attachment data prepared for JavaScript. |
4228 * |
4552 * |
4229 * @since 3.5.0 |
4553 * @since 3.5.0 |
4230 * |
4554 * |
4231 * @param array $response Array of prepared attachment data. @see wp_prepare_attachment_for_js(). |
4555 * @param array $response Array of prepared attachment data. See {@see wp_prepare_attachment_for_js()}. |
4232 * @param WP_Post $attachment Attachment object. |
4556 * @param WP_Post $attachment Attachment object. |
4233 * @param array|false $meta Array of attachment meta data, or false if there is none. |
4557 * @param array|false $meta Array of attachment meta data, or false if there is none. |
4234 */ |
4558 */ |
4235 return apply_filters( 'wp_prepare_attachment_for_js', $response, $attachment, $meta ); |
4559 return apply_filters( 'wp_prepare_attachment_for_js', $response, $attachment, $meta ); |
4236 } |
4560 } |
4246 * @global WP_Locale $wp_locale WordPress date and time locale object. |
4570 * @global WP_Locale $wp_locale WordPress date and time locale object. |
4247 * |
4571 * |
4248 * @param array $args { |
4572 * @param array $args { |
4249 * Arguments for enqueuing media scripts. |
4573 * Arguments for enqueuing media scripts. |
4250 * |
4574 * |
4251 * @type int|WP_Post $post A post object or ID. |
4575 * @type int|WP_Post $post Post ID or post object. |
4252 * } |
4576 * } |
4253 */ |
4577 */ |
4254 function wp_enqueue_media( $args = array() ) { |
4578 function wp_enqueue_media( $args = array() ) { |
4255 // Enqueue me just once per page, please. |
4579 // Enqueue me just once per page, please. |
4256 if ( did_action( 'wp_enqueue_media' ) ) { |
4580 if ( did_action( 'wp_enqueue_media' ) ) { |
4262 $defaults = array( |
4586 $defaults = array( |
4263 'post' => null, |
4587 'post' => null, |
4264 ); |
4588 ); |
4265 $args = wp_parse_args( $args, $defaults ); |
4589 $args = wp_parse_args( $args, $defaults ); |
4266 |
4590 |
4267 // We're going to pass the old thickbox media tabs to `media_upload_tabs` |
4591 /* |
4268 // to ensure plugins will work. We will then unset those tabs. |
4592 * We're going to pass the old thickbox media tabs to `media_upload_tabs` |
4593 * to ensure plugins will work. We will then unset those tabs. |
|
4594 */ |
|
4269 $tabs = array( |
4595 $tabs = array( |
4270 // handler action suffix => tab label |
4596 // handler action suffix => tab label |
4271 'type' => '', |
4597 'type' => '', |
4272 'type_url' => '', |
4598 'type_url' => '', |
4273 'gallery' => '', |
4599 'gallery' => '', |
4314 * on whether any audio files exist in the media library. |
4640 * on whether any audio files exist in the media library. |
4315 */ |
4641 */ |
4316 $show_audio_playlist = apply_filters( 'media_library_show_audio_playlist', true ); |
4642 $show_audio_playlist = apply_filters( 'media_library_show_audio_playlist', true ); |
4317 if ( null === $show_audio_playlist ) { |
4643 if ( null === $show_audio_playlist ) { |
4318 $show_audio_playlist = $wpdb->get_var( |
4644 $show_audio_playlist = $wpdb->get_var( |
4319 " |
4645 "SELECT ID |
4320 SELECT ID |
|
4321 FROM $wpdb->posts |
4646 FROM $wpdb->posts |
4322 WHERE post_type = 'attachment' |
4647 WHERE post_type = 'attachment' |
4323 AND post_mime_type LIKE 'audio%' |
4648 AND post_mime_type LIKE 'audio%' |
4324 LIMIT 1 |
4649 LIMIT 1" |
4325 " |
|
4326 ); |
4650 ); |
4327 } |
4651 } |
4328 |
4652 |
4329 /** |
4653 /** |
4330 * Allows showing or hiding the "Create Video Playlist" button in the media library. |
4654 * Allows showing or hiding the "Create Video Playlist" button in the media library. |
4344 * on whether any video files exist in the media library. |
4668 * on whether any video files exist in the media library. |
4345 */ |
4669 */ |
4346 $show_video_playlist = apply_filters( 'media_library_show_video_playlist', true ); |
4670 $show_video_playlist = apply_filters( 'media_library_show_video_playlist', true ); |
4347 if ( null === $show_video_playlist ) { |
4671 if ( null === $show_video_playlist ) { |
4348 $show_video_playlist = $wpdb->get_var( |
4672 $show_video_playlist = $wpdb->get_var( |
4349 " |
4673 "SELECT ID |
4350 SELECT ID |
|
4351 FROM $wpdb->posts |
4674 FROM $wpdb->posts |
4352 WHERE post_type = 'attachment' |
4675 WHERE post_type = 'attachment' |
4353 AND post_mime_type LIKE 'video%' |
4676 AND post_mime_type LIKE 'video%' |
4354 LIMIT 1 |
4677 LIMIT 1" |
4355 " |
|
4356 ); |
4678 ); |
4357 } |
4679 } |
4358 |
4680 |
4359 /** |
4681 /** |
4360 * Allows overriding the list of months displayed in the media library. |
4682 * Allows overriding the list of months displayed in the media library. |
4366 * |
4688 * |
4367 * @since 4.7.4 |
4689 * @since 4.7.4 |
4368 * |
4690 * |
4369 * @link https://core.trac.wordpress.org/ticket/31071 |
4691 * @link https://core.trac.wordpress.org/ticket/31071 |
4370 * |
4692 * |
4371 * @param array|null $months An array of objects with `month` and `year` |
4693 * @param stdClass[]|null $months An array of objects with `month` and `year` |
4372 * properties, or `null` (or any other non-array value) |
4694 * properties, or `null` for default behavior. |
4373 * for default behavior. |
|
4374 */ |
4695 */ |
4375 $months = apply_filters( 'media_library_months_with_files', null ); |
4696 $months = apply_filters( 'media_library_months_with_files', null ); |
4376 if ( ! is_array( $months ) ) { |
4697 if ( ! is_array( $months ) ) { |
4377 $months = $wpdb->get_results( |
4698 $months = $wpdb->get_results( |
4378 $wpdb->prepare( |
4699 $wpdb->prepare( |
4379 " |
4700 "SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month |
4380 SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month |
4701 FROM $wpdb->posts |
4381 FROM $wpdb->posts |
4702 WHERE post_type = %s |
4382 WHERE post_type = %s |
4703 ORDER BY post_date DESC", |
4383 ORDER BY post_date DESC |
|
4384 ", |
|
4385 'attachment' |
4704 'attachment' |
4386 ) |
4705 ) |
4387 ); |
4706 ); |
4388 } |
4707 } |
4389 foreach ( $months as $month_year ) { |
4708 foreach ( $months as $month_year ) { |
4409 'tabUrl' => add_query_arg( array( 'chromeless' => true ), admin_url( 'media-upload.php' ) ), |
4728 'tabUrl' => add_query_arg( array( 'chromeless' => true ), admin_url( 'media-upload.php' ) ), |
4410 'mimeTypes' => wp_list_pluck( get_post_mime_types(), 0 ), |
4729 'mimeTypes' => wp_list_pluck( get_post_mime_types(), 0 ), |
4411 /** This filter is documented in wp-admin/includes/media.php */ |
4730 /** This filter is documented in wp-admin/includes/media.php */ |
4412 'captions' => ! apply_filters( 'disable_captions', '' ), |
4731 'captions' => ! apply_filters( 'disable_captions', '' ), |
4413 'nonce' => array( |
4732 'nonce' => array( |
4414 'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ), |
4733 'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ), |
4734 'setAttachmentThumbnail' => wp_create_nonce( 'set-attachment-thumbnail' ), |
|
4415 ), |
4735 ), |
4416 'post' => array( |
4736 'post' => array( |
4417 'id' => 0, |
4737 'id' => 0, |
4418 ), |
4738 ), |
4419 'defaultProps' => $props, |
4739 'defaultProps' => $props, |
4507 'deletePermanently' => __( 'Delete permanently' ), |
4827 'deletePermanently' => __( 'Delete permanently' ), |
4508 'errorDeleting' => __( 'Error in deleting the attachment.' ), |
4828 'errorDeleting' => __( 'Error in deleting the attachment.' ), |
4509 'apply' => __( 'Apply' ), |
4829 'apply' => __( 'Apply' ), |
4510 'filterByDate' => __( 'Filter by date' ), |
4830 'filterByDate' => __( 'Filter by date' ), |
4511 'filterByType' => __( 'Filter by type' ), |
4831 'filterByType' => __( 'Filter by type' ), |
4512 'searchLabel' => __( 'Search' ), |
4832 'searchLabel' => __( 'Search media' ), |
4513 'searchMediaLabel' => __( 'Search media' ), // Backward compatibility pre-5.3. |
4833 'searchMediaLabel' => __( 'Search media' ), // Backward compatibility pre-5.3. |
4514 'searchMediaPlaceholder' => __( 'Search media items...' ), // Placeholder (no ellipsis), backward compatibility pre-5.3. |
4834 'searchMediaPlaceholder' => __( 'Search media items...' ), // Placeholder (no ellipsis), backward compatibility pre-5.3. |
4515 /* translators: %d: Number of attachments found in a search. */ |
4835 /* translators: %d: Number of attachments found in a search. */ |
4516 'mediaFound' => __( 'Number of media items found: %d' ), |
4836 'mediaFound' => __( 'Number of media items found: %d' ), |
4517 'noMedia' => __( 'No media items found.' ), |
4837 'noMedia' => __( 'No media items found.' ), |
4613 */ |
4933 */ |
4614 $strings = apply_filters( 'media_view_strings', $strings, $post ); |
4934 $strings = apply_filters( 'media_view_strings', $strings, $post ); |
4615 |
4935 |
4616 $strings['settings'] = $settings; |
4936 $strings['settings'] = $settings; |
4617 |
4937 |
4618 // Ensure we enqueue media-editor first, that way media-views |
4938 /* |
4619 // is registered internally before we try to localize it. See #24724. |
4939 * Ensure we enqueue media-editor first, that way media-views |
4940 * is registered internally before we try to localize it. See #24724. |
|
4941 */ |
|
4620 wp_enqueue_script( 'media-editor' ); |
4942 wp_enqueue_script( 'media-editor' ); |
4621 wp_localize_script( 'media-views', '_wpMediaViewsL10n', $strings ); |
4943 wp_localize_script( 'media-views', '_wpMediaViewsL10n', $strings ); |
4622 |
4944 |
4623 wp_enqueue_script( 'media-audiovideo' ); |
4945 wp_enqueue_script( 'media-audiovideo' ); |
4624 wp_enqueue_style( 'media-views' ); |
4946 wp_enqueue_style( 'media-views' ); |
4691 */ |
5013 */ |
4692 return (array) apply_filters( 'get_attached_media', $children, $type, $post ); |
5014 return (array) apply_filters( 'get_attached_media', $children, $type, $post ); |
4693 } |
5015 } |
4694 |
5016 |
4695 /** |
5017 /** |
4696 * Check the content HTML for a audio, video, object, embed, or iframe tags. |
5018 * Checks the HTML content for an audio, video, object, embed, or iframe tags. |
4697 * |
5019 * |
4698 * @since 3.6.0 |
5020 * @since 3.6.0 |
4699 * |
5021 * |
4700 * @param string $content A string of HTML which might contain media elements. |
5022 * @param string $content A string of HTML which might contain media elements. |
4701 * @param string[] $types An array of media types: 'audio', 'video', 'object', 'embed', or 'iframe'. |
5023 * @param string[] $types An array of media types: 'audio', 'video', 'object', 'embed', or 'iframe'. |
4759 foreach ( $matches as $shortcode ) { |
5081 foreach ( $matches as $shortcode ) { |
4760 if ( 'gallery' === $shortcode[2] ) { |
5082 if ( 'gallery' === $shortcode[2] ) { |
4761 $srcs = array(); |
5083 $srcs = array(); |
4762 |
5084 |
4763 $shortcode_attrs = shortcode_parse_atts( $shortcode[3] ); |
5085 $shortcode_attrs = shortcode_parse_atts( $shortcode[3] ); |
4764 if ( ! is_array( $shortcode_attrs ) ) { |
|
4765 $shortcode_attrs = array(); |
|
4766 } |
|
4767 |
5086 |
4768 // Specify the post ID of the gallery we're viewing if the shortcode doesn't reference another post already. |
5087 // Specify the post ID of the gallery we're viewing if the shortcode doesn't reference another post already. |
4769 if ( ! isset( $shortcode_attrs['id'] ) ) { |
5088 if ( ! isset( $shortcode_attrs['id'] ) ) { |
4770 $shortcode[3] .= ' id="' . (int) $post->ID . '"'; |
5089 $shortcode[3] .= ' id="' . (int) $post->ID . '"'; |
4771 } |
5090 } |
4894 */ |
5213 */ |
4895 return apply_filters( 'get_post_galleries', $galleries, $post ); |
5214 return apply_filters( 'get_post_galleries', $galleries, $post ); |
4896 } |
5215 } |
4897 |
5216 |
4898 /** |
5217 /** |
4899 * Check a specified post's content for gallery and, if present, return the first |
5218 * Checks a specified post's content for gallery and, if present, return the first |
4900 * |
5219 * |
4901 * @since 3.6.0 |
5220 * @since 3.6.0 |
4902 * |
5221 * |
4903 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. |
5222 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. |
4904 * @param bool $html Optional. Whether to return HTML or data. Default is true. |
5223 * @param bool $html Optional. Whether to return HTML or data. Default is true. |
4919 */ |
5238 */ |
4920 return apply_filters( 'get_post_gallery', $gallery, $post, $galleries ); |
5239 return apply_filters( 'get_post_gallery', $gallery, $post, $galleries ); |
4921 } |
5240 } |
4922 |
5241 |
4923 /** |
5242 /** |
4924 * Retrieve the image srcs from galleries from a post's content, if present |
5243 * Retrieves the image srcs from galleries from a post's content, if present. |
4925 * |
5244 * |
4926 * @since 3.6.0 |
5245 * @since 3.6.0 |
4927 * |
5246 * |
4928 * @see get_post_galleries() |
5247 * @see get_post_galleries() |
4929 * |
5248 * |
4935 $galleries = get_post_galleries( $post, false ); |
5254 $galleries = get_post_galleries( $post, false ); |
4936 return wp_list_pluck( $galleries, 'src' ); |
5255 return wp_list_pluck( $galleries, 'src' ); |
4937 } |
5256 } |
4938 |
5257 |
4939 /** |
5258 /** |
4940 * Checks a post's content for galleries and return the image srcs for the first found gallery |
5259 * Checks a post's content for galleries and return the image srcs for the first found gallery. |
4941 * |
5260 * |
4942 * @since 3.6.0 |
5261 * @since 3.6.0 |
4943 * |
5262 * |
4944 * @see get_post_gallery() |
5263 * @see get_post_gallery() |
4945 * |
5264 * |
5001 // Force the protocols to match if needed. |
5320 // Force the protocols to match if needed. |
5002 if ( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) { |
5321 if ( isset( $image_path['scheme'] ) && ( $image_path['scheme'] !== $site_url['scheme'] ) ) { |
5003 $path = str_replace( $image_path['scheme'], $site_url['scheme'], $path ); |
5322 $path = str_replace( $image_path['scheme'], $site_url['scheme'], $path ); |
5004 } |
5323 } |
5005 |
5324 |
5006 if ( 0 === strpos( $path, $dir['baseurl'] . '/' ) ) { |
5325 if ( str_starts_with( $path, $dir['baseurl'] . '/' ) ) { |
5007 $path = substr( $path, strlen( $dir['baseurl'] . '/' ) ); |
5326 $path = substr( $path, strlen( $dir['baseurl'] . '/' ) ); |
5008 } |
5327 } |
5009 |
5328 |
5010 $sql = $wpdb->prepare( |
5329 $sql = $wpdb->prepare( |
5011 "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s", |
5330 "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '_wp_attached_file' AND meta_value = %s", |
5074 * Finds and exports attachments associated with an email address. |
5393 * Finds and exports attachments associated with an email address. |
5075 * |
5394 * |
5076 * @since 4.9.6 |
5395 * @since 4.9.6 |
5077 * |
5396 * |
5078 * @param string $email_address The attachment owner email address. |
5397 * @param string $email_address The attachment owner email address. |
5079 * @param int $page Attachment page. |
5398 * @param int $page Attachment page number. |
5080 * @return array An array of personal data. |
5399 * @return array { |
5400 * An array of personal data. |
|
5401 * |
|
5402 * @type array[] $data An array of personal data arrays. |
|
5403 * @type bool $done Whether the exporter is finished. |
|
5404 * } |
|
5081 */ |
5405 */ |
5082 function wp_media_personal_data_exporter( $email_address, $page = 1 ) { |
5406 function wp_media_personal_data_exporter( $email_address, $page = 1 ) { |
5083 // Limit us to 50 attachments at a time to avoid timing out. |
5407 // Limit us to 50 attachments at a time to avoid timing out. |
5084 $number = 50; |
5408 $number = 50; |
5085 $page = (int) $page; |
5409 $page = (int) $page; |
5134 'done' => $done, |
5458 'done' => $done, |
5135 ); |
5459 ); |
5136 } |
5460 } |
5137 |
5461 |
5138 /** |
5462 /** |
5139 * Add additional default image sub-sizes. |
5463 * Adds additional default image sub-sizes. |
5140 * |
5464 * |
5141 * These sizes are meant to enhance the way WordPress displays images on the front-end on larger, |
5465 * These sizes are meant to enhance the way WordPress displays images on the front-end on larger, |
5142 * high-density devices. They make it possible to generate more suitable `srcset` and `sizes` attributes |
5466 * high-density devices. They make it possible to generate more suitable `srcset` and `sizes` attributes |
5143 * when the users upload large images. |
5467 * when the users upload large images. |
5144 * |
5468 * |
5171 /** |
5495 /** |
5172 * Allows PHP's getimagesize() to be debuggable when necessary. |
5496 * Allows PHP's getimagesize() to be debuggable when necessary. |
5173 * |
5497 * |
5174 * @since 5.7.0 |
5498 * @since 5.7.0 |
5175 * @since 5.8.0 Added support for WebP images. |
5499 * @since 5.8.0 Added support for WebP images. |
5500 * @since 6.5.0 Added support for AVIF images. |
|
5176 * |
5501 * |
5177 * @param string $filename The file path. |
5502 * @param string $filename The file path. |
5178 * @param array $image_info Optional. Extended image information (passed by reference). |
5503 * @param array $image_info Optional. Extended image information (passed by reference). |
5179 * @return array|false Array of image information or false on failure. |
5504 * @return array|false Array of image information or false on failure. |
5180 */ |
5505 */ |
5181 function wp_getimagesize( $filename, array &$image_info = null ) { |
5506 function wp_getimagesize( $filename, ?array &$image_info = null ) { |
5182 // Don't silence errors when in debug mode, unless running unit tests. |
5507 // Don't silence errors when in debug mode, unless running unit tests. |
5183 if ( defined( 'WP_DEBUG' ) && WP_DEBUG |
5508 if ( defined( 'WP_DEBUG' ) && WP_DEBUG |
5184 && ! defined( 'WP_RUN_CORE_TESTS' ) |
5509 && ! defined( 'WP_RUN_CORE_TESTS' ) |
5185 ) { |
5510 ) { |
5186 if ( 2 === func_num_args() ) { |
5511 if ( 2 === func_num_args() ) { |
5197 * even when it's able to provide image size information. |
5522 * even when it's able to provide image size information. |
5198 * |
5523 * |
5199 * See https://core.trac.wordpress.org/ticket/42480 |
5524 * See https://core.trac.wordpress.org/ticket/42480 |
5200 */ |
5525 */ |
5201 if ( 2 === func_num_args() ) { |
5526 if ( 2 === func_num_args() ) { |
5202 // phpcs:ignore WordPress.PHP.NoSilencedErrors |
|
5203 $info = @getimagesize( $filename, $image_info ); |
5527 $info = @getimagesize( $filename, $image_info ); |
5204 } else { |
5528 } else { |
5205 // phpcs:ignore WordPress.PHP.NoSilencedErrors |
|
5206 $info = @getimagesize( $filename ); |
5529 $info = @getimagesize( $filename ); |
5207 } |
5530 } |
5208 } |
5531 } |
5209 |
5532 |
5210 if ( false !== $info ) { |
5533 if ( |
5534 ! empty( $info ) && |
|
5535 // Some PHP versions return 0x0 sizes from `getimagesize` for unrecognized image formats, including AVIFs. |
|
5536 ! ( empty( $info[0] ) && empty( $info[1] ) ) |
|
5537 ) { |
|
5211 return $info; |
5538 return $info; |
5212 } |
5539 } |
5213 |
5540 |
5214 // For PHP versions that don't support WebP images, |
5541 /* |
5215 // extract the image size info from the file headers. |
5542 * For PHP versions that don't support WebP images, |
5543 * extract the image size info from the file headers. |
|
5544 */ |
|
5216 if ( 'image/webp' === wp_get_image_mime( $filename ) ) { |
5545 if ( 'image/webp' === wp_get_image_mime( $filename ) ) { |
5217 $webp_info = wp_get_webp_info( $filename ); |
5546 $webp_info = wp_get_webp_info( $filename ); |
5218 $width = $webp_info['width']; |
5547 $width = $webp_info['width']; |
5219 $height = $webp_info['height']; |
5548 $height = $webp_info['height']; |
5220 |
5549 |
5232 'mime' => 'image/webp', |
5561 'mime' => 'image/webp', |
5233 ); |
5562 ); |
5234 } |
5563 } |
5235 } |
5564 } |
5236 |
5565 |
5566 // For PHP versions that don't support AVIF images, extract the image size info from the file headers. |
|
5567 if ( 'image/avif' === wp_get_image_mime( $filename ) ) { |
|
5568 $avif_info = wp_get_avif_info( $filename ); |
|
5569 |
|
5570 $width = $avif_info['width']; |
|
5571 $height = $avif_info['height']; |
|
5572 |
|
5573 // Mimic the native return format. |
|
5574 if ( $width && $height ) { |
|
5575 return array( |
|
5576 $width, |
|
5577 $height, |
|
5578 IMAGETYPE_AVIF, |
|
5579 sprintf( |
|
5580 'width="%d" height="%d"', |
|
5581 $width, |
|
5582 $height |
|
5583 ), |
|
5584 'mime' => 'image/avif', |
|
5585 ); |
|
5586 } |
|
5587 } |
|
5588 |
|
5237 // The image could not be parsed. |
5589 // The image could not be parsed. |
5238 return false; |
5590 return false; |
5591 } |
|
5592 |
|
5593 /** |
|
5594 * Extracts meta information about an AVIF file: width, height, bit depth, and number of channels. |
|
5595 * |
|
5596 * @since 6.5.0 |
|
5597 * |
|
5598 * @param string $filename Path to an AVIF file. |
|
5599 * @return array { |
|
5600 * An array of AVIF image information. |
|
5601 * |
|
5602 * @type int|false $width Image width on success, false on failure. |
|
5603 * @type int|false $height Image height on success, false on failure. |
|
5604 * @type int|false $bit_depth Image bit depth on success, false on failure. |
|
5605 * @type int|false $num_channels Image number of channels on success, false on failure. |
|
5606 * } |
|
5607 */ |
|
5608 function wp_get_avif_info( $filename ) { |
|
5609 $results = array( |
|
5610 'width' => false, |
|
5611 'height' => false, |
|
5612 'bit_depth' => false, |
|
5613 'num_channels' => false, |
|
5614 ); |
|
5615 |
|
5616 if ( 'image/avif' !== wp_get_image_mime( $filename ) ) { |
|
5617 return $results; |
|
5618 } |
|
5619 |
|
5620 // Parse the file using libavifinfo's PHP implementation. |
|
5621 require_once ABSPATH . WPINC . '/class-avif-info.php'; |
|
5622 |
|
5623 $handle = fopen( $filename, 'rb' ); |
|
5624 if ( $handle ) { |
|
5625 $parser = new Avifinfo\Parser( $handle ); |
|
5626 $success = $parser->parse_ftyp() && $parser->parse_file(); |
|
5627 fclose( $handle ); |
|
5628 if ( $success ) { |
|
5629 $results = $parser->features->primary_item_features; |
|
5630 } |
|
5631 } |
|
5632 return $results; |
|
5239 } |
5633 } |
5240 |
5634 |
5241 /** |
5635 /** |
5242 * Extracts meta information about a WebP file: width, height, and type. |
5636 * Extracts meta information about a WebP file: width, height, and type. |
5243 * |
5637 * |
5271 // Make sure we got enough bytes. |
5665 // Make sure we got enough bytes. |
5272 if ( strlen( $magic ) < 40 ) { |
5666 if ( strlen( $magic ) < 40 ) { |
5273 return compact( 'width', 'height', 'type' ); |
5667 return compact( 'width', 'height', 'type' ); |
5274 } |
5668 } |
5275 |
5669 |
5276 // The headers are a little different for each of the three formats. |
5670 /* |
5277 // Header values based on WebP docs, see https://developers.google.com/speed/webp/docs/riff_container. |
5671 * The headers are a little different for each of the three formats. |
5672 * Header values based on WebP docs, see https://developers.google.com/speed/webp/docs/riff_container. |
|
5673 */ |
|
5278 switch ( substr( $magic, 12, 4 ) ) { |
5674 switch ( substr( $magic, 12, 4 ) ) { |
5279 // Lossy WebP. |
5675 // Lossy WebP. |
5280 case 'VP8 ': |
5676 case 'VP8 ': |
5281 $parts = unpack( 'v2', substr( $magic, 26, 4 ) ); |
5677 $parts = unpack( 'v2', substr( $magic, 26, 4 ) ); |
5282 $width = (int) ( $parts[1] & 0x3FFF ); |
5678 $width = (int) ( $parts[1] & 0x3FFF ); |
5304 |
5700 |
5305 return compact( 'width', 'height', 'type' ); |
5701 return compact( 'width', 'height', 'type' ); |
5306 } |
5702 } |
5307 |
5703 |
5308 /** |
5704 /** |
5309 * Gets the default value to use for a `loading` attribute on an element. |
5705 * Gets loading optimization attributes. |
5310 * |
5706 * |
5311 * This function should only be called for a tag and context if lazy-loading is generally enabled. |
5707 * This function returns an array of attributes that should be merged into the given attributes array to optimize |
5312 * |
5708 * loading performance. Potential attributes returned by this function are: |
5313 * The function usually returns 'lazy', but uses certain heuristics to guess whether the current element is likely to |
5709 * - `loading` attribute with a value of "lazy" |
5314 * appear above the fold, in which case it returns a boolean `false`, which will lead to the `loading` attribute being |
5710 * - `fetchpriority` attribute with a value of "high" |
5315 * omitted on the element. The purpose of this refinement is to avoid lazy-loading elements that are within the initial |
5711 * - `decoding` attribute with a value of "async" |
5316 * viewport, which can have a negative performance impact. |
5712 * |
5317 * |
5713 * If any of these attributes are already present in the given attributes, they will not be modified. Note that no |
5318 * Under the hood, the function uses {@see wp_increase_content_media_count()} every time it is called for an element |
5714 * element should have both `loading="lazy"` and `fetchpriority="high"`, so the function will trigger a warning in case |
5319 * within the main content. If the element is the very first content element, the `loading` attribute will be omitted. |
5715 * both attributes are present with those values. |
5320 * This default threshold of 1 content element to omit the `loading` attribute for can be customized using the |
5716 * |
5321 * {@see 'wp_omit_loading_attr_threshold'} filter. |
5717 * @since 6.3.0 |
5322 * |
5718 * |
5323 * @since 5.9.0 |
5719 * @global WP_Query $wp_query WordPress Query object. |
5324 * |
5720 * |
5325 * @param string $context Context for the element for which the `loading` attribute value is requested. |
5721 * @param string $tag_name The tag name. |
5326 * @return string|bool The default `loading` attribute value. Either 'lazy', 'eager', or a boolean `false`, to indicate |
5722 * @param array $attr Array of the attributes for the tag. |
5327 * that the `loading` attribute should be skipped. |
5723 * @param string $context Context for the element for which the loading optimization attribute is requested. |
5328 */ |
5724 * @return array Loading optimization attributes. |
5329 function wp_get_loading_attr_default( $context ) { |
5725 */ |
5330 // Only elements with 'the_content' or 'the_post_thumbnail' context have special handling. |
5726 function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) { |
5331 if ( 'the_content' !== $context && 'the_post_thumbnail' !== $context ) { |
5727 global $wp_query; |
5332 return 'lazy'; |
5728 |
5333 } |
5729 /** |
5334 |
5730 * Filters whether to short-circuit loading optimization attributes. |
5335 // Only elements within the main query loop have special handling. |
5731 * |
5336 if ( is_admin() || ! in_the_loop() || ! is_main_query() ) { |
5732 * Returning an array from the filter will effectively short-circuit the loading of optimization attributes, |
5337 return 'lazy'; |
5733 * returning that value instead. |
5338 } |
5734 * |
5339 |
5735 * @since 6.4.0 |
5340 // Increase the counter since this is a main query content element. |
5736 * |
5341 $content_media_count = wp_increase_content_media_count(); |
5737 * @param array|false $loading_attrs False by default, or array of loading optimization attributes to short-circuit. |
5342 |
5738 * @param string $tag_name The tag name. |
5343 // If the count so far is below the threshold, return `false` so that the `loading` attribute is omitted. |
5739 * @param array $attr Array of the attributes for the tag. |
5344 if ( $content_media_count <= wp_omit_loading_attr_threshold() ) { |
5740 * @param string $context Context for the element for which the loading optimization attribute is requested. |
5345 return false; |
5741 */ |
5346 } |
5742 $loading_attrs = apply_filters( 'pre_wp_get_loading_optimization_attributes', false, $tag_name, $attr, $context ); |
5347 |
5743 |
5348 // For elements after the threshold, lazy-load them as usual. |
5744 if ( is_array( $loading_attrs ) ) { |
5349 return 'lazy'; |
5745 return $loading_attrs; |
5746 } |
|
5747 |
|
5748 $loading_attrs = array(); |
|
5749 |
|
5750 /* |
|
5751 * Skip lazy-loading for the overall block template, as it is handled more granularly. |
|
5752 * The skip is also applicable for `fetchpriority`. |
|
5753 */ |
|
5754 if ( 'template' === $context ) { |
|
5755 /** This filter is documented in wp-includes/media.php */ |
|
5756 return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context ); |
|
5757 } |
|
5758 |
|
5759 // For now this function only supports images and iframes. |
|
5760 if ( 'img' !== $tag_name && 'iframe' !== $tag_name ) { |
|
5761 /** This filter is documented in wp-includes/media.php */ |
|
5762 return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context ); |
|
5763 } |
|
5764 |
|
5765 /* |
|
5766 * Skip programmatically created images within content blobs as they need to be handled together with the other |
|
5767 * images within the post content or widget content. |
|
5768 * Without this clause, they would already be considered within their own context which skews the image count and |
|
5769 * can result in the first post content image being lazy-loaded or an image further down the page being marked as a |
|
5770 * high priority. |
|
5771 */ |
|
5772 if ( |
|
5773 'the_content' !== $context && doing_filter( 'the_content' ) || |
|
5774 'widget_text_content' !== $context && doing_filter( 'widget_text_content' ) || |
|
5775 'widget_block_content' !== $context && doing_filter( 'widget_block_content' ) |
|
5776 ) { |
|
5777 /** This filter is documented in wp-includes/media.php */ |
|
5778 return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context ); |
|
5779 |
|
5780 } |
|
5781 |
|
5782 /* |
|
5783 * Add `decoding` with a value of "async" for every image unless it has a |
|
5784 * conflicting `decoding` attribute already present. |
|
5785 */ |
|
5786 if ( 'img' === $tag_name ) { |
|
5787 if ( isset( $attr['decoding'] ) ) { |
|
5788 $loading_attrs['decoding'] = $attr['decoding']; |
|
5789 } else { |
|
5790 $loading_attrs['decoding'] = 'async'; |
|
5791 } |
|
5792 } |
|
5793 |
|
5794 // For any resources, width and height must be provided, to avoid layout shifts. |
|
5795 if ( ! isset( $attr['width'], $attr['height'] ) ) { |
|
5796 /** This filter is documented in wp-includes/media.php */ |
|
5797 return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context ); |
|
5798 } |
|
5799 |
|
5800 /* |
|
5801 * The key function logic starts here. |
|
5802 */ |
|
5803 $maybe_in_viewport = null; |
|
5804 $increase_count = false; |
|
5805 $maybe_increase_count = false; |
|
5806 |
|
5807 // Logic to handle a `loading` attribute that is already provided. |
|
5808 if ( isset( $attr['loading'] ) ) { |
|
5809 /* |
|
5810 * Interpret "lazy" as not in viewport. Any other value can be |
|
5811 * interpreted as in viewport (realistically only "eager" or `false` |
|
5812 * to force-omit the attribute are other potential values). |
|
5813 */ |
|
5814 if ( 'lazy' === $attr['loading'] ) { |
|
5815 $maybe_in_viewport = false; |
|
5816 } else { |
|
5817 $maybe_in_viewport = true; |
|
5818 } |
|
5819 } |
|
5820 |
|
5821 // Logic to handle a `fetchpriority` attribute that is already provided. |
|
5822 if ( isset( $attr['fetchpriority'] ) && 'high' === $attr['fetchpriority'] ) { |
|
5823 /* |
|
5824 * If the image was already determined to not be in the viewport (e.g. |
|
5825 * from an already provided `loading` attribute), trigger a warning. |
|
5826 * Otherwise, the value can be interpreted as in viewport, since only |
|
5827 * the most important in-viewport image should have `fetchpriority` set |
|
5828 * to "high". |
|
5829 */ |
|
5830 if ( false === $maybe_in_viewport ) { |
|
5831 _doing_it_wrong( |
|
5832 __FUNCTION__, |
|
5833 __( 'An image should not be lazy-loaded and marked as high priority at the same time.' ), |
|
5834 '6.3.0' |
|
5835 ); |
|
5836 /* |
|
5837 * Set `fetchpriority` here for backward-compatibility as we should |
|
5838 * not override what a developer decided, even though it seems |
|
5839 * incorrect. |
|
5840 */ |
|
5841 $loading_attrs['fetchpriority'] = 'high'; |
|
5842 } else { |
|
5843 $maybe_in_viewport = true; |
|
5844 } |
|
5845 } |
|
5846 |
|
5847 if ( null === $maybe_in_viewport ) { |
|
5848 $header_enforced_contexts = array( |
|
5849 'template_part_' . WP_TEMPLATE_PART_AREA_HEADER => true, |
|
5850 'get_header_image_tag' => true, |
|
5851 ); |
|
5852 |
|
5853 /** |
|
5854 * Filters the header-specific contexts. |
|
5855 * |
|
5856 * @since 6.4.0 |
|
5857 * |
|
5858 * @param array $default_header_enforced_contexts Map of contexts for which elements should be considered |
|
5859 * in the header of the page, as $context => $enabled |
|
5860 * pairs. The $enabled should always be true. |
|
5861 */ |
|
5862 $header_enforced_contexts = apply_filters( 'wp_loading_optimization_force_header_contexts', $header_enforced_contexts ); |
|
5863 |
|
5864 // Consider elements with these header-specific contexts to be in viewport. |
|
5865 if ( isset( $header_enforced_contexts[ $context ] ) ) { |
|
5866 $maybe_in_viewport = true; |
|
5867 $maybe_increase_count = true; |
|
5868 } elseif ( ! is_admin() && in_the_loop() && is_main_query() ) { |
|
5869 /* |
|
5870 * Get the content media count, since this is a main query |
|
5871 * content element. This is accomplished by "increasing" |
|
5872 * the count by zero, as the only way to get the count is |
|
5873 * to call this function. |
|
5874 * The actual count increase happens further below, based |
|
5875 * on the `$increase_count` flag set here. |
|
5876 */ |
|
5877 $content_media_count = wp_increase_content_media_count( 0 ); |
|
5878 $increase_count = true; |
|
5879 |
|
5880 // If the count so far is below the threshold, `loading` attribute is omitted. |
|
5881 if ( $content_media_count < wp_omit_loading_attr_threshold() ) { |
|
5882 $maybe_in_viewport = true; |
|
5883 } else { |
|
5884 $maybe_in_viewport = false; |
|
5885 } |
|
5886 } elseif ( |
|
5887 // Only apply for main query but before the loop. |
|
5888 $wp_query->before_loop && $wp_query->is_main_query() |
|
5889 /* |
|
5890 * Any image before the loop, but after the header has started should not be lazy-loaded, |
|
5891 * except when the footer has already started which can happen when the current template |
|
5892 * does not include any loop. |
|
5893 */ |
|
5894 && did_action( 'get_header' ) && ! did_action( 'get_footer' ) |
|
5895 ) { |
|
5896 $maybe_in_viewport = true; |
|
5897 $maybe_increase_count = true; |
|
5898 } |
|
5899 } |
|
5900 |
|
5901 /* |
|
5902 * If the element is in the viewport (`true`), potentially add |
|
5903 * `fetchpriority` with a value of "high". Otherwise, i.e. if the element |
|
5904 * is not not in the viewport (`false`) or it is unknown (`null`), add |
|
5905 * `loading` with a value of "lazy". |
|
5906 */ |
|
5907 if ( $maybe_in_viewport ) { |
|
5908 $loading_attrs = wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr ); |
|
5909 } else { |
|
5910 // Only add `loading="lazy"` if the feature is enabled. |
|
5911 if ( wp_lazy_loading_enabled( $tag_name, $context ) ) { |
|
5912 $loading_attrs['loading'] = 'lazy'; |
|
5913 } |
|
5914 } |
|
5915 |
|
5916 /* |
|
5917 * If flag was set based on contextual logic above, increase the content |
|
5918 * media count, either unconditionally, or based on whether the image size |
|
5919 * is larger than the threshold. |
|
5920 */ |
|
5921 if ( $increase_count ) { |
|
5922 wp_increase_content_media_count(); |
|
5923 } elseif ( $maybe_increase_count ) { |
|
5924 /** This filter is documented in wp-includes/media.php */ |
|
5925 $wp_min_priority_img_pixels = apply_filters( 'wp_min_priority_img_pixels', 50000 ); |
|
5926 |
|
5927 if ( $wp_min_priority_img_pixels <= $attr['width'] * $attr['height'] ) { |
|
5928 wp_increase_content_media_count(); |
|
5929 } |
|
5930 } |
|
5931 |
|
5932 /** |
|
5933 * Filters the loading optimization attributes. |
|
5934 * |
|
5935 * @since 6.4.0 |
|
5936 * |
|
5937 * @param array $loading_attrs The loading optimization attributes. |
|
5938 * @param string $tag_name The tag name. |
|
5939 * @param array $attr Array of the attributes for the tag. |
|
5940 * @param string $context Context for the element for which the loading optimization attribute is requested. |
|
5941 */ |
|
5942 return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context ); |
|
5350 } |
5943 } |
5351 |
5944 |
5352 /** |
5945 /** |
5353 * Gets the threshold for how many of the first content media elements to not lazy-load. |
5946 * Gets the threshold for how many of the first content media elements to not lazy-load. |
5354 * |
5947 * |
5355 * This function runs the {@see 'wp_omit_loading_attr_threshold'} filter, which uses a default threshold value of 1. |
5948 * This function runs the {@see 'wp_omit_loading_attr_threshold'} filter, which uses a default threshold value of 3. |
5356 * The filter is only run once per page load, unless the `$force` parameter is used. |
5949 * The filter is only run once per page load, unless the `$force` parameter is used. |
5357 * |
5950 * |
5358 * @since 5.9.0 |
5951 * @since 5.9.0 |
5359 * |
5952 * |
5360 * @param bool $force Optional. If set to true, the filter will be (re-)applied even if it already has been before. |
5953 * @param bool $force Optional. If set to true, the filter will be (re-)applied even if it already has been before. |
5371 * |
5964 * |
5372 * For these first content media elements, the `loading` attribute will be omitted. By default, this is the case |
5965 * For these first content media elements, the `loading` attribute will be omitted. By default, this is the case |
5373 * for only the very first content media element. |
5966 * for only the very first content media element. |
5374 * |
5967 * |
5375 * @since 5.9.0 |
5968 * @since 5.9.0 |
5969 * @since 6.3.0 The default threshold was changed from 1 to 3. |
|
5376 * |
5970 * |
5377 * @param int $omit_threshold The number of media elements where the `loading` attribute will not be added. Default 1. |
5971 * @param int $omit_threshold The number of media elements where the `loading` attribute will not be added. Default 3. |
5378 */ |
5972 */ |
5379 $omit_threshold = apply_filters( 'wp_omit_loading_attr_threshold', 1 ); |
5973 $omit_threshold = apply_filters( 'wp_omit_loading_attr_threshold', 3 ); |
5380 } |
5974 } |
5381 |
5975 |
5382 return $omit_threshold; |
5976 return $omit_threshold; |
5383 } |
5977 } |
5384 |
5978 |
5396 |
5990 |
5397 $content_media_count += $amount; |
5991 $content_media_count += $amount; |
5398 |
5992 |
5399 return $content_media_count; |
5993 return $content_media_count; |
5400 } |
5994 } |
5995 |
|
5996 /** |
|
5997 * Determines whether to add `fetchpriority='high'` to loading attributes. |
|
5998 * |
|
5999 * @since 6.3.0 |
|
6000 * @access private |
|
6001 * |
|
6002 * @param array $loading_attrs Array of the loading optimization attributes for the element. |
|
6003 * @param string $tag_name The tag name. |
|
6004 * @param array $attr Array of the attributes for the element. |
|
6005 * @return array Updated loading optimization attributes for the element. |
|
6006 */ |
|
6007 function wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr ) { |
|
6008 // For now, adding `fetchpriority="high"` is only supported for images. |
|
6009 if ( 'img' !== $tag_name ) { |
|
6010 return $loading_attrs; |
|
6011 } |
|
6012 |
|
6013 if ( isset( $attr['fetchpriority'] ) ) { |
|
6014 /* |
|
6015 * While any `fetchpriority` value could be set in `$loading_attrs`, |
|
6016 * for consistency we only do it for `fetchpriority="high"` since that |
|
6017 * is the only possible value that WordPress core would apply on its |
|
6018 * own. |
|
6019 */ |
|
6020 if ( 'high' === $attr['fetchpriority'] ) { |
|
6021 $loading_attrs['fetchpriority'] = 'high'; |
|
6022 wp_high_priority_element_flag( false ); |
|
6023 } |
|
6024 |
|
6025 return $loading_attrs; |
|
6026 } |
|
6027 |
|
6028 // Lazy-loading and `fetchpriority="high"` are mutually exclusive. |
|
6029 if ( isset( $loading_attrs['loading'] ) && 'lazy' === $loading_attrs['loading'] ) { |
|
6030 return $loading_attrs; |
|
6031 } |
|
6032 |
|
6033 if ( ! wp_high_priority_element_flag() ) { |
|
6034 return $loading_attrs; |
|
6035 } |
|
6036 |
|
6037 /** |
|
6038 * Filters the minimum square-pixels threshold for an image to be eligible as the high-priority image. |
|
6039 * |
|
6040 * @since 6.3.0 |
|
6041 * |
|
6042 * @param int $threshold Minimum square-pixels threshold. Default 50000. |
|
6043 */ |
|
6044 $wp_min_priority_img_pixels = apply_filters( 'wp_min_priority_img_pixels', 50000 ); |
|
6045 |
|
6046 if ( $wp_min_priority_img_pixels <= $attr['width'] * $attr['height'] ) { |
|
6047 $loading_attrs['fetchpriority'] = 'high'; |
|
6048 wp_high_priority_element_flag( false ); |
|
6049 } |
|
6050 |
|
6051 return $loading_attrs; |
|
6052 } |
|
6053 |
|
6054 /** |
|
6055 * Accesses a flag that indicates if an element is a possible candidate for `fetchpriority='high'`. |
|
6056 * |
|
6057 * @since 6.3.0 |
|
6058 * @access private |
|
6059 * |
|
6060 * @param bool $value Optional. Used to change the static variable. Default null. |
|
6061 * @return bool Returns true if high-priority element was marked already, otherwise false. |
|
6062 */ |
|
6063 function wp_high_priority_element_flag( $value = null ) { |
|
6064 static $high_priority_element = true; |
|
6065 |
|
6066 if ( is_bool( $value ) ) { |
|
6067 $high_priority_element = $value; |
|
6068 } |
|
6069 |
|
6070 return $high_priority_element; |
|
6071 } |