~canonical-sysadmins/wordpress/4.7.2

« back to all changes in this revision

Viewing changes to wp-includes/media.php

  • Committer: Jacek Nykis
  • Date: 2015-01-05 16:17:05 UTC
  • Revision ID: jacek.nykis@canonical.com-20150105161705-w544l1h5mcg7u4w9
Initial commit

Show diffs side-by-side

added added

removed removed

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