PageRenderTime 63ms CodeModel.GetById 16ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 1ms

/wp-includes/media.php

https://bitbucket.org/skyarch-iijima/wordpress
PHP | 3958 lines | 1934 code | 440 blank | 1584 comment | 395 complexity | 1cafc46a1a5e7146d64b2ee53ab7c5c1 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * WordPress API for media display.
   4 *
   5 * @package WordPress
   6 * @subpackage Media
   7 */
   8
   9/**
  10 * Retrieve additional image sizes.
  11 *
  12 * @since 4.7.0
  13 *
  14 * @global array $_wp_additional_image_sizes
  15 *
  16 * @return array Additional images size data.
  17 */
  18function wp_get_additional_image_sizes() {
  19	global $_wp_additional_image_sizes;
  20	if ( ! $_wp_additional_image_sizes ) {
  21		$_wp_additional_image_sizes = array();
  22	}
  23	return $_wp_additional_image_sizes;
  24}
  25
  26/**
  27 * Scale down the default size of an image.
  28 *
  29 * This is so that the image is a better fit for the editor and theme.
  30 *
  31 * The `$size` parameter accepts either an array or a string. The supported string
  32 * values are 'thumb' or 'thumbnail' for the given thumbnail size or defaults at
  33 * 128 width and 96 height in pixels. Also supported for the string value is
  34 * 'medium', 'medium_large' and 'full'. The 'full' isn't actually supported, but any value other
  35 * than the supported will result in the content_width size or 500 if that is
  36 * not set.
  37 *
  38 * Finally, there is a filter named {@see 'editor_max_image_size'}, that will be
  39 * called on the calculated array for width and height, respectively. The second
  40 * parameter will be the value that was in the $size parameter. The returned
  41 * type for the hook is an array with the width as the first element and the
  42 * height as the second element.
  43 *
  44 * @since 2.5.0
  45 *
  46 * @global int   $content_width
  47 *
  48 * @param int          $width   Width of the image in pixels.
  49 * @param int          $height  Height of the image in pixels.
  50 * @param string|array $size    Optional. Image size. Accepts any valid image size, or an array
  51 *                              of width and height values in pixels (in that order).
  52 *                              Default 'medium'.
  53 * @param string       $context Optional. Could be 'display' (like in a theme) or 'edit'
  54 *                              (like inserting into an editor). Default null.
  55 * @return array Width and height of what the result image should resize to.
  56 */
  57function image_constrain_size_for_editor( $width, $height, $size = 'medium', $context = null ) {
  58	global $content_width;
  59
  60	$_wp_additional_image_sizes = wp_get_additional_image_sizes();
  61
  62	if ( ! $context )
  63		$context = is_admin() ? 'edit' : 'display';
  64
  65	if ( is_array($size) ) {
  66		$max_width = $size[0];
  67		$max_height = $size[1];
  68	}
  69	elseif ( $size == 'thumb' || $size == 'thumbnail' ) {
  70		$max_width = intval(get_option('thumbnail_size_w'));
  71		$max_height = intval(get_option('thumbnail_size_h'));
  72		// last chance thumbnail size defaults
  73		if ( !$max_width && !$max_height ) {
  74			$max_width = 128;
  75			$max_height = 96;
  76		}
  77	}
  78	elseif ( $size == 'medium' ) {
  79		$max_width = intval(get_option('medium_size_w'));
  80		$max_height = intval(get_option('medium_size_h'));
  81
  82	}
  83	elseif ( $size == 'medium_large' ) {
  84		$max_width = intval( get_option( 'medium_large_size_w' ) );
  85		$max_height = intval( get_option( 'medium_large_size_h' ) );
  86
  87		if ( intval( $content_width ) > 0 ) {
  88			$max_width = min( intval( $content_width ), $max_width );
  89		}
  90	}
  91	elseif ( $size == 'large' ) {
  92		/*
  93		 * We're inserting a large size image into the editor. If it's a really
  94		 * big image we'll scale it down to fit reasonably within the editor
  95		 * itself, and within the theme's content width if it's known. The user
  96		 * can resize it in the editor if they wish.
  97		 */
  98		$max_width = intval(get_option('large_size_w'));
  99		$max_height = intval(get_option('large_size_h'));
 100		if ( intval($content_width) > 0 ) {
 101			$max_width = min( intval($content_width), $max_width );
 102		}
 103	} elseif ( ! empty( $_wp_additional_image_sizes ) && in_array( $size, array_keys( $_wp_additional_image_sizes ) ) ) {
 104		$max_width = intval( $_wp_additional_image_sizes[$size]['width'] );
 105		$max_height = intval( $_wp_additional_image_sizes[$size]['height'] );
 106		// Only in admin. Assume that theme authors know what they're doing.
 107		if ( intval( $content_width ) > 0 && 'edit' === $context ) {
 108			$max_width = min( intval( $content_width ), $max_width );
 109		}
 110	}
 111	// $size == 'full' has no constraint
 112	else {
 113		$max_width = $width;
 114		$max_height = $height;
 115	}
 116
 117	/**
 118	 * Filters the maximum image size dimensions for the editor.
 119	 *
 120	 * @since 2.5.0
 121	 *
 122	 * @param array        $max_image_size An array with the width as the first element,
 123	 *                                     and the height as the second element.
 124	 * @param string|array $size           Size of what the result image should be.
 125	 * @param string       $context        The context the image is being resized for.
 126	 *                                     Possible values are 'display' (like in a theme)
 127	 *                                     or 'edit' (like inserting into an editor).
 128	 */
 129	list( $max_width, $max_height ) = apply_filters( 'editor_max_image_size', array( $max_width, $max_height ), $size, $context );
 130
 131	return wp_constrain_dimensions( $width, $height, $max_width, $max_height );
 132}
 133
 134/**
 135 * Retrieve width and height attributes using given width and height values.
 136 *
 137 * Both attributes are required in the sense that both parameters must have a
 138 * value, but are optional in that if you set them to false or null, then they
 139 * will not be added to the returned string.
 140 *
 141 * You can set the value using a string, but it will only take numeric values.
 142 * If you wish to put 'px' after the numbers, then it will be stripped out of
 143 * the return.
 144 *
 145 * @since 2.5.0
 146 *
 147 * @param int|string $width  Image width in pixels.
 148 * @param int|string $height Image height in pixels.
 149 * @return string HTML attributes for width and, or height.
 150 */
 151function image_hwstring( $width, $height ) {
 152	$out = '';
 153	if ($width)
 154		$out .= 'width="'.intval($width).'" ';
 155	if ($height)
 156		$out .= 'height="'.intval($height).'" ';
 157	return $out;
 158}
 159
 160/**
 161 * Scale an image to fit a particular size (such as 'thumb' or 'medium').
 162 *
 163 * Array with image url, width, height, and whether is intermediate size, in
 164 * that order is returned on success is returned. $is_intermediate is true if
 165 * $url is a resized image, false if it is the original.
 166 *
 167 * The URL might be the original image, or it might be a resized version. This
 168 * function won't create a new resized copy, it will just return an already
 169 * resized one if it exists.
 170 *
 171 * A plugin may use the {@see 'image_downsize'} filter to hook into and offer image
 172 * resizing services for images. The hook must return an array with the same
 173 * elements that are returned in the function. The first element being the URL
 174 * to the new image that was resized.
 175 *
 176 * @since 2.5.0
 177 *
 178 * @param int          $id   Attachment ID for image.
 179 * @param array|string $size Optional. Image size to scale to. Accepts any valid image size,
 180 *                           or an array of width and height values in pixels (in that order).
 181 *                           Default 'medium'.
 182 * @return false|array Array containing the image URL, width, height, and boolean for whether
 183 *                     the image is an intermediate size. False on failure.
 184 */
 185function image_downsize( $id, $size = 'medium' ) {
 186	$is_image = wp_attachment_is_image( $id );
 187
 188	/**
 189	 * Filters whether to preempt the output of image_downsize().
 190	 *
 191	 * Passing a truthy value to the filter will effectively short-circuit
 192	 * down-sizing the image, returning that value as output instead.
 193	 *
 194	 * @since 2.5.0
 195	 *
 196	 * @param bool         $downsize Whether to short-circuit the image downsize. Default false.
 197	 * @param int          $id       Attachment ID for image.
 198	 * @param array|string $size     Size of image. Image size or array of width and height values (in that order).
 199	 *                               Default 'medium'.
 200	 */
 201	if ( $out = apply_filters( 'image_downsize', false, $id, $size ) ) {
 202		return $out;
 203	}
 204
 205	$img_url = wp_get_attachment_url($id);
 206	$meta = wp_get_attachment_metadata($id);
 207	$width = $height = 0;
 208	$is_intermediate = false;
 209	$img_url_basename = wp_basename($img_url);
 210
 211	// If the file isn't an image, attempt to replace its URL with a rendered image from its meta.
 212	// Otherwise, a non-image type could be returned.
 213	if ( ! $is_image ) {
 214		if ( ! empty( $meta['sizes'] ) ) {
 215			$img_url = str_replace( $img_url_basename, $meta['sizes']['full']['file'], $img_url );
 216			$img_url_basename = $meta['sizes']['full']['file'];
 217			$width = $meta['sizes']['full']['width'];
 218			$height = $meta['sizes']['full']['height'];
 219		} else {
 220			return false;
 221		}
 222	}
 223
 224	// try for a new style intermediate size
 225	if ( $intermediate = image_get_intermediate_size($id, $size) ) {
 226		$img_url = str_replace($img_url_basename, $intermediate['file'], $img_url);
 227		$width = $intermediate['width'];
 228		$height = $intermediate['height'];
 229		$is_intermediate = true;
 230	}
 231	elseif ( $size == 'thumbnail' ) {
 232		// fall back to the old thumbnail
 233		if ( ($thumb_file = wp_get_attachment_thumb_file($id)) && $info = getimagesize($thumb_file) ) {
 234			$img_url = str_replace($img_url_basename, wp_basename($thumb_file), $img_url);
 235			$width = $info[0];
 236			$height = $info[1];
 237			$is_intermediate = true;
 238		}
 239	}
 240	if ( !$width && !$height && isset( $meta['width'], $meta['height'] ) ) {
 241		// any other type: use the real image
 242		$width = $meta['width'];
 243		$height = $meta['height'];
 244	}
 245
 246	if ( $img_url) {
 247		// we have the actual image size, but might need to further constrain it if content_width is narrower
 248		list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size );
 249
 250		return array( $img_url, $width, $height, $is_intermediate );
 251	}
 252	return false;
 253
 254}
 255
 256/**
 257 * Register a new image size.
 258 *
 259 * Cropping behavior for the image size is dependent on the value of $crop:
 260 * 1. If false (default), images will be scaled, not cropped.
 261 * 2. If an array in the form of array( x_crop_position, y_crop_position ):
 262 *    - x_crop_position accepts 'left' 'center', or 'right'.
 263 *    - y_crop_position accepts 'top', 'center', or 'bottom'.
 264 *    Images will be cropped to the specified dimensions within the defined crop area.
 265 * 3. If true, images will be cropped to the specified dimensions using center positions.
 266 *
 267 * @since 2.9.0
 268 *
 269 * @global array $_wp_additional_image_sizes Associative array of additional image sizes.
 270 *
 271 * @param string     $name   Image size identifier.
 272 * @param int        $width  Image width in pixels.
 273 * @param int        $height Image height in pixels.
 274 * @param bool|array $crop   Optional. Whether to crop images to specified width and height or resize.
 275 *                           An array can specify positioning of the crop area. Default false.
 276 */
 277function add_image_size( $name, $width = 0, $height = 0, $crop = false ) {
 278	global $_wp_additional_image_sizes;
 279
 280	$_wp_additional_image_sizes[ $name ] = array(
 281		'width'  => absint( $width ),
 282		'height' => absint( $height ),
 283		'crop'   => $crop,
 284	);
 285}
 286
 287/**
 288 * Check if an image size exists.
 289 *
 290 * @since 3.9.0
 291 *
 292 * @param string $name The image size to check.
 293 * @return bool True if the image size exists, false if not.
 294 */
 295function has_image_size( $name ) {
 296	$sizes = wp_get_additional_image_sizes();
 297	return isset( $sizes[ $name ] );
 298}
 299
 300/**
 301 * Remove a new image size.
 302 *
 303 * @since 3.9.0
 304 *
 305 * @global array $_wp_additional_image_sizes
 306 *
 307 * @param string $name The image size to remove.
 308 * @return bool True if the image size was successfully removed, false on failure.
 309 */
 310function remove_image_size( $name ) {
 311	global $_wp_additional_image_sizes;
 312
 313	if ( isset( $_wp_additional_image_sizes[ $name ] ) ) {
 314		unset( $_wp_additional_image_sizes[ $name ] );
 315		return true;
 316	}
 317
 318	return false;
 319}
 320
 321/**
 322 * Registers an image size for the post thumbnail.
 323 *
 324 * @since 2.9.0
 325 *
 326 * @see add_image_size() for details on cropping behavior.
 327 *
 328 * @param int        $width  Image width in pixels.
 329 * @param int        $height Image height in pixels.
 330 * @param bool|array $crop   Optional. Whether to crop images to specified width and height or resize.
 331 *                           An array can specify positioning of the crop area. Default false.
 332 */
 333function set_post_thumbnail_size( $width = 0, $height = 0, $crop = false ) {
 334	add_image_size( 'post-thumbnail', $width, $height, $crop );
 335}
 336
 337/**
 338 * Gets an img tag for an image attachment, scaling it down if requested.
 339 *
 340 * The {@see 'get_image_tag_class'} filter allows for changing the class name for the
 341 * image without having to use regular expressions on the HTML content. The
 342 * parameters are: what WordPress will use for the class, the Attachment ID,
 343 * image align value, and the size the image should be.
 344 *
 345 * The second filter, {@see 'get_image_tag'}, has the HTML content, which can then be
 346 * further manipulated by a plugin to change all attribute values and even HTML
 347 * content.
 348 *
 349 * @since 2.5.0
 350 *
 351 * @param int          $id    Attachment ID.
 352 * @param string       $alt   Image Description for the alt attribute.
 353 * @param string       $title Image Description for the title attribute.
 354 * @param string       $align Part of the class name for aligning the image.
 355 * @param string|array $size  Optional. Registered image size to retrieve a tag for. Accepts any
 356 *                            valid image size, or an array of width and height values in pixels
 357 *                            (in that order). Default 'medium'.
 358 * @return string HTML IMG element for given image attachment
 359 */
 360function get_image_tag( $id, $alt, $title, $align, $size = 'medium' ) {
 361
 362	list( $img_src, $width, $height ) = image_downsize($id, $size);
 363	$hwstring = image_hwstring($width, $height);
 364
 365	$title = $title ? 'title="' . esc_attr( $title ) . '" ' : '';
 366
 367	$class = 'align' . esc_attr($align) .' size-' . esc_attr($size) . ' wp-image-' . $id;
 368
 369	/**
 370	 * Filters the value of the attachment's image tag class attribute.
 371	 *
 372	 * @since 2.6.0
 373	 *
 374	 * @param string       $class CSS class name or space-separated list of classes.
 375	 * @param int          $id    Attachment ID.
 376	 * @param string       $align Part of the class name for aligning the image.
 377	 * @param string|array $size  Size of image. Image size or array of width and height values (in that order).
 378	 *                            Default 'medium'.
 379	 */
 380	$class = apply_filters( 'get_image_tag_class', $class, $id, $align, $size );
 381
 382	$html = '<img src="' . esc_attr($img_src) . '" alt="' . esc_attr($alt) . '" ' . $title . $hwstring . 'class="' . $class . '" />';
 383
 384	/**
 385	 * Filters the HTML content for the image tag.
 386	 *
 387	 * @since 2.6.0
 388	 *
 389	 * @param string       $html  HTML content for the image.
 390	 * @param int          $id    Attachment ID.
 391	 * @param string       $alt   Alternate text.
 392	 * @param string       $title Attachment title.
 393	 * @param string       $align Part of the class name for aligning the image.
 394	 * @param string|array $size  Size of image. Image size or array of width and height values (in that order).
 395	 *                            Default 'medium'.
 396	 */
 397	return apply_filters( 'get_image_tag', $html, $id, $alt, $title, $align, $size );
 398}
 399
 400/**
 401 * Calculates the new dimensions for a down-sampled image.
 402 *
 403 * If either width or height are empty, no constraint is applied on
 404 * that dimension.
 405 *
 406 * @since 2.5.0
 407 *
 408 * @param int $current_width  Current width of the image.
 409 * @param int $current_height Current height of the image.
 410 * @param int $max_width      Optional. Max width in pixels to constrain to. Default 0.
 411 * @param int $max_height     Optional. Max height in pixels to constrain to. Default 0.
 412 * @return array First item is the width, the second item is the height.
 413 */
 414function wp_constrain_dimensions( $current_width, $current_height, $max_width = 0, $max_height = 0 ) {
 415	if ( !$max_width && !$max_height )
 416		return array( $current_width, $current_height );
 417
 418	$width_ratio = $height_ratio = 1.0;
 419	$did_width = $did_height = false;
 420
 421	if ( $max_width > 0 && $current_width > 0 && $current_width > $max_width ) {
 422		$width_ratio = $max_width / $current_width;
 423		$did_width = true;
 424	}
 425
 426	if ( $max_height > 0 && $current_height > 0 && $current_height > $max_height ) {
 427		$height_ratio = $max_height / $current_height;
 428		$did_height = true;
 429	}
 430
 431	// Calculate the larger/smaller ratios
 432	$smaller_ratio = min( $width_ratio, $height_ratio );
 433	$larger_ratio  = max( $width_ratio, $height_ratio );
 434
 435	if ( (int) round( $current_width * $larger_ratio ) > $max_width || (int) round( $current_height * $larger_ratio ) > $max_height ) {
 436 		// The larger ratio is too big. It would result in an overflow.
 437		$ratio = $smaller_ratio;
 438	} else {
 439		// The larger ratio fits, and is likely to be a more "snug" fit.
 440		$ratio = $larger_ratio;
 441	}
 442
 443	// Very small dimensions may result in 0, 1 should be the minimum.
 444	$w = max ( 1, (int) round( $current_width  * $ratio ) );
 445	$h = max ( 1, (int) round( $current_height * $ratio ) );
 446
 447	// Sometimes, due to rounding, we'll end up with a result like this: 465x700 in a 177x177 box is 117x176... a pixel short
 448	// We also have issues with recursive calls resulting in an ever-changing result. Constraining to the result of a constraint should yield the original result.
 449	// Thus we look for dimensions that are one pixel shy of the max value and bump them up
 450
 451	// Note: $did_width means it is possible $smaller_ratio == $width_ratio.
 452	if ( $did_width && $w == $max_width - 1 ) {
 453		$w = $max_width; // Round it up
 454	}
 455
 456	// Note: $did_height means it is possible $smaller_ratio == $height_ratio.
 457	if ( $did_height && $h == $max_height - 1 ) {
 458		$h = $max_height; // Round it up
 459	}
 460
 461	/**
 462	 * Filters dimensions to constrain down-sampled images to.
 463	 *
 464	 * @since 4.1.0
 465	 *
 466	 * @param array $dimensions     The image width and height.
 467	 * @param int 	$current_width  The current width of the image.
 468	 * @param int 	$current_height The current height of the image.
 469	 * @param int 	$max_width      The maximum width permitted.
 470	 * @param int 	$max_height     The maximum height permitted.
 471	 */
 472	return apply_filters( 'wp_constrain_dimensions', array( $w, $h ), $current_width, $current_height, $max_width, $max_height );
 473}
 474
 475/**
 476 * Retrieves calculated resize dimensions for use in WP_Image_Editor.
 477 *
 478 * Calculates dimensions and coordinates for a resized image that fits
 479 * within a specified width and height.
 480 *
 481 * Cropping behavior is dependent on the value of $crop:
 482 * 1. If false (default), images will not be cropped.
 483 * 2. If an array in the form of array( x_crop_position, y_crop_position ):
 484 *    - x_crop_position accepts 'left' 'center', or 'right'.
 485 *    - y_crop_position accepts 'top', 'center', or 'bottom'.
 486 *    Images will be cropped to the specified dimensions within the defined crop area.
 487 * 3. If true, images will be cropped to the specified dimensions using center positions.
 488 *
 489 * @since 2.5.0
 490 *
 491 * @param int        $orig_w Original width in pixels.
 492 * @param int        $orig_h Original height in pixels.
 493 * @param int        $dest_w New width in pixels.
 494 * @param int        $dest_h New height in pixels.
 495 * @param bool|array $crop   Optional. Whether to crop image to specified width and height or resize.
 496 *                           An array can specify positioning of the crop area. Default false.
 497 * @return false|array False on failure. Returned array matches parameters for `imagecopyresampled()`.
 498 */
 499function image_resize_dimensions( $orig_w, $orig_h, $dest_w, $dest_h, $crop = false ) {
 500
 501	if ($orig_w <= 0 || $orig_h <= 0)
 502		return false;
 503	// at least one of dest_w or dest_h must be specific
 504	if ($dest_w <= 0 && $dest_h <= 0)
 505		return false;
 506
 507	/**
 508	 * Filters whether to preempt calculating the image resize dimensions.
 509	 *
 510	 * Passing a non-null value to the filter will effectively short-circuit
 511	 * image_resize_dimensions(), returning that value instead.
 512	 *
 513	 * @since 3.4.0
 514	 *
 515	 * @param null|mixed $null   Whether to preempt output of the resize dimensions.
 516	 * @param int        $orig_w Original width in pixels.
 517	 * @param int        $orig_h Original height in pixels.
 518	 * @param int        $dest_w New width in pixels.
 519	 * @param int        $dest_h New height in pixels.
 520	 * @param bool|array $crop   Whether to crop image to specified width and height or resize.
 521	 *                           An array can specify positioning of the crop area. Default false.
 522	 */
 523	$output = apply_filters( 'image_resize_dimensions', null, $orig_w, $orig_h, $dest_w, $dest_h, $crop );
 524	if ( null !== $output )
 525		return $output;
 526
 527	if ( $crop ) {
 528		// crop the largest possible portion of the original image that we can size to $dest_w x $dest_h
 529		$aspect_ratio = $orig_w / $orig_h;
 530		$new_w = min($dest_w, $orig_w);
 531		$new_h = min($dest_h, $orig_h);
 532
 533		if ( ! $new_w ) {
 534			$new_w = (int) round( $new_h * $aspect_ratio );
 535		}
 536
 537		if ( ! $new_h ) {
 538			$new_h = (int) round( $new_w / $aspect_ratio );
 539		}
 540
 541		$size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
 542
 543		$crop_w = round($new_w / $size_ratio);
 544		$crop_h = round($new_h / $size_ratio);
 545
 546		if ( ! is_array( $crop ) || count( $crop ) !== 2 ) {
 547			$crop = array( 'center', 'center' );
 548		}
 549
 550		list( $x, $y ) = $crop;
 551
 552		if ( 'left' === $x ) {
 553			$s_x = 0;
 554		} elseif ( 'right' === $x ) {
 555			$s_x = $orig_w - $crop_w;
 556		} else {
 557			$s_x = floor( ( $orig_w - $crop_w ) / 2 );
 558		}
 559
 560		if ( 'top' === $y ) {
 561			$s_y = 0;
 562		} elseif ( 'bottom' === $y ) {
 563			$s_y = $orig_h - $crop_h;
 564		} else {
 565			$s_y = floor( ( $orig_h - $crop_h ) / 2 );
 566		}
 567	} else {
 568		// don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
 569		$crop_w = $orig_w;
 570		$crop_h = $orig_h;
 571
 572		$s_x = 0;
 573		$s_y = 0;
 574
 575		list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
 576	}
 577
 578	// if the resulting image would be the same size or larger we don't want to resize it
 579	if ( $new_w >= $orig_w && $new_h >= $orig_h && $dest_w != $orig_w && $dest_h != $orig_h ) {
 580		return false;
 581	}
 582
 583	// the return array matches the parameters to imagecopyresampled()
 584	// int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
 585	return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h );
 586
 587}
 588
 589/**
 590 * Resizes an image to make a thumbnail or intermediate size.
 591 *
 592 * The returned array has the file size, the image width, and image height. The
 593 * {@see 'image_make_intermediate_size'} filter can be used to hook in and change the
 594 * values of the returned array. The only parameter is the resized file path.
 595 *
 596 * @since 2.5.0
 597 *
 598 * @param string $file   File path.
 599 * @param int    $width  Image width.
 600 * @param int    $height Image height.
 601 * @param bool   $crop   Optional. Whether to crop image to specified width and height or resize.
 602 *                       Default false.
 603 * @return false|array False, if no image was created. Metadata array on success.
 604 */
 605function image_make_intermediate_size( $file, $width, $height, $crop = false ) {
 606	if ( $width || $height ) {
 607		$editor = wp_get_image_editor( $file );
 608
 609		if ( is_wp_error( $editor ) || is_wp_error( $editor->resize( $width, $height, $crop ) ) )
 610			return false;
 611
 612		$resized_file = $editor->save();
 613
 614		if ( ! is_wp_error( $resized_file ) && $resized_file ) {
 615			unset( $resized_file['path'] );
 616			return $resized_file;
 617		}
 618	}
 619	return false;
 620}
 621
 622/**
 623 * Helper function to test if aspect ratios for two images match.
 624 *
 625 * @since 4.6.0
 626 *
 627 * @param int $source_width  Width of the first image in pixels.
 628 * @param int $source_height Height of the first image in pixels.
 629 * @param int $target_width  Width of the second image in pixels.
 630 * @param int $target_height Height of the second image in pixels.
 631 * @return bool True if aspect ratios match within 1px. False if not.
 632 */
 633function wp_image_matches_ratio( $source_width, $source_height, $target_width, $target_height ) {
 634	/*
 635	 * To test for varying crops, we constrain the dimensions of the larger image
 636	 * to the dimensions of the smaller image and see if they match.
 637	 */
 638	if ( $source_width > $target_width ) {
 639		$constrained_size = wp_constrain_dimensions( $source_width, $source_height, $target_width );
 640		$expected_size = array( $target_width, $target_height );
 641	} else {
 642		$constrained_size = wp_constrain_dimensions( $target_width, $target_height, $source_width );
 643		$expected_size = array( $source_width, $source_height );
 644	}
 645
 646	// If the image dimensions are within 1px of the expected size, we consider it a match.
 647	$matched = ( abs( $constrained_size[0] - $expected_size[0] ) <= 1 && abs( $constrained_size[1] - $expected_size[1] ) <= 1 );
 648
 649	return $matched;
 650}
 651
 652/**
 653 * Retrieves the image's intermediate size (resized) path, width, and height.
 654 *
 655 * The $size parameter can be an array with the width and height respectively.
 656 * If the size matches the 'sizes' metadata array for width and height, then it
 657 * will be used. If there is no direct match, then the nearest image size larger
 658 * than the specified size will be used. If nothing is found, then the function
 659 * will break out and return false.
 660 *
 661 * The metadata 'sizes' is used for compatible sizes that can be used for the
 662 * parameter $size value.
 663 *
 664 * The url path will be given, when the $size parameter is a string.
 665 *
 666 * If you are passing an array for the $size, you should consider using
 667 * add_image_size() so that a cropped version is generated. It's much more
 668 * efficient than having to find the closest-sized image and then having the
 669 * browser scale down the image.
 670 *
 671 * @since 2.5.0
 672 *
 673 * @param int          $post_id Attachment ID.
 674 * @param array|string $size    Optional. Image size. Accepts any valid image size, or an array
 675 *                              of width and height values in pixels (in that order).
 676 *                              Default 'thumbnail'.
 677 * @return false|array $data {
 678 *     Array of file relative path, width, and height on success. Additionally includes absolute
 679 *     path and URL if registered size is passed to $size parameter. False on failure.
 680 *
 681 *     @type string $file   Image's path relative to uploads directory
 682 *     @type int    $width  Width of image
 683 *     @type int    $height Height of image
 684 *     @type string $path   Image's absolute filesystem path.
 685 *     @type string $url    Image's URL.
 686 * }
 687 */
 688function image_get_intermediate_size( $post_id, $size = 'thumbnail' ) {
 689	if ( ! $size || ! is_array( $imagedata = wp_get_attachment_metadata( $post_id ) ) || empty( $imagedata['sizes'] )  ) {
 690		return false;
 691	}
 692
 693	$data = array();
 694
 695	// Find the best match when '$size' is an array.
 696	if ( is_array( $size ) ) {
 697		$candidates = array();
 698
 699		if ( ! isset( $imagedata['file'] ) && isset( $imagedata['sizes']['full'] ) ) {
 700			$imagedata['height'] = $imagedata['sizes']['full']['height'];
 701			$imagedata['width']  = $imagedata['sizes']['full']['width'];
 702		}
 703
 704		foreach ( $imagedata['sizes'] as $_size => $data ) {
 705			// If there's an exact match to an existing image size, short circuit.
 706			if ( $data['width'] == $size[0] && $data['height'] == $size[1] ) {
 707				$candidates[ $data['width'] * $data['height'] ] = $data;
 708				break;
 709			}
 710
 711			// If it's not an exact match, consider larger sizes with the same aspect ratio.
 712			if ( $data['width'] >= $size[0] && $data['height'] >= $size[1] ) {
 713				// If '0' is passed to either size, we test ratios against the original file.
 714				if ( 0 === $size[0] || 0 === $size[1] ) {
 715					$same_ratio = wp_image_matches_ratio( $data['width'], $data['height'], $imagedata['width'], $imagedata['height'] );
 716				} else {
 717					$same_ratio = wp_image_matches_ratio( $data['width'], $data['height'], $size[0], $size[1] );
 718				}
 719
 720				if ( $same_ratio ) {
 721					$candidates[ $data['width'] * $data['height'] ] = $data;
 722				}
 723			}
 724		}
 725
 726		if ( ! empty( $candidates ) ) {
 727			// Sort the array by size if we have more than one candidate.
 728			if ( 1 < count( $candidates ) ) {
 729				ksort( $candidates );
 730			}
 731
 732			$data = array_shift( $candidates );
 733		/*
 734		 * When the size requested is smaller than the thumbnail dimensions, we
 735		 * fall back to the thumbnail size to maintain backwards compatibility with
 736		 * pre 4.6 versions of WordPress.
 737		 */
 738		} elseif ( ! empty( $imagedata['sizes']['thumbnail'] ) && $imagedata['sizes']['thumbnail']['width'] >= $size[0] && $imagedata['sizes']['thumbnail']['width'] >= $size[1] ) {
 739			$data = $imagedata['sizes']['thumbnail'];
 740		} else {
 741			return false;
 742		}
 743
 744		// Constrain the width and height attributes to the requested values.
 745		list( $data['width'], $data['height'] ) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
 746
 747	} elseif ( ! empty( $imagedata['sizes'][ $size ] ) ) {
 748		$data = $imagedata['sizes'][ $size ];
 749	}
 750
 751	// If we still don't have a match at this point, return false.
 752	if ( empty( $data ) ) {
 753		return false;
 754	}
 755
 756	// include the full filesystem path of the intermediate file
 757	if ( empty( $data['path'] ) && ! empty( $data['file'] ) && ! empty( $imagedata['file'] ) ) {
 758		$file_url = wp_get_attachment_url($post_id);
 759		$data['path'] = path_join( dirname($imagedata['file']), $data['file'] );
 760		$data['url'] = path_join( dirname($file_url), $data['file'] );
 761	}
 762
 763	/**
 764	 * Filters the output of image_get_intermediate_size()
 765	 *
 766	 * @since 4.4.0
 767	 *
 768	 * @see image_get_intermediate_size()
 769	 *
 770	 * @param array        $data    Array of file relative path, width, and height on success. May also include
 771	 *                              file absolute path and URL.
 772	 * @param int          $post_id The post_id of the image attachment
 773	 * @param string|array $size    Registered image size or flat array of initially-requested height and width
 774	 *                              dimensions (in that order).
 775	 */
 776	return apply_filters( 'image_get_intermediate_size', $data, $post_id, $size );
 777}
 778
 779/**
 780 * Gets the available intermediate image sizes.
 781 *
 782 * @since 3.0.0
 783 *
 784 * @return array Returns a filtered array of image size strings.
 785 */
 786function get_intermediate_image_sizes() {
 787	$_wp_additional_image_sizes = wp_get_additional_image_sizes();
 788	$image_sizes = array('thumbnail', 'medium', 'medium_large', 'large'); // Standard sizes
 789	if ( ! empty( $_wp_additional_image_sizes ) ) {
 790		$image_sizes = array_merge( $image_sizes, array_keys( $_wp_additional_image_sizes ) );
 791	}
 792
 793	/**
 794	 * Filters the list of intermediate image sizes.
 795	 *
 796	 * @since 2.5.0
 797	 *
 798	 * @param array $image_sizes An array of intermediate image sizes. Defaults
 799	 *                           are 'thumbnail', 'medium', 'medium_large', 'large'.
 800	 */
 801	return apply_filters( 'intermediate_image_sizes', $image_sizes );
 802}
 803
 804/**
 805 * Retrieve an image to represent an attachment.
 806 *
 807 * A mime icon for files, thumbnail or intermediate size for images.
 808 *
 809 * The returned array contains four values: the URL of the attachment image src,
 810 * the width of the image file, the height of the image file, and a boolean
 811 * representing whether the returned array describes an intermediate (generated)
 812 * image size or the original, full-sized upload.
 813 *
 814 * @since 2.5.0
 815 *
 816 * @param int          $attachment_id Image attachment ID.
 817 * @param string|array $size          Optional. Image size. Accepts any valid image size, or an array of width
 818 *                                    and height values in pixels (in that order). Default 'thumbnail'.
 819 * @param bool         $icon          Optional. Whether the image should be treated as an icon. Default false.
 820 * @return false|array Returns an array (url, width, height, is_intermediate), or false, if no image is available.
 821 */
 822function wp_get_attachment_image_src( $attachment_id, $size = 'thumbnail', $icon = false ) {
 823	// get a thumbnail or intermediate image if there is one
 824	$image = image_downsize( $attachment_id, $size );
 825	if ( ! $image ) {
 826		$src = false;
 827
 828		if ( $icon && $src = wp_mime_type_icon( $attachment_id ) ) {
 829			/** This filter is documented in wp-includes/post.php */
 830			$icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' );
 831
 832			$src_file = $icon_dir . '/' . wp_basename( $src );
 833			@list( $width, $height ) = getimagesize( $src_file );
 834		}
 835
 836		if ( $src && $width && $height ) {
 837			$image = array( $src, $width, $height );
 838		}
 839	}
 840	/**
 841	 * Filters the image src result.
 842	 *
 843	 * @since 4.3.0
 844	 *
 845	 * @param array|false  $image         Either array with src, width & height, icon src, or false.
 846	 * @param int          $attachment_id Image attachment ID.
 847	 * @param string|array $size          Size of image. Image size or array of width and height values
 848	 *                                    (in that order). Default 'thumbnail'.
 849	 * @param bool         $icon          Whether the image should be treated as an icon. Default false.
 850	 */
 851	return apply_filters( 'wp_get_attachment_image_src', $image, $attachment_id, $size, $icon );
 852}
 853
 854/**
 855 * Get an HTML img element representing an image attachment
 856 *
 857 * While `$size` will accept an array, it is better to register a size with
 858 * add_image_size() so that a cropped version is generated. It's much more
 859 * efficient than having to find the closest-sized image and then having the
 860 * browser scale down the image.
 861 *
 862 * @since 2.5.0
 863 *
 864 * @param int          $attachment_id Image attachment ID.
 865 * @param string|array $size          Optional. Image size. Accepts any valid image size, or an array of width
 866 *                                    and height values in pixels (in that order). Default 'thumbnail'.
 867 * @param bool         $icon          Optional. Whether the image should be treated as an icon. Default false.
 868 * @param string|array $attr          Optional. Attributes for the image markup. Default empty.
 869 * @return string HTML img element or empty string on failure.
 870 */
 871function wp_get_attachment_image($attachment_id, $size = 'thumbnail', $icon = false, $attr = '') {
 872	$html = '';
 873	$image = wp_get_attachment_image_src($attachment_id, $size, $icon);
 874	if ( $image ) {
 875		list($src, $width, $height) = $image;
 876		$hwstring = image_hwstring($width, $height);
 877		$size_class = $size;
 878		if ( is_array( $size_class ) ) {
 879			$size_class = join( 'x', $size_class );
 880		}
 881		$attachment = get_post($attachment_id);
 882		$default_attr = array(
 883			'src'	=> $src,
 884			'class'	=> "attachment-$size_class size-$size_class",
 885			'alt'	=> trim( strip_tags( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) ),
 886		);
 887
 888		$attr = wp_parse_args( $attr, $default_attr );
 889
 890		// Generate 'srcset' and 'sizes' if not already present.
 891		if ( empty( $attr['srcset'] ) ) {
 892			$image_meta = wp_get_attachment_metadata( $attachment_id );
 893
 894			if ( is_array( $image_meta ) ) {
 895				$size_array = array( absint( $width ), absint( $height ) );
 896				$srcset = wp_calculate_image_srcset( $size_array, $src, $image_meta, $attachment_id );
 897				$sizes = wp_calculate_image_sizes( $size_array, $src, $image_meta, $attachment_id );
 898
 899				if ( $srcset && ( $sizes || ! empty( $attr['sizes'] ) ) ) {
 900					$attr['srcset'] = $srcset;
 901
 902					if ( empty( $attr['sizes'] ) ) {
 903						$attr['sizes'] = $sizes;
 904					}
 905				}
 906			}
 907		}
 908
 909		/**
 910		 * Filters the list of attachment image attributes.
 911		 *
 912		 * @since 2.8.0
 913		 *
 914		 * @param array        $attr       Attributes for the image markup.
 915		 * @param WP_Post      $attachment Image attachment post.
 916		 * @param string|array $size       Requested size. Image size or array of width and height values
 917		 *                                 (in that order). Default 'thumbnail'.
 918		 */
 919		$attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment, $size );
 920		$attr = array_map( 'esc_attr', $attr );
 921		$html = rtrim("<img $hwstring");
 922		foreach ( $attr as $name => $value ) {
 923			$html .= " $name=" . '"' . $value . '"';
 924		}
 925		$html .= ' />';
 926	}
 927
 928	return $html;
 929}
 930
 931/**
 932 * Get the URL of an image attachment.
 933 *
 934 * @since 4.4.0
 935 *
 936 * @param int          $attachment_id Image attachment ID.
 937 * @param string|array $size          Optional. Image size to retrieve. Accepts any valid image size, or an array
 938 *                                    of width and height values in pixels (in that order). Default 'thumbnail'.
 939 * @param bool         $icon          Optional. Whether the image should be treated as an icon. Default false.
 940 * @return string|false Attachment URL or false if no image is available.
 941 */
 942function wp_get_attachment_image_url( $attachment_id, $size = 'thumbnail', $icon = false ) {
 943	$image = wp_get_attachment_image_src( $attachment_id, $size, $icon );
 944	return isset( $image['0'] ) ? $image['0'] : false;
 945}
 946
 947/**
 948 * Get the attachment path relative to the upload directory.
 949 *
 950 * @since 4.4.1
 951 * @access private
 952 *
 953 * @param string $file Attachment file name.
 954 * @return string Attachment path relative to the upload directory.
 955 */
 956function _wp_get_attachment_relative_path( $file ) {
 957	$dirname = dirname( $file );
 958
 959	if ( '.' === $dirname ) {
 960		return '';
 961	}
 962
 963	if ( false !== strpos( $dirname, 'wp-content/uploads' ) ) {
 964		// Get the directory name relative to the upload directory (back compat for pre-2.7 uploads)
 965		$dirname = substr( $dirname, strpos( $dirname, 'wp-content/uploads' ) + 18 );
 966		$dirname = ltrim( $dirname, '/' );
 967	}
 968
 969	return $dirname;
 970}
 971
 972/**
 973 * Get the image size as array from its meta data.
 974 *
 975 * Used for responsive images.
 976 *
 977 * @since 4.4.0
 978 * @access private
 979 *
 980 * @param string $size_name  Image size. Accepts any valid image size name ('thumbnail', 'medium', etc.).
 981 * @param array  $image_meta The image meta data.
 982 * @return array|bool Array of width and height values in pixels (in that order)
 983 *                    or false if the size doesn't exist.
 984 */
 985function _wp_get_image_size_from_meta( $size_name, $image_meta ) {
 986	if ( $size_name === 'full' ) {
 987		return array(
 988			absint( $image_meta['width'] ),
 989			absint( $image_meta['height'] ),
 990		);
 991	} elseif ( ! empty( $image_meta['sizes'][$size_name] ) ) {
 992		return array(
 993			absint( $image_meta['sizes'][$size_name]['width'] ),
 994			absint( $image_meta['sizes'][$size_name]['height'] ),
 995		);
 996	}
 997
 998	return false;
 999}
