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