1000
1001/**
1002 * Retrieves the value for an image attachment's 'srcset' attribute.
1003 *
1004 * @since 4.4.0
1005 *
1006 * @see wp_calculate_image_srcset()
1007 *
1008 * @param int          $attachment_id Image attachment ID.
1009 * @param array|string $size          Optional. Image size. Accepts any valid image size, or an array of
1010 *                                    width and height values in pixels (in that order). Default 'medium'.
1011 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
1012 *                                    Default null.
1013 * @return string|bool A 'srcset' value string or false.
1014 */
1015function wp_get_attachment_image_srcset( $attachment_id, $size = 'medium', $image_meta = null ) {
1016	if ( ! $image = wp_get_attachment_image_src( $attachment_id, $size ) ) {
1017		return false;
1018	}
1019
1020	if ( ! is_array( $image_meta ) ) {
1021		$image_meta = wp_get_attachment_metadata( $attachment_id );
1022	}
1023
1024	$image_src = $image[0];
1025	$size_array = array(
1026		absint( $image[1] ),
1027		absint( $image[2] )
1028	);
1029
1030	return wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id );
1031}
1032
1033/**
1034 * A helper function to calculate the image sources to include in a 'srcset' attribute.
1035 *
1036 * @since 4.4.0
1037 *
1038 * @param array  $size_array    Array of width and height values in pixels (in that order).
1039 * @param string $image_src     The 'src' of the image.
1040 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1041 * @param int    $attachment_id Optional. The image attachment ID to pass to the filter. Default 0.
1042 * @return string|bool          The 'srcset' attribute value. False on error or when only one source exists.
1043 */
1044function wp_calculate_image_srcset( $size_array, $image_src, $image_meta, $attachment_id = 0 ) {
1045	/**
1046	 * Let plugins pre-filter the image meta to be able to fix inconsistencies in the stored data.
1047	 *
1048	 * @since 4.5.0
1049	 *
1050	 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1051	 * @param array  $size_array    Array of width and height values in pixels (in that order).
1052	 * @param string $image_src     The 'src' of the image.
1053	 * @param int    $attachment_id The image attachment ID or 0 if not supplied.
1054	 */
1055	$image_meta = apply_filters( 'wp_calculate_image_srcset_meta', $image_meta, $size_array, $image_src, $attachment_id );
1056
1057	if ( empty( $image_meta['sizes'] ) || ! isset( $image_meta['file'] ) || strlen( $image_meta['file'] ) < 4 ) {
1058		return false;
1059	}
1060
1061	$image_sizes = $image_meta['sizes'];
1062
1063	// Get the width and height of the image.
1064	$image_width = (int) $size_array[0];
1065	$image_height = (int) $size_array[1];
1066
1067	// Bail early if error/no width.
1068	if ( $image_width < 1 ) {
1069		return false;
1070	}
1071
1072	$image_basename = wp_basename( $image_meta['file'] );
1073
1074	/*
1075	 * WordPress flattens animated GIFs into one frame when generating intermediate sizes.
1076	 * To avoid hiding animation in user content, if src is a full size GIF, a srcset attribute is not generated.
1077	 * If src is an intermediate size GIF, the full size is excluded from srcset to keep a flattened GIF from becoming animated.
1078	 */
1079	if ( ! isset( $image_sizes['thumbnail']['mime-type'] ) || 'image/gif' !== $image_sizes['thumbnail']['mime-type'] ) {
1080		$image_sizes[] = array(
1081			'width'  => $image_meta['width'],
1082			'height' => $image_meta['height'],
1083			'file'   => $image_basename,
1084		);
1085	} elseif ( strpos( $image_src, $image_meta['file'] ) ) {
1086		return false;
1087	}
1088
1089	// Retrieve the uploads sub-directory from the full size image.
1090	$dirname = _wp_get_attachment_relative_path( $image_meta['file'] );
1091
1092	if ( $dirname ) {
1093		$dirname = trailingslashit( $dirname );
1094	}
1095
1096	$upload_dir = wp_get_upload_dir();
1097	$image_baseurl = trailingslashit( $upload_dir['baseurl'] ) . $dirname;
1098
1099	/*
1100	 * If currently on HTTPS, prefer HTTPS URLs when we know they're supported by the domain
1101	 * (which is to say, when they share the domain name of the current request).
1102	 */
1103	if ( is_ssl() && 'https' !== substr( $image_baseurl, 0, 5 ) && parse_url( $image_baseurl, PHP_URL_HOST ) === $_SERVER['HTTP_HOST'] ) {
1104		$image_baseurl = set_url_scheme( $image_baseurl, 'https' );
1105	}
1106
1107	/*
1108	 * Images that have been edited in WordPress after being uploaded will
1109	 * contain a unique hash. Look for that hash and use it later to filter
1110	 * out images that are leftovers from previous versions.
1111	 */
1112	$image_edited = preg_match( '/-e[0-9]{13}/', wp_basename( $image_src ), $image_edit_hash );
1113
1114	/**
1115	 * Filters the maximum image width to be included in a 'srcset' attribute.
1116	 *
1117	 * @since 4.4.0
1118	 *
1119	 * @param int   $max_width  The maximum image width to be included in the 'srcset'. Default '1600'.
1120	 * @param array $size_array Array of width and height values in pixels (in that order).
1121	 */
1122	$max_srcset_image_width = apply_filters( 'max_srcset_image_width', 1600, $size_array );
1123
1124	// Array to hold URL candidates.
1125	$sources = array();
1126
1127	/**
1128	 * To make sure the ID matches our image src, we will check to see if any sizes in our attachment
1129	 * meta match our $image_src. If no matches are found we don't return a srcset to avoid serving
1130	 * an incorrect image. See #35045.
1131	 */
1132	$src_matched = false;
1133
1134	/*
1135	 * Loop through available images. Only use images that are resized
1136	 * versions of the same edit.
1137	 */
1138	foreach ( $image_sizes as $image ) {
1139		$is_src = false;
1140
1141		// Check if image meta isn't corrupted.
1142		if ( ! is_array( $image ) ) {
1143			continue;
1144		}
1145
1146		// If the file name is part of the `src`, we've confirmed a match.
1147		if ( ! $src_matched && false !== strpos( $image_src, $dirname . $image['file'] ) ) {
1148			$src_matched = $is_src = true;
1149		}
1150
1151		// Filter out images that are from previous edits.
1152		if ( $image_edited && ! strpos( $image['file'], $image_edit_hash[0] ) ) {
1153			continue;
1154		}
1155
1156		/*
1157		 * Filters out images that are wider than '$max_srcset_image_width' unless
1158		 * that file is in the 'src' attribute.
1159		 */
1160		if ( $max_srcset_image_width && $image['width'] > $max_srcset_image_width && ! $is_src ) {
1161			continue;
1162		}
1163
1164		// If the image dimensions are within 1px of the expected size, use it.
1165		if ( wp_image_matches_ratio( $image_width, $image_height, $image['width'], $image['height'] ) ) {
1166			// Add the URL, descriptor, and value to the sources array to be returned.
1167			$source = array(
1168				'url'        => $image_baseurl . $image['file'],
1169				'descriptor' => 'w',
1170				'value'      => $image['width'],
1171			);
1172
1173			// The 'src' image has to be the first in the 'srcset', because of a bug in iOS8. See #35030.
1174			if ( $is_src ) {
1175				$sources = array( $image['width'] => $source ) + $sources;
1176			} else {
1177				$sources[ $image['width'] ] = $source;
1178			}
1179		}
1180	}
1181
1182	/**
1183	 * Filters an image's 'srcset' sources.
1184	 *
1185	 * @since 4.4.0
1186	 *
1187	 * @param array  $sources {
1188	 *     One or more arrays of source data to include in the 'srcset'.
1189	 *
1190	 *     @type array $width {
1191	 *         @type string $url        The URL of an image source.
1192	 *         @type string $descriptor The descriptor type used in the image candidate string,
1193	 *                                  either 'w' or 'x'.
1194	 *         @type int    $value      The source width if paired with a 'w' descriptor, or a
1195	 *                                  pixel density value if paired with an 'x' descriptor.
1196	 *     }
1197	 * }
1198	 * @param array  $size_array    Array of width and height values in pixels (in that order).
1199	 * @param string $image_src     The 'src' of the image.
1200	 * @param array  $image_meta    The image meta data as returned by 'wp_get_attachment_metadata()'.
1201	 * @param int    $attachment_id Image attachment ID or 0.
1202	 */
1203	$sources = apply_filters( 'wp_calculate_image_srcset', $sources, $size_array, $image_src, $image_meta, $attachment_id );
1204
1205	// Only return a 'srcset' value if there is more than one source.
1206	if ( ! $src_matched || count( $sources ) < 2 ) {
1207		return false;
1208	}
1209
1210	$srcset = '';
1211
1212	foreach ( $sources as $source ) {
1213		$srcset .= str_replace( ' ', '%20', $source['url'] ) . ' ' . $source['value'] . $source['descriptor'] . ', ';
1214	}
1215
1216	return rtrim( $srcset, ', ' );
1217}
1218
1219/**
1220 * Retrieves the value for an image attachment's 'sizes' attribute.
1221 *
1222 * @since 4.4.0
1223 *
1224 * @see wp_calculate_image_sizes()
1225 *
1226 * @param int          $attachment_id Image attachment ID.
1227 * @param array|string $size          Optional. Image size. Accepts any valid image size, or an array of width
1228 *                                    and height values in pixels (in that order). Default 'medium'.
1229 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
1230 *                                    Default null.
1231 * @return string|bool A valid source size value for use in a 'sizes' attribute or false.
1232 */
1233function wp_get_attachment_image_sizes( $attachment_id, $size = 'medium', $image_meta = null ) {
1234	if ( ! $image = wp_get_attachment_image_src( $attachment_id, $size ) ) {
1235		return false;
1236	}
1237
1238	if ( ! is_array( $image_meta ) ) {
1239		$image_meta = wp_get_attachment_metadata( $attachment_id );
1240	}
1241
1242	$image_src = $image[0];
1243	$size_array = array(
1244		absint( $image[1] ),
1245		absint( $image[2] )
1246	);
1247
1248	return wp_calculate_image_sizes( $size_array, $image_src, $image_meta, $attachment_id );
1249}
1250
1251/**
1252 * Creates a 'sizes' attribute value for an image.
1253 *
1254 * @since 4.4.0
1255 *
1256 * @param array|string $size          Image size to retrieve. Accepts any valid image size, or an array
1257 *                                    of width and height values in pixels (in that order). Default 'medium'.
1258 * @param string       $image_src     Optional. The URL to the image file. Default null.
1259 * @param array        $image_meta    Optional. The image meta data as returned by 'wp_get_attachment_metadata()'.
1260 *                                    Default null.
1261 * @param int          $attachment_id Optional. Image attachment ID. Either `$image_meta` or `$attachment_id`
1262 *                                    is needed when using the image size name as argument for `$size`. Default 0.
1263 * @return string|bool A valid source size value for use in a 'sizes' attribute or false.
1264 */
1265function wp_calculate_image_sizes( $size, $image_src = null, $image_meta = null, $attachment_id = 0 ) {
1266	$width = 0;
1267
1268	if ( is_array( $size ) ) {
1269		$width = absint( $size[0] );
1270	} elseif ( is_string( $size ) ) {
1271		if ( ! $image_meta && $attachment_id ) {
1272			$image_meta = wp_get_attachment_metadata( $attachment_id );
1273		}
1274
1275		if ( is_array( $image_meta ) ) {
1276			$size_array = _wp_get_image_size_from_meta( $size, $image_meta );
1277			if ( $size_array ) {
1278				$width = absint( $size_array[0] );
1279			}
1280		}
1281	}
1282
1283	if ( ! $width ) {
1284		return false;
1285	}
1286
1287	// Setup the default 'sizes' attribute.
1288	$sizes = sprintf( '(max-width: %1$dpx) 100vw, %1$dpx', $width );
1289
1290	/**
1291	 * Filters the output of 'wp_calculate_image_sizes()'.
1292	 *
1293	 * @since 4.4.0
1294	 *
1295	 * @param string       $sizes         A source size value for use in a 'sizes' attribute.
1296	 * @param array|string $size          Requested size. Image size or array of width and height values
1297	 *                                    in pixels (in that order).
1298	 * @param string|null  $image_src     The URL to the image file or null.
1299	 * @param array|null   $image_meta    The image meta data as returned by wp_get_attachment_metadata() or null.
1300	 * @param int          $attachment_id Image attachment ID of the original image or 0.
1301	 */
1302	return apply_filters( 'wp_calculate_image_sizes', $sizes, $size, $image_src, $image_meta, $attachment_id );
1303}
1304
1305/**
1306 * Filters 'img' elements in post content to add 'srcset' and 'sizes' attributes.
1307 *
1308 * @since 4.4.0
1309 *
1310 * @see wp_image_add_srcset_and_sizes()
1311 *
1312 * @param string $content The raw post content to be filtered.
1313 * @return string Converted content with 'srcset' and 'sizes' attributes added to images.
1314 */
1315function wp_make_content_images_responsive( $content ) {
1316	if ( ! preg_match_all( '/<img [^>]+>/', $content, $matches ) ) {
1317		return $content;
1318	}
1319
1320	$selected_images = $attachment_ids = array();
1321
1322	foreach( $matches[0] as $image ) {
1323		if ( false === strpos( $image, ' srcset=' ) && preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) &&
1324			( $attachment_id = absint( $class_id[1] ) ) ) {
1325
1326			/*
1327			 * If exactly the same image tag is used more than once, overwrite it.
1328			 * All identical tags will be replaced later with 'str_replace()'.
1329			 */
1330			$selected_images[ $image ] = $attachment_…

Large files files are truncated, but you can click here to view the full file