run:R W Run
7.85 KB
2026-03-11 16:18:51
R W Run
3.54 KB
2026-03-11 16:18:51
R W Run
148.33 KB
2026-03-11 16:18:51
R W Run
11.45 KB
2026-03-11 16:18:51
R W Run
3.58 KB
2026-03-11 16:18:51
R W Run
2.53 KB
2026-03-11 16:18:51
R W Run
2.6 KB
2026-03-11 16:18:51
R W Run
6.59 KB
2026-03-11 16:18:51
R W Run
14.83 KB
2026-03-11 16:18:51
R W Run
21.18 KB
2026-03-11 16:18:51
R W Run
48.13 KB
2026-03-11 16:18:51
R W Run
4.07 KB
2026-03-11 16:18:51
R W Run
5.3 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
26.73 KB
2026-03-11 16:18:51
R W Run
2.8 KB
2026-03-11 16:18:51
R W Run
15.2 KB
2026-03-11 16:18:51
R W Run
192.08 KB
2026-03-11 16:18:51
R W Run
11.77 KB
2026-03-11 16:18:51
R W Run
3.2 KB
2026-03-11 16:18:51
R W Run
22.89 KB
2026-03-11 16:18:51
R W Run
12.77 KB
2026-03-11 16:18:51
R W Run
4.08 KB
2026-03-11 16:18:51
R W Run
26.27 KB
2026-03-11 16:18:51
R W Run
4.97 KB
2026-03-11 16:18:51
R W Run
5.57 KB
2026-03-11 16:18:51
R W Run
13.93 KB
2026-03-11 16:18:51
R W Run
4.09 KB
2026-03-11 16:18:51
R W Run
6.79 KB
2026-03-11 16:18:51
R W Run
60.45 KB
2026-03-11 16:18:51
R W Run
32.4 KB
2026-03-11 16:18:51
R W Run
18.24 KB
2026-03-11 16:18:51
R W Run
66.01 KB
2026-03-11 16:18:51
R W Run
23.84 KB
2026-03-11 16:18:51
R W Run
17.72 KB
2026-03-11 16:18:51
R W Run
22.71 KB
2026-03-11 16:18:51
R W Run
18.05 KB
2026-03-11 16:18:51
R W Run
22.76 KB
2026-03-11 16:18:51
R W Run
7.34 KB
2026-03-11 16:18:51
R W Run
4.51 KB
2026-03-11 16:18:51
R W Run
9.02 KB
2026-03-11 16:18:51
R W Run
1.46 KB
2026-03-11 16:18:51
R W Run
51.76 KB
2026-03-11 16:18:51
R W Run
25.29 KB
2026-03-11 16:18:51
R W Run
21.61 KB
2026-03-11 16:18:51
R W Run
27.77 KB
2026-03-11 16:18:51
R W Run
15.35 KB
2026-03-11 16:18:51
R W Run
24.54 KB
2026-03-11 16:18:51
R W Run
56.44 KB
2026-03-11 16:18:51
R W Run
1.42 KB
2026-03-11 16:18:51
R W Run
63.66 KB
2026-03-11 16:18:51
R W Run
31.9 KB
2026-03-11 16:18:51
R W Run
14.44 KB
2026-03-11 16:18:51
R W Run
36.47 KB
2026-03-11 16:18:51
R W Run
14 KB
2026-03-11 16:18:51
R W Run
121.89 KB
2026-03-11 16:18:51
R W Run
6.26 KB
2026-03-11 16:18:51
R W Run
20.73 KB
2026-03-11 16:18:51
R W Run
15.23 KB
2026-03-11 16:18:51
R W Run
10.14 KB
2026-03-11 16:18:51
R W Run
6.94 KB
2026-03-11 16:18:51
R W Run
1.44 KB
2026-03-11 16:18:51
R W Run
46.85 KB
2026-03-11 16:18:51
R W Run
18.61 KB
2026-03-11 16:18:51
R W Run
6.08 KB
2026-03-11 16:18:51
R W Run
20.06 KB
2026-03-11 16:18:51
R W Run
5.73 KB
2026-03-11 16:18:51
R W Run
68.18 KB
2026-03-11 16:18:51
R W Run
40.8 KB
2026-03-11 16:18:51
R W Run
1.44 KB
2026-03-11 16:18:51
R W Run
25.26 KB
2026-03-11 16:18:51
R W Run
95.94 KB
2026-03-11 16:18:51
R W Run
43.12 KB
2026-03-11 16:18:51
R W Run
41.73 KB
2026-03-11 16:18:51
R W Run
6.46 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
116.31 KB
2026-03-11 16:18:51
R W Run
9.39 KB
2026-03-11 16:18:51
R W Run
64.34 KB
2026-03-11 16:18:51
R W Run
44.73 KB
2026-03-11 16:18:51
R W Run
1.27 KB
2026-03-11 16:18:51
R W Run
3.68 KB
2026-03-11 16:18:51
R W Run
33.53 KB
2026-03-11 16:18:51
R W Run
48.84 KB
2026-03-11 16:18:51
R W Run
26.35 KB
2026-03-11 16:18:51
R W Run
1.12 KB
2026-03-11 16:18:51
R W Run
4.19 KB
2026-03-11 16:18:51
R W Run
38.19 KB
2026-03-11 16:18:51
R W Run
91.33 KB
2026-03-11 16:18:51
R W Run
80.39 KB
2026-03-11 16:18:51
R W Run
32.67 KB
2026-03-11 16:18:51
R W Run
16.18 KB
2026-03-11 16:18:51
R W Run
44.46 KB
2026-03-11 16:18:51
R W Run
6.23 KB
2026-03-11 16:18:51
R W Run
8.23 KB
2026-03-11 16:18:51
R W Run
96.96 KB
2026-03-11 16:18:51
R W Run
6.83 KB
2026-03-11 16:18:51
R W Run
46.62 KB
2026-03-11 16:18:51
R W Run
10.82 KB
2026-03-11 16:18:51
R W Run
68.86 KB
2026-03-11 16:18:51
R W Run
33.63 KB
2026-03-11 16:18:51
R W Run
113.3 KB
2026-03-11 16:18:51
R W Run
22.98 KB
2026-03-11 16:18:51
R W Run
10.66 KB
2026-03-11 16:18:51
R W Run
error_log
📄media.php
1<?php
2/**
3 * WordPress Administration Media API.
4 *
5 * @package WordPress
6 * @subpackage Administration
7 */
8
9/**
10 * Defines the default media upload tabs.
11 *
12 * @since 2.5.0
13 *
14 * @return string[] Default tabs.
15 */
16function media_upload_tabs() {
17 $_default_tabs = array(
18 'type' => __( 'From Computer' ), // Handler action suffix => tab text.
19 'type_url' => __( 'From URL' ),
20 'gallery' => __( 'Gallery' ),
21 'library' => __( 'Media Library' ),
22 );
23
24 /**
25 * Filters the available tabs in the legacy (pre-3.5.0) media popup.
26 *
27 * @since 2.5.0
28 *
29 * @param string[] $_default_tabs An array of media tabs.
30 */
31 return apply_filters( 'media_upload_tabs', $_default_tabs );
32}
33
34/**
35 * Adds the gallery tab back to the tabs array if post has image attachments.
36 *
37 * @since 2.5.0
38 *
39 * @global wpdb $wpdb WordPress database abstraction object.
40 *
41 * @param array $tabs
42 * @return array $tabs with gallery if post has image attachment
43 */
44function update_gallery_tab( $tabs ) {
45 global $wpdb;
46
47 if ( ! isset( $_REQUEST['post_id'] ) ) {
48 unset( $tabs['gallery'] );
49 return $tabs;
50 }
51
52 $post_id = (int) $_REQUEST['post_id'];
53
54 if ( $post_id ) {
55 $attachments = (int) $wpdb->get_var( $wpdb->prepare( "SELECT count(*) FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status != 'trash' AND post_parent = %d", $post_id ) );
56 }
57
58 if ( empty( $attachments ) ) {
59 unset( $tabs['gallery'] );
60 return $tabs;
61 }
62
63 /* translators: %s: Number of attachments. */
64 $tabs['gallery'] = sprintf( __( 'Gallery (%s)' ), "<span id='attachments-count'>$attachments</span>" );
65
66 return $tabs;
67}
68
69/**
70 * Outputs the legacy media upload tabs UI.
71 *
72 * @since 2.5.0
73 *
74 * @global string $redir_tab
75 */
76function the_media_upload_tabs() {
77 global $redir_tab;
78 $tabs = media_upload_tabs();
79 $default = 'type';
80
81 if ( ! empty( $tabs ) ) {
82 echo "<ul id='sidemenu'>\n";
83
84 if ( isset( $redir_tab ) && array_key_exists( $redir_tab, $tabs ) ) {
85 $current = $redir_tab;
86 } elseif ( isset( $_GET['tab'] ) && array_key_exists( $_GET['tab'], $tabs ) ) {
87 $current = $_GET['tab'];
88 } else {
89 /** This filter is documented in wp-admin/media-upload.php */
90 $current = apply_filters( 'media_upload_default_tab', $default );
91 }
92
93 foreach ( $tabs as $callback => $text ) {
94 $class = '';
95
96 if ( $current === $callback ) {
97 $class = " class='current'";
98 }
99
100 $href = add_query_arg(
101 array(
102 'tab' => $callback,
103 's' => false,
104 'paged' => false,
105 'post_mime_type' => false,
106 'm' => false,
107 )
108 );
109 $link = "<a href='" . esc_url( $href ) . "'$class>$text</a>";
110 echo "\t<li id='" . esc_attr( "tab-$callback" ) . "'>$link</li>\n";
111 }
112
113 echo "</ul>\n";
114 }
115}
116
117/**
118 * Retrieves the image HTML to send to the editor.
119 *
120 * @since 2.5.0
121 *
122 * @param int $id Image attachment ID.
123 * @param string $caption Image caption.
124 * @param string $title Image title attribute.
125 * @param string $align Image CSS alignment property.
126 * @param string $url Optional. Image src URL. Default empty.
127 * @param bool|string $rel Optional. Value for rel attribute or whether to add a default value. Default false.
128 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array of
129 * width and height values in pixels (in that order). Default 'medium'.
130 * @param string $alt Optional. Image alt attribute. Default empty.
131 * @return string The HTML output to insert into the editor.
132 */
133function get_image_send_to_editor( $id, $caption, $title, $align, $url = '', $rel = false, $size = 'medium', $alt = '' ) {
134
135 $html = get_image_tag( $id, $alt, '', $align, $size );
136
137 if ( $rel ) {
138 if ( is_string( $rel ) ) {
139 $rel = ' rel="' . esc_attr( $rel ) . '"';
140 } else {
141 $rel = ' rel="attachment wp-att-' . (int) $id . '"';
142 }
143 } else {
144 $rel = '';
145 }
146
147 if ( $url ) {
148 $html = '<a href="' . esc_url( $url ) . '"' . $rel . '>' . $html . '</a>';
149 }
150
151 /**
152 * Filters the image HTML markup to send to the editor when inserting an image.
153 *
154 * @since 2.5.0
155 * @since 5.6.0 The `$rel` parameter was added.
156 *
157 * @param string $html The image HTML markup to send.
158 * @param int $id The attachment ID.
159 * @param string $caption The image caption.
160 * @param string $title The image title.
161 * @param string $align The image alignment.
162 * @param string $url The image source URL.
163 * @param string|int[] $size Requested image size. Can be any registered image size name, or
164 * an array of width and height values in pixels (in that order).
165 * @param string $alt The image alternative, or alt, text.
166 * @param string $rel The image rel attribute.
167 */
168 $html = apply_filters( 'image_send_to_editor', $html, $id, $caption, $title, $align, $url, $size, $alt, $rel );
169
170 return $html;
171}
172
173/**
174 * Adds image shortcode with caption to editor.
175 *
176 * @since 2.6.0
177 *
178 * @param string $html The image HTML markup to send.
179 * @param int $id Image attachment ID.
180 * @param string $caption Image caption.
181 * @param string $title Image title attribute (not used).
182 * @param string $align Image CSS alignment property.
183 * @param string $url Image source URL (not used).
184 * @param string $size Image size (not used).
185 * @param string $alt Image `alt` attribute (not used).
186 * @return string The image HTML markup with caption shortcode.
187 */
188function image_add_caption( $html, $id, $caption, $title, $align, $url, $size, $alt = '' ) {
189
190 /**
191 * Filters the caption text.
192 *
193 * Note: If the caption text is empty, the caption shortcode will not be appended
194 * to the image HTML when inserted into the editor.
195 *
196 * Passing an empty value also prevents the {@see 'image_add_caption_shortcode'}
197 * Filters from being evaluated at the end of image_add_caption().
198 *
199 * @since 4.1.0
200 *
201 * @param string $caption The original caption text.
202 * @param int $id The attachment ID.
203 */
204 $caption = apply_filters( 'image_add_caption_text', $caption, $id );
205
206 /**
207 * Filters whether to disable captions.
208 *
209 * Prevents image captions from being appended to image HTML when inserted into the editor.
210 *
211 * @since 2.6.0
212 *
213 * @param bool $bool Whether to disable appending captions. Returning true from the filter
214 * will disable captions. Default empty string.
215 */
216 if ( empty( $caption ) || apply_filters( 'disable_captions', '' ) ) {
217 return $html;
218 }
219
220 $id = ( 0 < (int) $id ) ? 'attachment_' . $id : '';
221
222 if ( ! preg_match( '/width=["\']([0-9]+)/', $html, $matches ) ) {
223 return $html;
224 }
225
226 $width = $matches[1];
227
228 $caption = str_replace( array( "\r\n", "\r" ), "\n", $caption );
229 $caption = preg_replace_callback( '/<[a-zA-Z0-9]+(?: [^<>]+>)*/', '_cleanup_image_add_caption', $caption );
230
231 // Convert any remaining line breaks to <br />.
232 $caption = preg_replace( '/[ \n\t]*\n[ \t]*/', '<br />', $caption );
233
234 $html = preg_replace( '/(class=["\'][^\'"]*)align(none|left|right|center)\s?/', '$1', $html );
235 if ( empty( $align ) ) {
236 $align = 'none';
237 }
238
239 $shcode = '[caption id="' . $id . '" align="align' . $align . '" width="' . $width . '"]' . $html . ' ' . $caption . '[/caption]';
240
241 /**
242 * Filters the image HTML markup including the caption shortcode.
243 *
244 * @since 2.6.0
245 *
246 * @param string $shcode The image HTML markup with caption shortcode.
247 * @param string $html The image HTML markup.
248 */
249 return apply_filters( 'image_add_caption_shortcode', $shcode, $html );
250}
251
252/**
253 * Private preg_replace callback used in image_add_caption().
254 *
255 * @access private
256 * @since 3.4.0
257 *
258 * @param array $matches Single regex match.
259 * @return string Cleaned up HTML for caption.
260 */
261function _cleanup_image_add_caption( $matches ) {
262 // Remove any line breaks from inside the tags.
263 return preg_replace( '/[\r\n\t]+/', ' ', $matches[0] );
264}
265
266/**
267 * Adds image HTML to editor.
268 *
269 * @since 2.5.0
270 *
271 * @param string $html
272 */
273function media_send_to_editor( $html ) {
274 ?>
275 <script type="text/javascript">
276 var win = window.dialogArguments || opener || parent || top;
277 win.send_to_editor( <?php echo wp_json_encode( $html, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); ?> );
278 </script>
279 <?php
280 exit;
281}
282
283/**
284 * Saves a file submitted from a POST request and create an attachment post for it.
285 *
286 * @since 2.5.0
287 *
288 * @param string $file_id Index of the `$_FILES` array that the file was sent.
289 * @param int $post_id The post ID of a post to attach the media item to. Required, but can
290 * be set to 0, creating a media item that has no relationship to a post.
291 * @param array $post_data Optional. Overwrite some of the attachment.
292 * @param array $overrides Optional. Override the wp_handle_upload() behavior.
293 * @return int|WP_Error ID of the attachment or a WP_Error object on failure.
294 */
295function media_handle_upload( $file_id, $post_id, $post_data = array(), $overrides = array( 'test_form' => false ) ) {
296 $time = current_time( 'mysql' );
297 $post = get_post( $post_id );
298
299 if ( $post ) {
300 // The post date doesn't usually matter for pages, so don't backdate this upload.
301 if ( 'page' !== $post->post_type && substr( $post->post_date, 0, 4 ) > 0 ) {
302 $time = $post->post_date;
303 }
304 }
305
306 $file = wp_handle_upload( $_FILES[ $file_id ], $overrides, $time );
307
308 if ( isset( $file['error'] ) ) {
309 return new WP_Error( 'upload_error', $file['error'] );
310 }
311
312 $name = $_FILES[ $file_id ]['name'];
313 $ext = pathinfo( $name, PATHINFO_EXTENSION );
314 $name = wp_basename( $name, ".$ext" );
315
316 $url = $file['url'];
317 $type = $file['type'];
318 $file = $file['file'];
319 $title = sanitize_text_field( $name );
320 $content = '';
321 $excerpt = '';
322
323 if ( preg_match( '#^audio#', $type ) ) {
324 $meta = wp_read_audio_metadata( $file );
325
326 if ( ! empty( $meta['title'] ) ) {
327 $title = $meta['title'];
328 }
329
330 if ( ! empty( $title ) ) {
331
332 if ( ! empty( $meta['album'] ) && ! empty( $meta['artist'] ) ) {
333 /* translators: 1: Audio track title, 2: Album title, 3: Artist name. */
334 $content .= sprintf( __( '"%1$s" from %2$s by %3$s.' ), $title, $meta['album'], $meta['artist'] );
335 } elseif ( ! empty( $meta['album'] ) ) {
336 /* translators: 1: Audio track title, 2: Album title. */
337 $content .= sprintf( __( '"%1$s" from %2$s.' ), $title, $meta['album'] );
338 } elseif ( ! empty( $meta['artist'] ) ) {
339 /* translators: 1: Audio track title, 2: Artist name. */
340 $content .= sprintf( __( '"%1$s" by %2$s.' ), $title, $meta['artist'] );
341 } else {
342 /* translators: %s: Audio track title. */
343 $content .= sprintf( __( '"%s".' ), $title );
344 }
345 } elseif ( ! empty( $meta['album'] ) ) {
346
347 if ( ! empty( $meta['artist'] ) ) {
348 /* translators: 1: Audio album title, 2: Artist name. */
349 $content .= sprintf( __( '%1$s by %2$s.' ), $meta['album'], $meta['artist'] );
350 } else {
351 $content .= $meta['album'] . '.';
352 }
353 } elseif ( ! empty( $meta['artist'] ) ) {
354
355 $content .= $meta['artist'] . '.';
356
357 }
358
359 if ( ! empty( $meta['year'] ) ) {
360 /* translators: Audio file track information. %d: Year of audio track release. */
361 $content .= ' ' . sprintf( __( 'Released: %d.' ), $meta['year'] );
362 }
363
364 if ( ! empty( $meta['track_number'] ) ) {
365 $track_number = explode( '/', $meta['track_number'] );
366
367 if ( is_numeric( $track_number[0] ) ) {
368 if ( isset( $track_number[1] ) && is_numeric( $track_number[1] ) ) {
369 $content .= ' ' . sprintf(
370 /* translators: Audio file track information. 1: Audio track number, 2: Total audio tracks. */
371 __( 'Track %1$s of %2$s.' ),
372 number_format_i18n( $track_number[0] ),
373 number_format_i18n( $track_number[1] )
374 );
375 } else {
376 $content .= ' ' . sprintf(
377 /* translators: Audio file track information. %s: Audio track number. */
378 __( 'Track %s.' ),
379 number_format_i18n( $track_number[0] )
380 );
381 }
382 }
383 }
384
385 if ( ! empty( $meta['genre'] ) ) {
386 /* translators: Audio file genre information. %s: Audio genre name. */
387 $content .= ' ' . sprintf( __( 'Genre: %s.' ), $meta['genre'] );
388 }
389
390 // Use image exif/iptc data for title and caption defaults if possible.
391 } elseif ( str_starts_with( $type, 'image/' ) ) {
392 $image_meta = wp_read_image_metadata( $file );
393
394 if ( $image_meta ) {
395 if ( trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) {
396 $title = $image_meta['title'];
397 }
398
399 if ( trim( $image_meta['caption'] ) ) {
400 $excerpt = $image_meta['caption'];
401 }
402 }
403 }
404
405 // Construct the attachment array.
406 $attachment = array_merge(
407 array(
408 'post_mime_type' => $type,
409 'guid' => $url,
410 'post_parent' => $post_id,
411 'post_title' => $title,
412 'post_content' => $content,
413 'post_excerpt' => $excerpt,
414 ),
415 $post_data
416 );
417
418 // This should never be set as it would then overwrite an existing attachment.
419 unset( $attachment['ID'] );
420
421 // Save the data.
422 $attachment_id = wp_insert_attachment( $attachment, $file, $post_id, true );
423
424 if ( ! is_wp_error( $attachment_id ) ) {
425 /*
426 * Set a custom header with the attachment_id.
427 * Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
428 */
429 if ( ! headers_sent() ) {
430 header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id );
431 }
432
433 /*
434 * The image sub-sizes are created during wp_generate_attachment_metadata().
435 * This is generally slow and may cause timeouts or out of memory errors.
436 */
437 wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
438 }
439
440 return $attachment_id;
441}
442
443/**
444 * Handles a side-loaded file in the same way as an uploaded file is handled by media_handle_upload().
445 *
446 * @since 2.6.0
447 * @since 5.3.0 The `$post_id` parameter was made optional.
448 *
449 * @param string[] $file_array Array that represents a `$_FILES` upload array.
450 * @param int $post_id Optional. The post ID the media is associated with.
451 * @param string $desc Optional. Description of the side-loaded file. Default null.
452 * @param array $post_data Optional. Post data to override. Default empty array.
453 * @return int|WP_Error The ID of the attachment or a WP_Error on failure.
454 */
455function media_handle_sideload( $file_array, $post_id = 0, $desc = null, $post_data = array() ) {
456 $overrides = array( 'test_form' => false );
457
458 if ( isset( $post_data['post_date'] ) && substr( $post_data['post_date'], 0, 4 ) > 0 ) {
459 $time = $post_data['post_date'];
460 } else {
461 $post = get_post( $post_id );
462 if ( $post && substr( $post->post_date, 0, 4 ) > 0 ) {
463 $time = $post->post_date;
464 } else {
465 $time = current_time( 'mysql' );
466 }
467 }
468
469 $file = wp_handle_sideload( $file_array, $overrides, $time );
470
471 if ( isset( $file['error'] ) ) {
472 return new WP_Error( 'upload_error', $file['error'] );
473 }
474
475 $url = $file['url'];
476 $type = $file['type'];
477 $file = $file['file'];
478 $title = preg_replace( '/\.[^.]+$/', '', wp_basename( $file ) );
479 $content = '';
480
481 // Use image exif/iptc data for title and caption defaults if possible.
482 $image_meta = wp_read_image_metadata( $file );
483
484 if ( $image_meta ) {
485 if ( trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) {
486 $title = $image_meta['title'];
487 }
488
489 if ( trim( $image_meta['caption'] ) ) {
490 $content = $image_meta['caption'];
491 }
492 }
493
494 if ( isset( $desc ) ) {
495 $title = $desc;
496 }
497
498 // Construct the attachment array.
499 $attachment = array_merge(
500 array(
501 'post_mime_type' => $type,
502 'guid' => $url,
503 'post_parent' => $post_id,
504 'post_title' => $title,
505 'post_content' => $content,
506 ),
507 $post_data
508 );
509
510 // This should never be set as it would then overwrite an existing attachment.
511 unset( $attachment['ID'] );
512
513 // Save the attachment metadata.
514 $attachment_id = wp_insert_attachment( $attachment, $file, $post_id, true );
515
516 if ( ! is_wp_error( $attachment_id ) ) {
517 wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
518 }
519
520 return $attachment_id;
521}
522
523/**
524 * Outputs the iframe to display the media upload page.
525 *
526 * @since 2.5.0
527 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
528 * by adding it to the function signature.
529 *
530 * @global string $body_id
531 *
532 * @param callable $content_func Function that outputs the content.
533 * @param mixed ...$args Optional additional parameters to pass to the callback function when it's called.
534 */
535function wp_iframe( $content_func, ...$args ) {
536 global $body_id;
537
538 _wp_admin_html_begin();
539 ?>
540 <title><?php bloginfo( 'name' ); ?> &rsaquo; <?php _e( 'Uploads' ); ?> &#8212; <?php _e( 'WordPress' ); ?></title>
541 <?php
542
543 wp_enqueue_style( 'colors' );
544 // Check callback name for 'media'.
545 if (
546 ( is_array( $content_func ) && ! empty( $content_func[1] ) && str_starts_with( (string) $content_func[1], 'media' ) ) ||
547 ( ! is_array( $content_func ) && str_starts_with( $content_func, 'media' ) )
548 ) {
549 wp_enqueue_style( 'deprecated-media' );
550 }
551
552 ?>
553 <script type="text/javascript">
554 addLoadEvent = function(func){if(typeof jQuery!=='undefined')jQuery(function(){func();});else if(typeof wpOnload!=='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
555 var ajaxurl = '<?php echo esc_js( admin_url( 'admin-ajax.php', 'relative' ) ); ?>', pagenow = 'media-upload-popup', adminpage = 'media-upload-popup',
556 isRtl = <?php echo (int) is_rtl(); ?>;
557 </script>
558 <?php
559 /** This action is documented in wp-admin/admin-header.php */
560 do_action( 'admin_enqueue_scripts', 'media-upload-popup' );
561
562 /**
563 * Fires when admin styles enqueued for the legacy (pre-3.5.0) media upload popup are printed.
564 *
565 * @since 2.9.0
566 */
567 do_action( 'admin_print_styles-media-upload-popup' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
568
569 /** This action is documented in wp-admin/admin-header.php */
570 do_action( 'admin_print_styles' );
571
572 /**
573 * Fires when admin scripts enqueued for the legacy (pre-3.5.0) media upload popup are printed.
574 *
575 * @since 2.9.0
576 */
577 do_action( 'admin_print_scripts-media-upload-popup' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
578
579 /** This action is documented in wp-admin/admin-header.php */
580 do_action( 'admin_print_scripts' );
581
582 /**
583 * Fires when scripts enqueued for the admin header for the legacy (pre-3.5.0)
584 * media upload popup are printed.
585 *
586 * @since 2.9.0
587 */
588 do_action( 'admin_head-media-upload-popup' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
589
590 /** This action is documented in wp-admin/admin-header.php */
591 do_action( 'admin_head' );
592
593 if ( is_string( $content_func ) ) {
594 /**
595 * Fires in the admin header for each specific form tab in the legacy
596 * (pre-3.5.0) media upload popup.
597 *
598 * The dynamic portion of the hook name, `$content_func`, refers to the form
599 * callback for the media upload type.
600 *
601 * @since 2.5.0
602 */
603 do_action( "admin_head_{$content_func}" );
604 }
605
606 $body_id_attr = '';
607
608 if ( isset( $body_id ) ) {
609 $body_id_attr = ' id="' . $body_id . '"';
610 }
611
612 ?>
613 </head>
614 <body<?php echo $body_id_attr; ?> class="wp-core-ui no-js">
615 <script type="text/javascript">
616 document.body.className = document.body.className.replace('no-js', 'js');
617 </script>
618 <?php
619
620 call_user_func_array( $content_func, $args );
621
622 /** This action is documented in wp-admin/admin-footer.php */
623 do_action( 'admin_print_footer_scripts' );
624
625 ?>
626 <script type="text/javascript">if(typeof wpOnload==='function')wpOnload();</script>
627 </body>
628 </html>
629 <?php
630}
631
632/**
633 * Adds the media button to the editor.
634 *
635 * @since 2.5.0
636 *
637 * @global int $post_ID
638 *
639 * @param string $editor_id
640 */
641function media_buttons( $editor_id = 'content' ) {
642 static $instance = 0;
643 ++$instance;
644
645 $post = get_post();
646
647 if ( ! $post && ! empty( $GLOBALS['post_ID'] ) ) {
648 $post = $GLOBALS['post_ID'];
649 }
650
651 wp_enqueue_media( array( 'post' => $post ) );
652
653 $img = '<span class="wp-media-buttons-icon" aria-hidden="true"></span> ';
654
655 $id_attribute = 1 === $instance ? ' id="insert-media-button"' : '';
656
657 printf(
658 '<button type="button"%s class="button insert-media add_media" data-editor="%s" aria-haspopup="dialog" aria-controls="wp-media-modal">%s</button>',
659 $id_attribute,
660 esc_attr( $editor_id ),
661 $img . __( 'Add Media' )
662 );
663
664 /**
665 * Filters the legacy (pre-3.5.0) media buttons.
666 *
667 * Use {@see 'media_buttons'} action instead.
668 *
669 * @since 2.5.0
670 * @deprecated 3.5.0 Use {@see 'media_buttons'} action instead.
671 *
672 * @param string $string Media buttons context. Default empty.
673 */
674 $legacy_filter = apply_filters_deprecated( 'media_buttons_context', array( '' ), '3.5.0', 'media_buttons' );
675
676 if ( $legacy_filter ) {
677 // #WP22559. Close <a> if a plugin started by closing <a> to open their own <a> tag.
678 if ( 0 === stripos( trim( $legacy_filter ), '</a>' ) ) {
679 $legacy_filter .= '</a>';
680 }
681 echo $legacy_filter;
682 }
683}
684
685/**
686 * Retrieves the upload iframe source URL.
687 *
688 * @since 3.0.0
689 *
690 * @global int $post_ID
691 *
692 * @param string $type Media type.
693 * @param int $post_id Post ID.
694 * @param string $tab Media upload tab.
695 * @return string Upload iframe source URL.
696 */
697function get_upload_iframe_src( $type = null, $post_id = null, $tab = null ) {
698 global $post_ID;
699
700 if ( empty( $post_id ) ) {
701 $post_id = $post_ID;
702 }
703
704 $upload_iframe_src = add_query_arg( 'post_id', (int) $post_id, admin_url( 'media-upload.php' ) );
705
706 if ( $type && 'media' !== $type ) {
707 $upload_iframe_src = add_query_arg( 'type', $type, $upload_iframe_src );
708 }
709
710 if ( ! empty( $tab ) ) {
711 $upload_iframe_src = add_query_arg( 'tab', $tab, $upload_iframe_src );
712 }
713
714 /**
715 * Filters the upload iframe source URL for a specific media type.
716 *
717 * The dynamic portion of the hook name, `$type`, refers to the type
718 * of media uploaded.
719 *
720 * Possible hook names include:
721 *
722 * - `image_upload_iframe_src`
723 * - `media_upload_iframe_src`
724 *
725 * @since 3.0.0
726 *
727 * @param string $upload_iframe_src The upload iframe source URL.
728 */
729 $upload_iframe_src = apply_filters( "{$type}_upload_iframe_src", $upload_iframe_src );
730
731 return add_query_arg( 'TB_iframe', true, $upload_iframe_src );
732}
733
734/**
735 * Handles form submissions for the legacy media uploader.
736 *
737 * @since 2.5.0
738 *
739 * @return null|array|void Array of error messages keyed by attachment ID, null or void on success.
740 */
741function media_upload_form_handler() {
742 check_admin_referer( 'media-form' );
743
744 $errors = null;
745
746 if ( isset( $_POST['send'] ) ) {
747 $keys = array_keys( $_POST['send'] );
748 $send_id = (int) reset( $keys );
749 }
750
751 if ( ! empty( $_POST['attachments'] ) ) {
752 foreach ( $_POST['attachments'] as $attachment_id => $attachment ) {
753 $post = get_post( $attachment_id, ARRAY_A );
754 $_post = $post;
755
756 if ( ! current_user_can( 'edit_post', $attachment_id ) ) {
757 continue;
758 }
759
760 if ( isset( $attachment['post_content'] ) ) {
761 $post['post_content'] = $attachment['post_content'];
762 }
763
764 if ( isset( $attachment['post_title'] ) ) {
765 $post['post_title'] = $attachment['post_title'];
766 }
767
768 if ( isset( $attachment['post_excerpt'] ) ) {
769 $post['post_excerpt'] = $attachment['post_excerpt'];
770 }
771
772 if ( isset( $attachment['menu_order'] ) ) {
773 $post['menu_order'] = $attachment['menu_order'];
774 }
775
776 if ( isset( $send_id ) && $attachment_id === $send_id ) {
777 if ( isset( $attachment['post_parent'] ) ) {
778 $post['post_parent'] = $attachment['post_parent'];
779 }
780 }
781
782 /**
783 * Filters the attachment fields to be saved.
784 *
785 * @since 2.5.0
786 *
787 * @see wp_get_attachment_metadata()
788 *
789 * @param array $post An array of post data.
790 * @param array $attachment An array of attachment metadata.
791 */
792 $post = apply_filters( 'attachment_fields_to_save', $post, $attachment );
793
794 if ( isset( $attachment['image_alt'] ) ) {
795 $image_alt = wp_unslash( $attachment['image_alt'] );
796
797 if ( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) !== $image_alt ) {
798 $image_alt = wp_strip_all_tags( $image_alt, true );
799
800 // update_post_meta() expects slashed.
801 update_post_meta( $attachment_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) );
802 }
803 }
804
805 if ( isset( $post['errors'] ) ) {
806 $errors[ $attachment_id ] = $post['errors'];
807 unset( $post['errors'] );
808 }
809
810 if ( $post != $_post ) {
811 wp_update_post( $post );
812 }
813
814 foreach ( get_attachment_taxonomies( $post ) as $t ) {
815 if ( isset( $attachment[ $t ] ) ) {
816 wp_set_object_terms( $attachment_id, array_map( 'trim', preg_split( '/,+/', $attachment[ $t ] ) ), $t, false );
817 }
818 }
819 }
820 }
821
822 if ( isset( $_POST['insert-gallery'] ) || isset( $_POST['update-gallery'] ) ) {
823 ?>
824 <script type="text/javascript">
825 var win = window.dialogArguments || opener || parent || top;
826 win.tb_remove();
827 </script>
828 <?php
829
830 exit;
831 }
832
833 if ( isset( $send_id ) ) {
834 $attachment = wp_unslash( $_POST['attachments'][ $send_id ] );
835 $html = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
836
837 if ( ! empty( $attachment['url'] ) ) {
838 $rel = '';
839
840 if ( str_contains( $attachment['url'], 'attachment_id' ) || get_attachment_link( $send_id ) === $attachment['url'] ) {
841 $rel = " rel='attachment wp-att-" . esc_attr( $send_id ) . "'";
842 }
843
844 $html = "<a href='{$attachment['url']}'$rel>$html</a>";
845 }
846
847 /**
848 * Filters the HTML markup for a media item sent to the editor.
849 *
850 * @since 2.5.0
851 *
852 * @see wp_get_attachment_metadata()
853 *
854 * @param string $html HTML markup for a media item sent to the editor.
855 * @param int $send_id The first key from the $_POST['send'] data.
856 * @param array $attachment Array of attachment metadata.
857 */
858 $html = apply_filters( 'media_send_to_editor', $html, $send_id, $attachment );
859
860 return media_send_to_editor( $html );
861 }
862
863 return $errors;
864}
865
866/**
867 * Handles the process of uploading media.
868 *
869 * @since 2.5.0
870 *
871 * @return null|string
872 */
873function wp_media_upload_handler() {
874 $errors = array();
875 $id = 0;
876
877 if ( isset( $_POST['html-upload'] ) && ! empty( $_FILES ) ) {
878 check_admin_referer( 'media-form' );
879 // Upload File button was clicked.
880 $id = media_handle_upload( 'async-upload', $_REQUEST['post_id'] );
881 unset( $_FILES );
882
883 if ( is_wp_error( $id ) ) {
884 $errors['upload_error'] = $id;
885 $id = false;
886 }
887 }
888
889 if ( ! empty( $_POST['insertonlybutton'] ) ) {
890 $src = $_POST['src'];
891
892 if ( ! empty( $src ) && ! strpos( $src, '://' ) ) {
893 $src = "http://$src";
894 }
895
896 if ( isset( $_POST['media_type'] ) && 'image' !== $_POST['media_type'] ) {
897 $title = esc_html( wp_unslash( $_POST['title'] ) );
898 if ( empty( $title ) ) {
899 $title = esc_html( wp_basename( $src ) );
900 }
901
902 if ( $title && $src ) {
903 $html = "<a href='" . esc_url( $src ) . "'>$title</a>";
904 }
905
906 $type = 'file';
907 $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src );
908
909 if ( $ext ) {
910 $ext_type = wp_ext2type( $ext );
911 if ( 'audio' === $ext_type || 'video' === $ext_type ) {
912 $type = $ext_type;
913 }
914 }
915
916 /**
917 * Filters the URL sent to the editor for a specific media type.
918 *
919 * The dynamic portion of the hook name, `$type`, refers to the type
920 * of media being sent.
921 *
922 * Possible hook names include:
923 *
924 * - `audio_send_to_editor_url`
925 * - `file_send_to_editor_url`
926 * - `video_send_to_editor_url`
927 *
928 * @since 3.3.0
929 *
930 * @param string $html HTML markup sent to the editor.
931 * @param string $src Media source URL.
932 * @param string $title Media title.
933 */
934 $html = apply_filters( "{$type}_send_to_editor_url", $html, sanitize_url( $src ), $title );
935 } else {
936 $align = '';
937 $alt = esc_attr( wp_unslash( $_POST['alt'] ) );
938
939 if ( isset( $_POST['align'] ) ) {
940 $align = esc_attr( wp_unslash( $_POST['align'] ) );
941 $class = " class='align$align'";
942 }
943
944 if ( ! empty( $src ) ) {
945 $html = "<img src='" . esc_url( $src ) . "' alt='$alt'$class />";
946 }
947
948 /**
949 * Filters the image URL sent to the editor.
950 *
951 * @since 2.8.0
952 *
953 * @param string $html HTML markup sent to the editor for an image.
954 * @param string $src Image source URL.
955 * @param string $alt Image alternate, or alt, text.
956 * @param string $align The image alignment. Default 'alignnone'. Possible values include
957 * 'alignleft', 'aligncenter', 'alignright', 'alignnone'.
958 */
959 $html = apply_filters( 'image_send_to_editor_url', $html, sanitize_url( $src ), $alt, $align );
960 }
961
962 return media_send_to_editor( $html );
963 }
964
965 if ( isset( $_POST['save'] ) ) {
966 $errors['upload_notice'] = __( 'Saved.' );
967 wp_enqueue_script( 'admin-gallery' );
968
969 return wp_iframe( 'media_upload_gallery_form', $errors );
970
971 } elseif ( ! empty( $_POST ) ) {
972 $return = media_upload_form_handler();
973
974 if ( is_string( $return ) ) {
975 return $return;
976 }
977
978 if ( is_array( $return ) ) {
979 $errors = $return;
980 }
981 }
982
983 if ( isset( $_GET['tab'] ) && 'type_url' === $_GET['tab'] ) {
984 $type = 'image';
985
986 if ( isset( $_GET['type'] ) && in_array( $_GET['type'], array( 'video', 'audio', 'file' ), true ) ) {
987 $type = $_GET['type'];
988 }
989
990 return wp_iframe( 'media_upload_type_url_form', $type, $errors, $id );
991 }
992
993 return wp_iframe( 'media_upload_type_form', 'image', $errors, $id );
994}
995
996/**
997 * Downloads an image from the specified URL, saves it as an attachment, and optionally attaches it to a post.
998 *
999 * @since 2.6.0
1000 * @since 4.2.0 Introduced the `$return_type` parameter.
1001 * @since 4.8.0 Introduced the 'id' option for the `$return_type` parameter.
1002 * @since 5.3.0 The `$post_id` parameter was made optional.
1003 * @since 5.4.0 The original URL of the attachment is stored in the `_source_url`
1004 * post meta value.
1005 * @since 5.8.0 Added 'webp' to the default list of allowed file extensions.
1006 *
1007 * @param string $file The URL of the image to download.
1008 * @param int $post_id Optional. The post ID the media is to be associated with.
1009 * @param string $desc Optional. Description of the image.
1010 * @param string $return_type Optional. Accepts 'html' (image tag html) or 'src' (URL),
1011 * or 'id' (attachment ID). Default 'html'.
1012 * @return string|int|WP_Error Populated HTML img tag, attachment ID, or attachment source
1013 * on success, WP_Error object otherwise.
1014 */
1015function media_sideload_image( $file, $post_id = 0, $desc = null, $return_type = 'html' ) {
1016 if ( ! empty( $file ) ) {
1017
1018 $allowed_extensions = array( 'jpg', 'jpeg', 'jpe', 'png', 'gif', 'webp' );
1019
1020 /**
1021 * Filters the list of allowed file extensions when sideloading an image from a URL.
1022 *
1023 * The default allowed extensions are:
1024 *
1025 * - `jpg`
1026 * - `jpeg`
1027 * - `jpe`
1028 * - `png`
1029 * - `gif`
1030 * - `webp`
1031 *
1032 * @since 5.6.0
1033 * @since 5.8.0 Added 'webp' to the default list of allowed file extensions.
1034 *
1035 * @param string[] $allowed_extensions Array of allowed file extensions.
1036 * @param string $file The URL of the image to download.
1037 */
1038 $allowed_extensions = apply_filters( 'image_sideload_extensions', $allowed_extensions, $file );
1039 $allowed_extensions = array_map( 'preg_quote', $allowed_extensions );
1040
1041 // Set variables for storage, fix file filename for query strings.
1042 preg_match( '/[^\?]+\.(' . implode( '|', $allowed_extensions ) . ')\b/i', $file, $matches );
1043
1044 if ( ! $matches ) {
1045 return new WP_Error( 'image_sideload_failed', __( 'Invalid image URL.' ) );
1046 }
1047
1048 $file_array = array();
1049 $file_array['name'] = wp_basename( $matches[0] );
1050
1051 // Download file to temp location.
1052 $file_array['tmp_name'] = download_url( $file );
1053
1054 // If error storing temporarily, return the error.
1055 if ( is_wp_error( $file_array['tmp_name'] ) ) {
1056 return $file_array['tmp_name'];
1057 }
1058
1059 // Do the validation and storage stuff.
1060 $id = media_handle_sideload( $file_array, $post_id, $desc );
1061
1062 // If error storing permanently, unlink.
1063 if ( is_wp_error( $id ) ) {
1064 @unlink( $file_array['tmp_name'] );
1065 return $id;
1066 }
1067
1068 // Store the original attachment source in meta.
1069 add_post_meta( $id, '_source_url', $file );
1070
1071 // If attachment ID was requested, return it.
1072 if ( 'id' === $return_type ) {
1073 return $id;
1074 }
1075
1076 $src = wp_get_attachment_url( $id );
1077 }
1078
1079 // Finally, check to make sure the file has been saved, then return the HTML.
1080 if ( ! empty( $src ) ) {
1081 if ( 'src' === $return_type ) {
1082 return $src;
1083 }
1084
1085 $alt = isset( $desc ) ? esc_attr( $desc ) : '';
1086 $html = "<img src='$src' alt='$alt' />";
1087
1088 return $html;
1089 } else {
1090 return new WP_Error( 'image_sideload_failed' );
1091 }
1092}
1093
1094/**
1095 * Retrieves the legacy media uploader form in an iframe.
1096 *
1097 * @since 2.5.0
1098 *
1099 * @return string|null
1100 */
1101function media_upload_gallery() {
1102 $errors = array();
1103
1104 if ( ! empty( $_POST ) ) {
1105 $return = media_upload_form_handler();
1106
1107 if ( is_string( $return ) ) {
1108 return $return;
1109 }
1110
1111 if ( is_array( $return ) ) {
1112 $errors = $return;
1113 }
1114 }
1115
1116 wp_enqueue_script( 'admin-gallery' );
1117 return wp_iframe( 'media_upload_gallery_form', $errors );
1118}
1119
1120/**
1121 * Retrieves the legacy media library form in an iframe.
1122 *
1123 * @since 2.5.0
1124 *
1125 * @return string|null
1126 */
1127function media_upload_library() {
1128 $errors = array();
1129
1130 if ( ! empty( $_POST ) ) {
1131 $return = media_upload_form_handler();
1132
1133 if ( is_string( $return ) ) {
1134 return $return;
1135 }
1136 if ( is_array( $return ) ) {
1137 $errors = $return;
1138 }
1139 }
1140
1141 return wp_iframe( 'media_upload_library_form', $errors );
1142}
1143
1144/**
1145 * Retrieves HTML for the image alignment radio buttons with the specified one checked.
1146 *
1147 * @since 2.7.0
1148 *
1149 * @param WP_Post $post
1150 * @param string $checked
1151 * @return string
1152 */
1153function image_align_input_fields( $post, $checked = '' ) {
1154
1155 if ( empty( $checked ) ) {
1156 $checked = get_user_setting( 'align', 'none' );
1157 }
1158
1159 $alignments = array(
1160 'none' => __( 'None' ),
1161 'left' => __( 'Left' ),
1162 'center' => __( 'Center' ),
1163 'right' => __( 'Right' ),
1164 );
1165
1166 if ( ! array_key_exists( (string) $checked, $alignments ) ) {
1167 $checked = 'none';
1168 }
1169
1170 $output = array();
1171
1172 foreach ( $alignments as $name => $label ) {
1173 $name = esc_attr( $name );
1174 $output[] = "<input type='radio' name='attachments[{$post->ID}][align]' id='image-align-{$name}-{$post->ID}' value='$name'" .
1175 ( $checked === $name ? " checked='checked'" : '' ) .
1176 " /><label for='image-align-{$name}-{$post->ID}' class='align image-align-{$name}-label'>$label</label>";
1177 }
1178
1179 return implode( "\n", $output );
1180}
1181
1182/**
1183 * Retrieves HTML for the size radio buttons with the specified one checked.
1184 *
1185 * @since 2.7.0
1186 *
1187 * @param WP_Post $post
1188 * @param bool|string $check
1189 * @return array
1190 */
1191function image_size_input_fields( $post, $check = '' ) {
1192 /**
1193 * Filters the names and labels of the default image sizes.
1194 *
1195 * @since 3.3.0
1196 *
1197 * @param string[] $size_names Array of image size labels keyed by their name. Default values
1198 * include 'Thumbnail', 'Medium', 'Large', and 'Full Size'.
1199 */
1200 $size_names = apply_filters(
1201 'image_size_names_choose',
1202 array(
1203 'thumbnail' => __( 'Thumbnail' ),
1204 'medium' => __( 'Medium' ),
1205 'large' => __( 'Large' ),
1206 'full' => __( 'Full Size' ),
1207 )
1208 );
1209
1210 if ( empty( $check ) ) {
1211 $check = get_user_setting( 'imgsize', 'medium' );
1212 }
1213
1214 $output = array();
1215
1216 foreach ( $size_names as $size => $label ) {
1217 $downsize = image_downsize( $post->ID, $size );
1218 $checked = '';
1219
1220 // Is this size selectable?
1221 $enabled = ( $downsize[3] || 'full' === $size );
1222 $css_id = "image-size-{$size}-{$post->ID}";
1223
1224 // If this size is the default but that's not available, don't select it.
1225 if ( $size === $check ) {
1226 if ( $enabled ) {
1227 $checked = " checked='checked'";
1228 } else {
1229 $check = '';
1230 }
1231 } elseif ( ! $check && $enabled && 'thumbnail' !== $size ) {
1232 /*
1233 * If $check is not enabled, default to the first available size
1234 * that's bigger than a thumbnail.
1235 */
1236 $check = $size;
1237 $checked = " checked='checked'";
1238 }
1239
1240 $html = "<div class='image-size-item'><input type='radio' " . disabled( $enabled, false, false ) . "name='attachments[$post->ID][image-size]' id='{$css_id}' value='{$size}'$checked />";
1241
1242 $html .= "<label for='{$css_id}'>$label</label>";
1243
1244 // Only show the dimensions if that choice is available.
1245 if ( $enabled ) {
1246 $html .= " <label for='{$css_id}' class='help'>" . sprintf( '(%d&nbsp;&times;&nbsp;%d)', $downsize[1], $downsize[2] ) . '</label>';
1247 }
1248 $html .= '</div>';
1249
1250 $output[] = $html;
1251 }
1252
1253 return array(
1254 'label' => __( 'Size' ),
1255 'input' => 'html',
1256 'html' => implode( "\n", $output ),
1257 );
1258}
1259
1260/**
1261 * Retrieves HTML for the Link URL buttons with the default link type as specified.
1262 *
1263 * @since 2.7.0
1264 *
1265 * @param WP_Post $post
1266 * @param string $url_type
1267 * @return string
1268 */
1269function image_link_input_fields( $post, $url_type = '' ) {
1270
1271 $file = wp_get_attachment_url( $post->ID );
1272 $link = get_attachment_link( $post->ID );
1273
1274 if ( empty( $url_type ) ) {
1275 $url_type = get_user_setting( 'urlbutton', 'post' );
1276 }
1277
1278 $url = '';
1279
1280 if ( 'file' === $url_type ) {
1281 $url = $file;
1282 } elseif ( 'post' === $url_type ) {
1283 $url = $link;
1284 }
1285
1286 return "
1287 <input type='text' class='text urlfield' name='attachments[$post->ID][url]' value='" . esc_attr( $url ) . "' /><br />
1288 <button type='button' class='button urlnone' data-link-url=''>" . __( 'None' ) . "</button>
1289 <button type='button' class='button urlfile' data-link-url='" . esc_url( $file ) . "'>" . __( 'File URL' ) . "</button>
1290 <button type='button' class='button urlpost' data-link-url='" . esc_url( $link ) . "'>" . __( 'Attachment Post URL' ) . '</button>
1291';
1292}
1293
1294/**
1295 * Outputs a textarea element for inputting an attachment caption.
1296 *
1297 * @since 3.4.0
1298 *
1299 * @param WP_Post $edit_post Attachment WP_Post object.
1300 * @return string HTML markup for the textarea element.
1301 */
1302function wp_caption_input_textarea( $edit_post ) {
1303 // Post data is already escaped.
1304 $name = "attachments[{$edit_post->ID}][post_excerpt]";
1305
1306 return '<textarea name="' . $name . '" id="' . $name . '">' . $edit_post->post_excerpt . '</textarea>';
1307}
1308
1309/**
1310 * Retrieves the image attachment fields to edit form fields.
1311 *
1312 * @since 2.5.0
1313 *
1314 * @param array $form_fields
1315 * @param object $post
1316 * @return array
1317 */
1318function image_attachment_fields_to_edit( $form_fields, $post ) {
1319 return $form_fields;
1320}
1321
1322/**
1323 * Retrieves the single non-image attachment fields to edit form fields.
1324 *
1325 * @since 2.5.0
1326 *
1327 * @param array $form_fields An array of attachment form fields.
1328 * @param WP_Post $post The WP_Post attachment object.
1329 * @return array Filtered attachment form fields.
1330 */
1331function media_single_attachment_fields_to_edit( $form_fields, $post ) {
1332 unset( $form_fields['url'], $form_fields['align'], $form_fields['image-size'] );
1333 return $form_fields;
1334}
1335
1336/**
1337 * Retrieves the post non-image attachment fields to edit form fields.
1338 *
1339 * @since 2.8.0
1340 *
1341 * @param array $form_fields An array of attachment form fields.
1342 * @param WP_Post $post The WP_Post attachment object.
1343 * @return array Filtered attachment form fields.
1344 */
1345function media_post_single_attachment_fields_to_edit( $form_fields, $post ) {
1346 unset( $form_fields['image_url'] );
1347 return $form_fields;
1348}
1349
1350/**
1351 * Retrieves the media element HTML to send to the editor.
1352 *
1353 * @since 2.5.0
1354 *
1355 * @param string $html
1356 * @param int $attachment_id
1357 * @param array $attachment
1358 * @return string
1359 */
1360function image_media_send_to_editor( $html, $attachment_id, $attachment ) {
1361 $post = get_post( $attachment_id );
1362
1363 if ( str_starts_with( $post->post_mime_type, 'image' ) ) {
1364 $url = $attachment['url'];
1365 $align = ! empty( $attachment['align'] ) ? $attachment['align'] : 'none';
1366 $size = ! empty( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium';
1367 $alt = ! empty( $attachment['image_alt'] ) ? $attachment['image_alt'] : '';
1368 $rel = ( str_contains( $url, 'attachment_id' ) || get_attachment_link( $attachment_id ) === $url );
1369
1370 return get_image_send_to_editor( $attachment_id, $attachment['post_excerpt'], $attachment['post_title'], $align, $url, $rel, $size, $alt );
1371 }
1372
1373 return $html;
1374}
1375
1376/**
1377 * Retrieves the attachment fields to edit form fields.
1378 *
1379 * @since 2.5.0
1380 *
1381 * @param WP_Post $post
1382 * @param array $errors
1383 * @return array
1384 */
1385function get_attachment_fields_to_edit( $post, $errors = null ) {
1386 if ( is_int( $post ) ) {
1387 $post = get_post( $post );
1388 }
1389
1390 if ( is_array( $post ) ) {
1391 $post = new WP_Post( (object) $post );
1392 }
1393
1394 $image_url = wp_get_attachment_url( $post->ID );
1395
1396 $edit_post = sanitize_post( $post, 'edit' );
1397
1398 $form_fields = array(
1399 'post_title' => array(
1400 'label' => __( 'Title' ),
1401 'value' => $edit_post->post_title,
1402 ),
1403 'image_alt' => array(),
1404 'post_excerpt' => array(
1405 'label' => __( 'Caption' ),
1406 'input' => 'html',
1407 'html' => wp_caption_input_textarea( $edit_post ),
1408 ),
1409 'post_content' => array(
1410 'label' => __( 'Description' ),
1411 'value' => $edit_post->post_content,
1412 'input' => 'textarea',
1413 ),
1414 'url' => array(
1415 'label' => __( 'Link URL' ),
1416 'input' => 'html',
1417 'html' => image_link_input_fields( $post, get_option( 'image_default_link_type' ) ),
1418 'helps' => __( 'Enter a link URL or click above for presets.' ),
1419 ),
1420 'menu_order' => array(
1421 'label' => __( 'Order' ),
1422 'value' => $edit_post->menu_order,
1423 ),
1424 'image_url' => array(
1425 'label' => __( 'File URL' ),
1426 'input' => 'html',
1427 'html' => "<input type='text' class='text urlfield' readonly='readonly' name='attachments[$post->ID][url]' value='" . esc_attr( $image_url ) . "' /><br />",
1428 'value' => wp_get_attachment_url( $post->ID ),
1429 'helps' => __( 'Location of the uploaded file.' ),
1430 ),
1431 );
1432
1433 foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) {
1434 $t = (array) get_taxonomy( $taxonomy );
1435
1436 if ( ! $t['public'] || ! $t['show_ui'] ) {
1437 continue;
1438 }
1439
1440 if ( empty( $t['label'] ) ) {
1441 $t['label'] = $taxonomy;
1442 }
1443
1444 if ( empty( $t['args'] ) ) {
1445 $t['args'] = array();
1446 }
1447
1448 $terms = get_object_term_cache( $post->ID, $taxonomy );
1449
1450 if ( false === $terms ) {
1451 $terms = wp_get_object_terms( $post->ID, $taxonomy, $t['args'] );
1452 }
1453
1454 $values = array();
1455
1456 foreach ( $terms as $term ) {
1457 $values[] = $term->slug;
1458 }
1459
1460 $t['value'] = implode( ', ', $values );
1461
1462 $form_fields[ $taxonomy ] = $t;
1463 }
1464
1465 /*
1466 * Merge default fields with their errors, so any key passed with the error
1467 * (e.g. 'error', 'helps', 'value') will replace the default.
1468 * The recursive merge is easily traversed with array casting:
1469 * foreach ( (array) $things as $thing )
1470 */
1471 $form_fields = array_merge_recursive( $form_fields, (array) $errors );
1472
1473 // This was formerly in image_attachment_fields_to_edit().
1474 if ( str_starts_with( $post->post_mime_type, 'image' ) ) {
1475 $alt = get_post_meta( $post->ID, '_wp_attachment_image_alt', true );
1476
1477 if ( empty( $alt ) ) {
1478 $alt = '';
1479 }
1480
1481 $form_fields['post_title']['required'] = true;
1482
1483 $form_fields['image_alt'] = array(
1484 'value' => $alt,
1485 'label' => __( 'Alternative Text' ),
1486 'helps' => __( 'Alt text for the image, e.g. &#8220;The Mona Lisa&#8221;' ),
1487 );
1488
1489 $form_fields['align'] = array(
1490 'label' => __( 'Alignment' ),
1491 'input' => 'html',
1492 'html' => image_align_input_fields( $post, get_option( 'image_default_align' ) ),
1493 );
1494
1495 $form_fields['image-size'] = image_size_input_fields( $post, get_option( 'image_default_size', 'medium' ) );
1496
1497 } else {
1498 unset( $form_fields['image_alt'] );
1499 }
1500
1501 /**
1502 * Filters the attachment fields to edit.
1503 *
1504 * @since 2.5.0
1505 *
1506 * @param array $form_fields An array of attachment form fields.
1507 * @param WP_Post $post The WP_Post attachment object.
1508 */
1509 $form_fields = apply_filters( 'attachment_fields_to_edit', $form_fields, $post );
1510
1511 return $form_fields;
1512}
1513
1514/**
1515 * Retrieves HTML for media items of post gallery.
1516 *
1517 * The HTML markup retrieved will be created for the progress of SWF Upload
1518 * component. Will also create link for showing and hiding the form to modify
1519 * the image attachment.
1520 *
1521 * @since 2.5.0
1522 *
1523 * @global WP_Query $wp_the_query WordPress Query object.
1524 *
1525 * @param int $post_id Post ID.
1526 * @param array $errors Errors for attachment, if any.
1527 * @return string HTML content for media items of post gallery.
1528 */
1529function get_media_items( $post_id, $errors ) {
1530 $attachments = array();
1531
1532 if ( $post_id ) {
1533 $post = get_post( $post_id );
1534
1535 if ( $post && 'attachment' === $post->post_type ) {
1536 $attachments = array( $post->ID => $post );
1537 } else {
1538 $attachments = get_children(
1539 array(
1540 'post_parent' => $post_id,
1541 'post_type' => 'attachment',
1542 'orderby' => 'menu_order ASC, ID',
1543 'order' => 'DESC',
1544 )
1545 );
1546 }
1547 } else {
1548 if ( is_array( $GLOBALS['wp_the_query']->posts ) ) {
1549 foreach ( $GLOBALS['wp_the_query']->posts as $attachment ) {
1550 $attachments[ $attachment->ID ] = $attachment;
1551 }
1552 }
1553 }
1554
1555 $output = '';
1556 foreach ( (array) $attachments as $id => $attachment ) {
1557 if ( 'trash' === $attachment->post_status ) {
1558 continue;
1559 }
1560
1561 $item = get_media_item( $id, array( 'errors' => isset( $errors[ $id ] ) ? $errors[ $id ] : null ) );
1562
1563 if ( $item ) {
1564 $output .= "\n<div id='media-item-$id' class='media-item child-of-$attachment->post_parent preloaded'><div class='progress hidden'><div class='bar'></div></div><div id='media-upload-error-$id' class='hidden'></div><div class='filename hidden'></div>$item\n</div>";
1565 }
1566 }
1567
1568 return $output;
1569}
1570
1571/**
1572 * Retrieves HTML form for modifying the image attachment.
1573 *
1574 * @since 2.5.0
1575 *
1576 * @global string $redir_tab
1577 *
1578 * @param int $attachment_id Attachment ID for modification.
1579 * @param string|array $args Optional. Override defaults.
1580 * @return string HTML form for attachment.
1581 */
1582function get_media_item( $attachment_id, $args = null ) {
1583 global $redir_tab;
1584
1585 $thumb_url = false;
1586 $attachment_id = (int) $attachment_id;
1587
1588 if ( $attachment_id ) {
1589 $thumb_url = wp_get_attachment_image_src( $attachment_id, 'thumbnail', true );
1590
1591 if ( $thumb_url ) {
1592 $thumb_url = $thumb_url[0];
1593 }
1594 }
1595
1596 $post = get_post( $attachment_id );
1597 $current_post_id = ! empty( $_GET['post_id'] ) ? (int) $_GET['post_id'] : 0;
1598
1599 $default_args = array(
1600 'errors' => null,
1601 'send' => $current_post_id ? post_type_supports( get_post_type( $current_post_id ), 'editor' ) : true,
1602 'delete' => true,
1603 'toggle' => true,
1604 'show_title' => true,
1605 );
1606
1607 $parsed_args = wp_parse_args( $args, $default_args );
1608
1609 /**
1610 * Filters the arguments used to retrieve an image for the edit image form.
1611 *
1612 * @since 3.1.0
1613 *
1614 * @see get_media_item
1615 *
1616 * @param array $parsed_args An array of arguments.
1617 */
1618 $parsed_args = apply_filters( 'get_media_item_args', $parsed_args );
1619
1620 $toggle_on = __( 'Show' );
1621 $toggle_off = __( 'Hide' );
1622
1623 $file = get_attached_file( $post->ID );
1624 $filename = esc_html( wp_basename( $file ) );
1625 $title = esc_attr( $post->post_title );
1626
1627 $post_mime_types = get_post_mime_types();
1628 $keys = array_keys( wp_match_mime_types( array_keys( $post_mime_types ), $post->post_mime_type ) );
1629 $type = reset( $keys );
1630 $type_html = "<input type='hidden' id='type-of-$attachment_id' value='" . esc_attr( $type ) . "' />";
1631
1632 $form_fields = get_attachment_fields_to_edit( $post, $parsed_args['errors'] );
1633
1634 if ( $parsed_args['toggle'] ) {
1635 $class = empty( $parsed_args['errors'] ) ? 'startclosed' : 'startopen';
1636 $toggle_links = "
1637 <a class='toggle describe-toggle-on' href='#'>$toggle_on</a>
1638 <a class='toggle describe-toggle-off' href='#'>$toggle_off</a>";
1639 } else {
1640 $class = '';
1641 $toggle_links = '';
1642 }
1643
1644 $display_title = ( ! empty( $title ) ) ? $title : $filename; // $title shouldn't ever be empty, but just in case.
1645 $display_title = $parsed_args['show_title'] ? "<div class='filename new'><span class='title'>" . wp_html_excerpt( $display_title, 60, '&hellip;' ) . '</span></div>' : '';
1646
1647 $gallery = ( ( isset( $_REQUEST['tab'] ) && 'gallery' === $_REQUEST['tab'] ) || ( isset( $redir_tab ) && 'gallery' === $redir_tab ) );
1648 $order = '';
1649
1650 foreach ( $form_fields as $key => $val ) {
1651 if ( 'menu_order' === $key ) {
1652 if ( $gallery ) {
1653 $order = "<div class='menu_order'> <input class='menu_order_input' type='text' id='attachments[$attachment_id][menu_order]' name='attachments[$attachment_id][menu_order]' value='" . esc_attr( $val['value'] ) . "' /></div>";
1654 } else {
1655 $order = "<input type='hidden' name='attachments[$attachment_id][menu_order]' value='" . esc_attr( $val['value'] ) . "' />";
1656 }
1657
1658 unset( $form_fields['menu_order'] );
1659 break;
1660 }
1661 }
1662
1663 $media_dims = '';
1664 $meta = wp_get_attachment_metadata( $post->ID );
1665
1666 if ( isset( $meta['width'], $meta['height'] ) ) {
1667 /* translators: 1: A number of pixels wide, 2: A number of pixels tall. */
1668 $media_dims .= "<span id='media-dims-$post->ID'>" . sprintf( __( '%1$s by %2$s pixels' ), $meta['width'], $meta['height'] ) . '</span>';
1669 }
1670
1671 /**
1672 * Filters the media metadata.
1673 *
1674 * @since 2.5.0
1675 *
1676 * @param string $media_dims The HTML markup containing the media dimensions.
1677 * @param WP_Post $post The WP_Post attachment object.
1678 */
1679 $media_dims = apply_filters( 'media_meta', $media_dims, $post );
1680
1681 $image_edit_button = '';
1682
1683 if ( wp_attachment_is_image( $post->ID ) && wp_image_editor_supports( array( 'mime_type' => $post->post_mime_type ) ) ) {
1684 $nonce = wp_create_nonce( "image_editor-$post->ID" );
1685 $image_edit_button = "<input type='button' id='imgedit-open-btn-$post->ID' onclick='imageEdit.open( $post->ID, \"$nonce\" )' class='button' value='" . esc_attr__( 'Edit Image' ) . "' /> <span class='spinner'></span>";
1686 }
1687
1688 $attachment_url = get_permalink( $attachment_id );
1689
1690 $item = "
1691 $type_html
1692 $toggle_links
1693 $order
1694 $display_title
1695 <table class='slidetoggle describe $class'>
1696 <thead class='media-item-info' id='media-head-$post->ID'>
1697 <tr>
1698 <td class='A1B1' id='thumbnail-head-$post->ID'>
1699 <p><a href='$attachment_url' target='_blank'><img class='thumbnail' src='$thumb_url' alt='' /></a></p>
1700 <p>$image_edit_button</p>
1701 </td>
1702 <td>
1703 <p><strong>" . __( 'File name:' ) . "</strong> $filename</p>
1704 <p><strong>" . __( 'File type:' ) . "</strong> $post->post_mime_type</p>
1705 <p><strong>" . __( 'Upload date:' ) . '</strong> ' . mysql2date( __( 'F j, Y' ), $post->post_date ) . '</p>';
1706
1707 if ( ! empty( $media_dims ) ) {
1708 $item .= '<p><strong>' . __( 'Dimensions:' ) . "</strong> $media_dims</p>\n";
1709 }
1710
1711 $item .= "</td></tr>\n";
1712
1713 $item .= "
1714 </thead>
1715 <tbody>
1716 <tr><td colspan='2' class='imgedit-response' id='imgedit-response-$post->ID'></td></tr>\n
1717 <tr><td style='display:none' colspan='2' class='image-editor' id='image-editor-$post->ID'></td></tr>\n
1718 <tr><td colspan='2'><p class='media-types media-types-required-info'>" .
1719 wp_required_field_message() .
1720 "</p></td></tr>\n";
1721
1722 $defaults = array(
1723 'input' => 'text',
1724 'required' => false,
1725 'value' => '',
1726 'extra_rows' => array(),
1727 );
1728
1729 if ( $parsed_args['send'] ) {
1730 $parsed_args['send'] = get_submit_button( __( 'Insert into Post' ), '', "send[$attachment_id]", false );
1731 }
1732
1733 $delete = empty( $parsed_args['delete'] ) ? '' : $parsed_args['delete'];
1734 if ( $delete && current_user_can( 'delete_post', $attachment_id ) ) {
1735 if ( ! EMPTY_TRASH_DAYS ) {
1736 $delete = "<a href='" . wp_nonce_url( "post.php?action=delete&amp;post=$attachment_id", 'delete-post_' . $attachment_id ) . "' id='del[$attachment_id]' class='delete-permanently'>" . __( 'Delete Permanently' ) . '</a>';
1737 } elseif ( ! MEDIA_TRASH ) {
1738 $delete = "<a href='#' class='del-link' onclick=\"document.getElementById('del_attachment_$attachment_id').style.display='block';return false;\">" . __( 'Delete' ) . "</a>
1739 <div id='del_attachment_$attachment_id' class='del-attachment' style='display:none;'>" .
1740 /* translators: %s: File name. */
1741 '<p>' . sprintf( __( 'You are about to delete %s.' ), '<strong>' . $filename . '</strong>' ) . "</p>
1742 <a href='" . wp_nonce_url( "post.php?action=delete&amp;post=$attachment_id", 'delete-post_' . $attachment_id ) . "' id='del[$attachment_id]' class='button'>" . __( 'Continue' ) . "</a>
1743 <a href='#' class='button' onclick=\"this.parentNode.style.display='none';return false;\">" . __( 'Cancel' ) . '</a>
1744 </div>';
1745 } else {
1746 $delete = "<a href='" . wp_nonce_url( "post.php?action=trash&amp;post=$attachment_id", 'trash-post_' . $attachment_id ) . "' id='del[$attachment_id]' class='delete'>" . __( 'Move to Trash' ) . "</a>
1747 <a href='" . wp_nonce_url( "post.php?action=untrash&amp;post=$attachment_id", 'untrash-post_' . $attachment_id ) . "' id='undo[$attachment_id]' class='undo hidden'>" . __( 'Undo' ) . '</a>';
1748 }
1749 } else {
1750 $delete = '';
1751 }
1752
1753 $thumbnail = '';
1754 $calling_post_id = 0;
1755
1756 if ( isset( $_GET['post_id'] ) ) {
1757 $calling_post_id = absint( $_GET['post_id'] );
1758 } elseif ( isset( $_POST ) && count( $_POST ) ) {// Like for async-upload where $_GET['post_id'] isn't set.
1759 $calling_post_id = $post->post_parent;
1760 }
1761
1762 if ( 'image' === $type && $calling_post_id
1763 && current_theme_supports( 'post-thumbnails', get_post_type( $calling_post_id ) )
1764 && post_type_supports( get_post_type( $calling_post_id ), 'thumbnail' )
1765 && get_post_thumbnail_id( $calling_post_id ) !== $attachment_id
1766 ) {
1767
1768 $calling_post = get_post( $calling_post_id );
1769 $calling_post_type_object = get_post_type_object( $calling_post->post_type );
1770
1771 $ajax_nonce = wp_create_nonce( "set_post_thumbnail-$calling_post_id" );
1772 $thumbnail = "<a class='wp-post-thumbnail' id='wp-post-thumbnail-" . $attachment_id . "' href='#' onclick='WPSetAsThumbnail(\"$attachment_id\", \"$ajax_nonce\");return false;'>" . esc_html( $calling_post_type_object->labels->use_featured_image ) . '</a>';
1773 }
1774
1775 if ( ( $parsed_args['send'] || $thumbnail || $delete ) && ! isset( $form_fields['buttons'] ) ) {
1776 $form_fields['buttons'] = array( 'tr' => "\t\t<tr class='submit'><td></td><td class='savesend'>" . $parsed_args['send'] . " $thumbnail $delete</td></tr>\n" );
1777 }
1778
1779 $hidden_fields = array();
1780
1781 foreach ( $form_fields as $id => $field ) {
1782 if ( '_' === $id[0] ) {
1783 continue;
1784 }
1785
1786 if ( ! empty( $field['tr'] ) ) {
1787 $item .= $field['tr'];
1788 continue;
1789 }
1790
1791 $field = array_merge( $defaults, $field );
1792 $name = "attachments[$attachment_id][$id]";
1793
1794 if ( 'hidden' === $field['input'] ) {
1795 $hidden_fields[ $name ] = $field['value'];
1796 continue;
1797 }
1798
1799 $required = $field['required'] ? ' ' . wp_required_field_indicator() : '';
1800 $required_attr = $field['required'] ? ' required' : '';
1801 $class = $id;
1802 $class .= $field['required'] ? ' form-required' : '';
1803
1804 $item .= "\t\t<tr class='$class'>\n\t\t\t<th scope='row' class='label'><label for='$name'><span class='alignleft'>{$field['label']}{$required}</span><br class='clear' /></label></th>\n\t\t\t<td class='field'>";
1805
1806 if ( ! empty( $field[ $field['input'] ] ) ) {
1807 $item .= $field[ $field['input'] ];
1808 } elseif ( 'textarea' === $field['input'] ) {
1809 if ( 'post_content' === $id && user_can_richedit() ) {
1810 // Sanitize_post() skips the post_content when user_can_richedit.
1811 $field['value'] = htmlspecialchars( $field['value'], ENT_QUOTES );
1812 }
1813 // Post_excerpt is already escaped by sanitize_post() in get_attachment_fields_to_edit().
1814 $item .= "<textarea id='$name' name='$name'{$required_attr}>" . $field['value'] . '</textarea>';
1815 } else {
1816 $item .= "<input type='text' class='text' id='$name' name='$name' value='" . esc_attr( $field['value'] ) . "'{$required_attr} />";
1817 }
1818
1819 if ( ! empty( $field['helps'] ) ) {
1820 $item .= "<p class='help'>" . implode( "</p>\n<p class='help'>", array_unique( (array) $field['helps'] ) ) . '</p>';
1821 }
1822 $item .= "</td>\n\t\t</tr>\n";
1823
1824 $extra_rows = array();
1825
1826 if ( ! empty( $field['errors'] ) ) {
1827 foreach ( array_unique( (array) $field['errors'] ) as $error ) {
1828 $extra_rows['error'][] = $error;
1829 }
1830 }
1831
1832 if ( ! empty( $field['extra_rows'] ) ) {
1833 foreach ( $field['extra_rows'] as $class => $rows ) {
1834 foreach ( (array) $rows as $html ) {
1835 $extra_rows[ $class ][] = $html;
1836 }
1837 }
1838 }
1839
1840 foreach ( $extra_rows as $class => $rows ) {
1841 foreach ( $rows as $html ) {
1842 $item .= "\t\t<tr><td></td><td class='$class'>$html</td></tr>\n";
1843 }
1844 }
1845 }
1846
1847 if ( ! empty( $form_fields['_final'] ) ) {
1848 $item .= "\t\t<tr class='final'><td colspan='2'>{$form_fields['_final']}</td></tr>\n";
1849 }
1850
1851 $item .= "\t</tbody>\n";
1852 $item .= "\t</table>\n";
1853
1854 foreach ( $hidden_fields as $name => $value ) {
1855 $item .= "\t<input type='hidden' name='$name' id='$name' value='" . esc_attr( $value ) . "' />\n";
1856 }
1857
1858 if ( $post->post_parent < 1 && isset( $_REQUEST['post_id'] ) ) {
1859 $parent = (int) $_REQUEST['post_id'];
1860 $parent_name = "attachments[$attachment_id][post_parent]";
1861 $item .= "\t<input type='hidden' name='$parent_name' id='$parent_name' value='$parent' />\n";
1862 }
1863
1864 return $item;
1865}
1866
1867/**
1868 * @since 3.5.0
1869 *
1870 * @param int $attachment_id
1871 * @param array $args
1872 * @return array
1873 */
1874function get_compat_media_markup( $attachment_id, $args = null ) {
1875 $post = get_post( $attachment_id );
1876
1877 $default_args = array(
1878 'errors' => null,
1879 'in_modal' => false,
1880 );
1881
1882 $user_can_edit = current_user_can( 'edit_post', $attachment_id );
1883
1884 $args = wp_parse_args( $args, $default_args );
1885
1886 /** This filter is documented in wp-admin/includes/media.php */
1887 $args = apply_filters( 'get_media_item_args', $args );
1888
1889 $form_fields = array();
1890
1891 if ( $args['in_modal'] ) {
1892 foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) {
1893 $t = (array) get_taxonomy( $taxonomy );
1894
1895 if ( ! $t['public'] || ! $t['show_ui'] ) {
1896 continue;
1897 }
1898
1899 if ( empty( $t['label'] ) ) {
1900 $t['label'] = $taxonomy;
1901 }
1902
1903 if ( empty( $t['args'] ) ) {
1904 $t['args'] = array();
1905 }
1906
1907 $terms = get_object_term_cache( $post->ID, $taxonomy );
1908
1909 if ( false === $terms ) {
1910 $terms = wp_get_object_terms( $post->ID, $taxonomy, $t['args'] );
1911 }
1912
1913 $values = array();
1914
1915 foreach ( $terms as $term ) {
1916 $values[] = $term->slug;
1917 }
1918
1919 $t['value'] = implode( ', ', $values );
1920 $t['taxonomy'] = true;
1921
1922 $form_fields[ $taxonomy ] = $t;
1923 }
1924 }
1925
1926 /*
1927 * Merge default fields with their errors, so any key passed with the error
1928 * (e.g. 'error', 'helps', 'value') will replace the default.
1929 * The recursive merge is easily traversed with array casting:
1930 * foreach ( (array) $things as $thing )
1931 */
1932 $form_fields = array_merge_recursive( $form_fields, (array) $args['errors'] );
1933
1934 /** This filter is documented in wp-admin/includes/media.php */
1935 $form_fields = apply_filters( 'attachment_fields_to_edit', $form_fields, $post );
1936
1937 unset(
1938 $form_fields['image-size'],
1939 $form_fields['align'],
1940 $form_fields['image_alt'],
1941 $form_fields['post_title'],
1942 $form_fields['post_excerpt'],
1943 $form_fields['post_content'],
1944 $form_fields['url'],
1945 $form_fields['menu_order'],
1946 $form_fields['image_url']
1947 );
1948
1949 /** This filter is documented in wp-admin/includes/media.php */
1950 $media_meta = apply_filters( 'media_meta', '', $post );
1951
1952 $defaults = array(
1953 'input' => 'text',
1954 'required' => false,
1955 'value' => '',
1956 'extra_rows' => array(),
1957 'show_in_edit' => true,
1958 'show_in_modal' => true,
1959 );
1960
1961 $hidden_fields = array();
1962
1963 $item = '';
1964
1965 foreach ( $form_fields as $id => $field ) {
1966 if ( '_' === $id[0] ) {
1967 continue;
1968 }
1969
1970 $name = "attachments[$attachment_id][$id]";
1971 $id_attr = "attachments-$attachment_id-$id";
1972
1973 if ( ! empty( $field['tr'] ) ) {
1974 $item .= $field['tr'];
1975 continue;
1976 }
1977
1978 $field = array_merge( $defaults, $field );
1979
1980 if ( ( ! $field['show_in_edit'] && ! $args['in_modal'] ) || ( ! $field['show_in_modal'] && $args['in_modal'] ) ) {
1981 continue;
1982 }
1983
1984 if ( 'hidden' === $field['input'] ) {
1985 $hidden_fields[ $name ] = $field['value'];
1986 continue;
1987 }
1988
1989 $readonly = ! $user_can_edit && ! empty( $field['taxonomy'] ) ? " readonly='readonly' " : '';
1990 $required = $field['required'] ? ' ' . wp_required_field_indicator() : '';
1991 $required_attr = $field['required'] ? ' required' : '';
1992 $class = 'compat-field-' . $id;
1993 $class .= $field['required'] ? ' form-required' : '';
1994
1995 $item .= "\t\t<tr class='$class'>";
1996 $item .= "\t\t\t<th scope='row' class='label'><label for='$id_attr'><span class='alignleft'>{$field['label']}</span>$required<br class='clear' /></label>";
1997 $item .= "</th>\n\t\t\t<td class='field'>";
1998
1999 if ( ! empty( $field[ $field['input'] ] ) ) {
2000 $item .= $field[ $field['input'] ];
2001 } elseif ( 'textarea' === $field['input'] ) {
2002 if ( 'post_content' === $id && user_can_richedit() ) {
2003 // sanitize_post() skips the post_content when user_can_richedit.
2004 $field['value'] = htmlspecialchars( $field['value'], ENT_QUOTES );
2005 }
2006 $item .= "<textarea id='$id_attr' name='$name'{$required_attr}>" . $field['value'] . '</textarea>';
2007 } else {
2008 $item .= "<input type='text' class='text' id='$id_attr' name='$name' value='" . esc_attr( $field['value'] ) . "' $readonly{$required_attr} />";
2009 }
2010
2011 if ( ! empty( $field['helps'] ) ) {
2012 $item .= "<p class='help'>" . implode( "</p>\n<p class='help'>", array_unique( (array) $field['helps'] ) ) . '</p>';
2013 }
2014
2015 $item .= "</td>\n\t\t</tr>\n";
2016
2017 $extra_rows = array();
2018
2019 if ( ! empty( $field['errors'] ) ) {
2020 foreach ( array_unique( (array) $field['errors'] ) as $error ) {
2021 $extra_rows['error'][] = $error;
2022 }
2023 }
2024
2025 if ( ! empty( $field['extra_rows'] ) ) {
2026 foreach ( $field['extra_rows'] as $class => $rows ) {
2027 foreach ( (array) $rows as $html ) {
2028 $extra_rows[ $class ][] = $html;
2029 }
2030 }
2031 }
2032
2033 foreach ( $extra_rows as $class => $rows ) {
2034 foreach ( $rows as $html ) {
2035 $item .= "\t\t<tr><td></td><td class='$class'>$html</td></tr>\n";
2036 }
2037 }
2038 }
2039
2040 if ( ! empty( $form_fields['_final'] ) ) {
2041 $item .= "\t\t<tr class='final'><td colspan='2'>{$form_fields['_final']}</td></tr>\n";
2042 }
2043
2044 if ( $item ) {
2045 $item = '<p class="media-types media-types-required-info">' .
2046 wp_required_field_message() .
2047 '</p>' .
2048 '<table class="compat-attachment-fields">' . $item . '</table>';
2049 }
2050
2051 foreach ( $hidden_fields as $hidden_field => $value ) {
2052 $item .= '<input type="hidden" name="' . esc_attr( $hidden_field ) . '" value="' . esc_attr( $value ) . '" />' . "\n";
2053 }
2054
2055 if ( $item ) {
2056 $item = '<input type="hidden" name="attachments[' . $attachment_id . '][menu_order]" value="' . esc_attr( $post->menu_order ) . '" />' . $item;
2057 }
2058
2059 return array(
2060 'item' => $item,
2061 'meta' => $media_meta,
2062 );
2063}
2064
2065/**
2066 * Outputs the legacy media upload header.
2067 *
2068 * @since 2.5.0
2069 */
2070function media_upload_header() {
2071 $post_id = isset( $_REQUEST['post_id'] ) ? (int) $_REQUEST['post_id'] : 0;
2072
2073 echo '<script type="text/javascript">post_id = ' . $post_id . ';</script>';
2074
2075 if ( empty( $_GET['chromeless'] ) ) {
2076 echo '<div id="media-upload-header">';
2077 the_media_upload_tabs();
2078 echo '</div>';
2079 }
2080}
2081
2082/**
2083 * Outputs the legacy media upload form.
2084 *
2085 * @since 2.5.0
2086 *
2087 * @global string $type
2088 * @global string $tab
2089 *
2090 * @param array $errors
2091 */
2092function media_upload_form( $errors = null ) {
2093 global $type, $tab;
2094
2095 if ( ! _device_can_upload() ) {
2096 echo '<p>' . sprintf(
2097 /* translators: %s: https://apps.wordpress.org/ */
2098 __( 'The web browser on your device cannot be used to upload files. You may be able to use the <a href="%s">native app for your device</a> instead.' ),
2099 'https://apps.wordpress.org/'
2100 ) . '</p>';
2101 return;
2102 }
2103
2104 $upload_action_url = admin_url( 'async-upload.php' );
2105 $post_id = isset( $_REQUEST['post_id'] ) ? (int) $_REQUEST['post_id'] : 0;
2106 $_type = isset( $type ) ? $type : '';
2107 $_tab = isset( $tab ) ? $tab : '';
2108
2109 $max_upload_size = wp_max_upload_size();
2110 if ( ! $max_upload_size ) {
2111 $max_upload_size = 0;
2112 }
2113
2114 ?>
2115 <div id="media-upload-notice">
2116 <?php
2117
2118 if ( isset( $errors['upload_notice'] ) ) {
2119 echo $errors['upload_notice'];
2120 }
2121
2122 ?>
2123 </div>
2124 <div id="media-upload-error">
2125 <?php
2126
2127 if ( isset( $errors['upload_error'] ) && is_wp_error( $errors['upload_error'] ) ) {
2128 echo $errors['upload_error']->get_error_message();
2129 }
2130
2131 ?>
2132 </div>
2133 <?php
2134
2135 if ( is_multisite() && ! is_upload_space_available() ) {
2136 /**
2137 * Fires when an upload will exceed the defined upload space quota for a network site.
2138 *
2139 * @since 3.5.0
2140 */
2141 do_action( 'upload_ui_over_quota' );
2142 return;
2143 }
2144
2145 /**
2146 * Fires just before the legacy (pre-3.5.0) upload interface is loaded.
2147 *
2148 * @since 2.6.0
2149 */
2150 do_action( 'pre-upload-ui' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2151
2152 $post_params = array(
2153 'post_id' => $post_id,
2154 '_wpnonce' => wp_create_nonce( 'media-form' ),
2155 'type' => $_type,
2156 'tab' => $_tab,
2157 'short' => '1',
2158 );
2159
2160 /**
2161 * Filters the media upload post parameters.
2162 *
2163 * @since 3.1.0 As 'swfupload_post_params'
2164 * @since 3.3.0
2165 *
2166 * @param array $post_params An array of media upload parameters used by Plupload.
2167 */
2168 $post_params = apply_filters( 'upload_post_params', $post_params );
2169
2170 /*
2171 * Since 4.9 the `runtimes` setting is hardcoded in our version of Plupload to `html5,html4`,
2172 * and the `flash_swf_url` and `silverlight_xap_url` are not used.
2173 */
2174 $plupload_init = array(
2175 'browse_button' => 'plupload-browse-button',
2176 'container' => 'plupload-upload-ui',
2177 'drop_element' => 'drag-drop-area',
2178 'file_data_name' => 'async-upload',
2179 'url' => $upload_action_url,
2180 'filters' => array( 'max_file_size' => $max_upload_size . 'b' ),
2181 'multipart_params' => $post_params,
2182 );
2183
2184 /*
2185 * Currently only iOS Safari supports multiple files uploading,
2186 * but iOS 7.x has a bug that prevents uploading of videos when enabled.
2187 * See #29602.
2188 */
2189 if (
2190 wp_is_mobile() &&
2191 str_contains( $_SERVER['HTTP_USER_AGENT'], 'OS 7_' ) &&
2192 str_contains( $_SERVER['HTTP_USER_AGENT'], 'like Mac OS X' )
2193 ) {
2194 $plupload_init['multi_selection'] = false;
2195 }
2196
2197 /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */
2198 $prevent_unsupported_uploads = apply_filters( 'wp_prevent_unsupported_mime_type_uploads', true, null );
2199
2200 if ( $prevent_unsupported_uploads ) {
2201 // Check if WebP images can be edited.
2202 if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) {
2203 $plupload_init['webp_upload_error'] = true;
2204 }
2205
2206 // Check if AVIF images can be edited.
2207 if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) {
2208 $plupload_init['avif_upload_error'] = true;
2209 }
2210 }
2211
2212 /**
2213 * Filters the default Plupload settings.
2214 *
2215 * @since 3.3.0
2216 *
2217 * @param array $plupload_init An array of default settings used by Plupload.
2218 */
2219 $plupload_init = apply_filters( 'plupload_init', $plupload_init );
2220
2221 ?>
2222 <script type="text/javascript">
2223 <?php
2224 // Verify size is an int. If not return default value.
2225 $large_size_h = absint( get_option( 'large_size_h' ) );
2226
2227 if ( ! $large_size_h ) {
2228 $large_size_h = 1024;
2229 }
2230
2231 $large_size_w = absint( get_option( 'large_size_w' ) );
2232
2233 if ( ! $large_size_w ) {
2234 $large_size_w = 1024;
2235 }
2236
2237 ?>
2238 var resize_height = <?php echo $large_size_h; ?>, resize_width = <?php echo $large_size_w; ?>,
2239 wpUploaderInit = <?php echo wp_json_encode( $plupload_init, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); ?>;
2240 </script>
2241
2242 <div id="plupload-upload-ui" class="hide-if-no-js">
2243 <?php
2244 /**
2245 * Fires before the upload interface loads.
2246 *
2247 * @since 2.6.0 As 'pre-flash-upload-ui'
2248 * @since 3.3.0
2249 */
2250 do_action( 'pre-plupload-upload-ui' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2251
2252 ?>
2253 <div id="drag-drop-area">
2254 <div class="drag-drop-inside">
2255 <p class="drag-drop-info"><?php _e( 'Drop files to upload' ); ?></p>
2256 <p><?php _ex( 'or', 'Uploader: Drop files here - or - Select Files' ); ?></p>
2257 <p class="drag-drop-buttons"><input id="plupload-browse-button" type="button" value="<?php esc_attr_e( 'Select Files' ); ?>" class="button" /></p>
2258 </div>
2259 </div>
2260 <?php
2261 /**
2262 * Fires after the upload interface loads.
2263 *
2264 * @since 2.6.0 As 'post-flash-upload-ui'
2265 * @since 3.3.0
2266 */
2267 do_action( 'post-plupload-upload-ui' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2268 ?>
2269 </div>
2270
2271 <div id="html-upload-ui" class="hide-if-js">
2272 <?php
2273 /**
2274 * Fires before the upload button in the media upload interface.
2275 *
2276 * @since 2.6.0
2277 */
2278 do_action( 'pre-html-upload-ui' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2279
2280 ?>
2281 <p id="async-upload-wrap">
2282 <label class="screen-reader-text" for="async-upload">
2283 <?php
2284 /* translators: Hidden accessibility text. */
2285 _ex( 'Upload', 'verb' );
2286 ?>
2287 </label>
2288 <input type="file" name="async-upload" id="async-upload" />
2289 <?php submit_button( _x( 'Upload', 'verb' ), 'primary', 'html-upload', false ); ?>
2290 <a href="#" onclick="try{top.tb_remove();}catch(e){}; return false;"><?php _e( 'Cancel' ); ?></a>
2291 </p>
2292 <div class="clear"></div>
2293 <?php
2294 /**
2295 * Fires after the upload button in the media upload interface.
2296 *
2297 * @since 2.6.0
2298 */
2299 do_action( 'post-html-upload-ui' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2300
2301 ?>
2302 </div>
2303
2304<p class="max-upload-size">
2305 <?php
2306 /* translators: %s: Maximum allowed file size. */
2307 printf( __( 'Maximum upload file size: %s.' ), esc_html( size_format( $max_upload_size ) ) );
2308 ?>
2309</p>
2310 <?php
2311
2312 /**
2313 * Fires on the post upload UI screen.
2314 *
2315 * Legacy (pre-3.5.0) media workflow hook.
2316 *
2317 * @since 2.6.0
2318 */
2319 do_action( 'post-upload-ui' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2320}
2321
2322/**
2323 * Outputs the legacy media upload form for a given media type.
2324 *
2325 * @since 2.5.0
2326 *
2327 * @param string $type
2328 * @param array $errors
2329 * @param int|WP_Error $id
2330 */
2331function media_upload_type_form( $type = 'file', $errors = null, $id = null ) {
2332
2333 media_upload_header();
2334
2335 $post_id = isset( $_REQUEST['post_id'] ) ? (int) $_REQUEST['post_id'] : 0;
2336
2337 $form_action_url = admin_url( "media-upload.php?type=$type&tab=type&post_id=$post_id" );
2338
2339 /**
2340 * Filters the media upload form action URL.
2341 *
2342 * @since 2.6.0
2343 *
2344 * @param string $form_action_url The media upload form action URL.
2345 * @param string $type The type of media. Default 'file'.
2346 */
2347 $form_action_url = apply_filters( 'media_upload_form_url', $form_action_url, $type );
2348 $form_class = 'media-upload-form type-form validate';
2349
2350 if ( get_user_setting( 'uploader' ) ) {
2351 $form_class .= ' html-uploader';
2352 }
2353
2354 ?>
2355 <form enctype="multipart/form-data" method="post" action="<?php echo esc_url( $form_action_url ); ?>" class="<?php echo $form_class; ?>" id="<?php echo $type; ?>-form">
2356 <?php submit_button( '', 'hidden', 'save', false ); ?>
2357 <input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
2358 <?php wp_nonce_field( 'media-form' ); ?>
2359
2360 <h3 class="media-title"><?php _e( 'Add media files from your computer' ); ?></h3>
2361
2362 <?php media_upload_form( $errors ); ?>
2363
2364 <script type="text/javascript">
2365 jQuery(function($){
2366 var preloaded = $(".media-item.preloaded");
2367 if ( preloaded.length > 0 ) {
2368 preloaded.each(function(){prepareMediaItem({id:this.id.replace(/[^0-9]/g, '')},'');});
2369 }
2370 updateMediaForm();
2371 });
2372 </script>
2373 <div id="media-items">
2374 <?php
2375
2376 if ( $id ) {
2377 if ( ! is_wp_error( $id ) ) {
2378 add_filter( 'attachment_fields_to_edit', 'media_post_single_attachment_fields_to_edit', 10, 2 );
2379 echo get_media_items( $id, $errors );
2380 } else {
2381 echo '<div id="media-upload-error">' . esc_html( $id->get_error_message() ) . '</div></div>';
2382 exit;
2383 }
2384 }
2385
2386 ?>
2387 </div>
2388
2389 <p class="savebutton ml-submit">
2390 <?php submit_button( __( 'Save all changes' ), '', 'save', false ); ?>
2391 </p>
2392 </form>
2393 <?php
2394}
2395
2396/**
2397 * Outputs the legacy media upload form for external media.
2398 *
2399 * @since 2.7.0
2400 *
2401 * @param string $type
2402 * @param object $errors
2403 * @param int $id
2404 */
2405function media_upload_type_url_form( $type = null, $errors = null, $id = null ) {
2406 if ( null === $type ) {
2407 $type = 'image';
2408 }
2409
2410 media_upload_header();
2411
2412 $post_id = isset( $_REQUEST['post_id'] ) ? (int) $_REQUEST['post_id'] : 0;
2413
2414 $form_action_url = admin_url( "media-upload.php?type=$type&tab=type&post_id=$post_id" );
2415 /** This filter is documented in wp-admin/includes/media.php */
2416 $form_action_url = apply_filters( 'media_upload_form_url', $form_action_url, $type );
2417 $form_class = 'media-upload-form type-form validate';
2418
2419 if ( get_user_setting( 'uploader' ) ) {
2420 $form_class .= ' html-uploader';
2421 }
2422
2423 ?>
2424 <form enctype="multipart/form-data" method="post" action="<?php echo esc_url( $form_action_url ); ?>" class="<?php echo $form_class; ?>" id="<?php echo $type; ?>-form">
2425 <input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
2426 <?php wp_nonce_field( 'media-form' ); ?>
2427
2428 <h3 class="media-title"><?php _e( 'Insert media from another website' ); ?></h3>
2429
2430 <script type="text/javascript">
2431 var addExtImage = {
2432
2433 width : '',
2434 height : '',
2435 align : 'alignnone',
2436
2437 insert : function() {
2438 var t = this, html, f = document.forms[0], cls, title = '', alt = '', caption = '';
2439
2440 if ( '' === f.src.value || '' === t.width )
2441 return false;
2442
2443 if ( f.alt.value )
2444 alt = f.alt.value.replace(/'/g, '&#039;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
2445
2446 <?php
2447 /** This filter is documented in wp-admin/includes/media.php */
2448 if ( ! apply_filters( 'disable_captions', '' ) ) {
2449 ?>
2450 if ( f.caption.value ) {
2451 caption = f.caption.value.replace(/\r\n|\r/g, '\n');
2452 caption = caption.replace(/<[a-zA-Z0-9]+( [^<>]+)?>/g, function(a){
2453 return a.replace(/[\r\n\t]+/, ' ');
2454 });
2455
2456 caption = caption.replace(/\s*\n\s*/g, '<br />');
2457 }
2458 <?php
2459 }
2460
2461 ?>
2462 cls = caption ? '' : ' class="'+t.align+'"';
2463
2464 html = '<img alt="'+alt+'" src="'+f.src.value+'"'+cls+' width="'+t.width+'" height="'+t.height+'" />';
2465
2466 if ( f.url.value ) {
2467 url = f.url.value.replace(/'/g, '&#039;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
2468 html = '<a href="'+url+'">'+html+'</a>';
2469 }
2470
2471 if ( caption )
2472 html = '[caption id="" align="'+t.align+'" width="'+t.width+'"]'+html+caption+'[/caption]';
2473
2474 var win = window.dialogArguments || opener || parent || top;
2475 win.send_to_editor(html);
2476 return false;
2477 },
2478
2479 resetImageData : function() {
2480 var t = addExtImage;
2481
2482 t.width = t.height = '';
2483 document.getElementById('go_button').style.color = '#bbb';
2484 if ( ! document.forms[0].src.value )
2485 document.getElementById('status_img').innerHTML = '';
2486 else document.getElementById('status_img').innerHTML = '<img src="<?php echo esc_url( admin_url( 'images/no.png' ) ); ?>" alt="" />';
2487 },
2488
2489 updateImageData : function() {
2490 var t = addExtImage;
2491
2492 t.width = t.preloadImg.width;
2493 t.height = t.preloadImg.height;
2494 document.getElementById('go_button').style.color = '#333';
2495 document.getElementById('status_img').innerHTML = '<img src="<?php echo esc_url( admin_url( 'images/yes.png' ) ); ?>" alt="" />';
2496 },
2497
2498 getImageData : function() {
2499 if ( jQuery('table.describe').hasClass('not-image') )
2500 return;
2501
2502 var t = addExtImage, src = document.forms[0].src.value;
2503
2504 if ( ! src ) {
2505 t.resetImageData();
2506 return false;
2507 }
2508
2509 document.getElementById('status_img').innerHTML = '<img src="<?php echo esc_url( admin_url( 'images/spinner-2x.gif' ) ); ?>" alt="" width="16" height="16" />';
2510 t.preloadImg = new Image();
2511 t.preloadImg.onload = t.updateImageData;
2512 t.preloadImg.onerror = t.resetImageData;
2513 t.preloadImg.src = src;
2514 }
2515 };
2516
2517 jQuery( function($) {
2518 $('.media-types input').click( function() {
2519 $('table.describe').toggleClass('not-image', $('#not-image').prop('checked') );
2520 });
2521 } );
2522 </script>
2523
2524 <div id="media-items">
2525 <div class="media-item media-blank">
2526 <?php
2527 /**
2528 * Filters the insert media from URL form HTML.
2529 *
2530 * @since 3.3.0
2531 *
2532 * @param string $form_html The insert from URL form HTML.
2533 */
2534 echo apply_filters( 'type_url_form_media', wp_media_insert_url_form( $type ) );
2535
2536 ?>
2537 </div>
2538 </div>
2539 </form>
2540 <?php
2541}
2542
2543/**
2544 * Adds gallery form to upload iframe.
2545 *
2546 * @since 2.5.0
2547 *
2548 * @global string $redir_tab
2549 * @global string $type
2550 * @global string $tab
2551 *
2552 * @param array $errors
2553 */
2554function media_upload_gallery_form( $errors ) {
2555 global $redir_tab, $type;
2556
2557 $redir_tab = 'gallery';
2558 media_upload_header();
2559
2560 $post_id = (int) $_REQUEST['post_id'];
2561 $form_action_url = admin_url( "media-upload.php?type=$type&tab=gallery&post_id=$post_id" );
2562 /** This filter is documented in wp-admin/includes/media.php */
2563 $form_action_url = apply_filters( 'media_upload_form_url', $form_action_url, $type );
2564 $form_class = 'media-upload-form validate';
2565
2566 if ( get_user_setting( 'uploader' ) ) {
2567 $form_class .= ' html-uploader';
2568 }
2569
2570 ?>
2571 <script type="text/javascript">
2572 jQuery(function($){
2573 var preloaded = $(".media-item.preloaded");
2574 if ( preloaded.length > 0 ) {
2575 preloaded.each(function(){prepareMediaItem({id:this.id.replace(/[^0-9]/g, '')},'');});
2576 updateMediaForm();
2577 }
2578 });
2579 </script>
2580 <div id="sort-buttons" class="hide-if-no-js">
2581 <span>
2582 <?php _e( 'All Tabs:' ); ?>
2583 <a href="#" id="showall"><?php _e( 'Show' ); ?></a>
2584 <a href="#" id="hideall" style="display:none;"><?php _e( 'Hide' ); ?></a>
2585 </span>
2586 <?php _e( 'Sort Order:' ); ?>
2587 <a href="#" id="asc"><?php _e( 'Ascending' ); ?></a> |
2588 <a href="#" id="desc"><?php _e( 'Descending' ); ?></a> |
2589 <a href="#" id="clear"><?php _ex( 'Clear', 'verb' ); ?></a>
2590 </div>
2591 <form enctype="multipart/form-data" method="post" action="<?php echo esc_url( $form_action_url ); ?>" class="<?php echo $form_class; ?>" id="gallery-form">
2592 <?php wp_nonce_field( 'media-form' ); ?>
2593 <table class="widefat">
2594 <thead><tr>
2595 <th><?php _e( 'Media' ); ?></th>
2596 <th class="order-head"><?php _e( 'Order' ); ?></th>
2597 <th class="actions-head"><?php _e( 'Actions' ); ?></th>
2598 </tr></thead>
2599 </table>
2600 <div id="media-items">
2601 <?php add_filter( 'attachment_fields_to_edit', 'media_post_single_attachment_fields_to_edit', 10, 2 ); ?>
2602 <?php echo get_media_items( $post_id, $errors ); ?>
2603 </div>
2604
2605 <p class="ml-submit">
2606 <?php
2607 submit_button(
2608 __( 'Save all changes' ),
2609 'savebutton',
2610 'save',
2611 false,
2612 array(
2613 'id' => 'save-all',
2614 'style' => 'display: none;',
2615 )
2616 );
2617 ?>
2618 <input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
2619 <input type="hidden" name="type" value="<?php echo esc_attr( $GLOBALS['type'] ); ?>" />
2620 <input type="hidden" name="tab" value="<?php echo esc_attr( $GLOBALS['tab'] ); ?>" />
2621 </p>
2622
2623 <div id="gallery-settings" style="display:none;">
2624 <div class="title"><?php _e( 'Gallery Settings' ); ?></div>
2625 <table id="basic" class="describe"><tbody>
2626 <tr>
2627 <th scope="row" class="label">
2628 <label>
2629 <span class="alignleft"><?php _e( 'Link thumbnails to:' ); ?></span>
2630 </label>
2631 </th>
2632 <td class="field">
2633 <input type="radio" name="linkto" id="linkto-file" value="file" />
2634 <label for="linkto-file" class="radio"><?php _e( 'Image File' ); ?></label>
2635
2636 <input type="radio" checked="checked" name="linkto" id="linkto-post" value="post" />
2637 <label for="linkto-post" class="radio"><?php _e( 'Attachment Page' ); ?></label>
2638 </td>
2639 </tr>
2640
2641 <tr>
2642 <th scope="row" class="label">
2643 <label>
2644 <span class="alignleft"><?php _e( 'Order images by:' ); ?></span>
2645 </label>
2646 </th>
2647 <td class="field">
2648 <select id="orderby" name="orderby">
2649 <option value="menu_order" selected="selected"><?php _e( 'Menu order' ); ?></option>
2650 <option value="title"><?php _e( 'Title' ); ?></option>
2651 <option value="post_date"><?php _e( 'Date/Time' ); ?></option>
2652 <option value="rand"><?php _e( 'Random' ); ?></option>
2653 </select>
2654 </td>
2655 </tr>
2656
2657 <tr>
2658 <th scope="row" class="label">
2659 <label>
2660 <span class="alignleft"><?php _e( 'Order:' ); ?></span>
2661 </label>
2662 </th>
2663 <td class="field">
2664 <input type="radio" checked="checked" name="order" id="order-asc" value="asc" />
2665 <label for="order-asc" class="radio"><?php _e( 'Ascending' ); ?></label>
2666
2667 <input type="radio" name="order" id="order-desc" value="desc" />
2668 <label for="order-desc" class="radio"><?php _e( 'Descending' ); ?></label>
2669 </td>
2670 </tr>
2671
2672 <tr>
2673 <th scope="row" class="label">
2674 <label>
2675 <span class="alignleft"><?php _e( 'Gallery columns:' ); ?></span>
2676 </label>
2677 </th>
2678 <td class="field">
2679 <select id="columns" name="columns">
2680 <option value="1">1</option>
2681 <option value="2">2</option>
2682 <option value="3" selected="selected">3</option>
2683 <option value="4">4</option>
2684 <option value="5">5</option>
2685 <option value="6">6</option>
2686 <option value="7">7</option>
2687 <option value="8">8</option>
2688 <option value="9">9</option>
2689 </select>
2690 </td>
2691 </tr>
2692 </tbody></table>
2693
2694 <p class="ml-submit">
2695 <input type="button" class="button" style="display:none;" onMouseDown="wpgallery.update();" name="insert-gallery" id="insert-gallery" value="<?php esc_attr_e( 'Insert gallery' ); ?>" />
2696 <input type="button" class="button" style="display:none;" onMouseDown="wpgallery.update();" name="update-gallery" id="update-gallery" value="<?php esc_attr_e( 'Update gallery settings' ); ?>" />
2697 </p>
2698 </div>
2699 </form>
2700 <?php
2701}
2702
2703/**
2704 * Outputs the legacy media upload form for the media library.
2705 *
2706 * @since 2.5.0
2707 *
2708 * @global wpdb $wpdb WordPress database abstraction object.
2709 * @global WP_Query $wp_query WordPress Query object.
2710 * @global WP_Locale $wp_locale WordPress date and time locale object.
2711 * @global string $type
2712 * @global string $tab
2713 * @global array $post_mime_types
2714 *
2715 * @param array $errors
2716 */
2717function media_upload_library_form( $errors ) {
2718 global $wpdb, $wp_query, $wp_locale, $type, $tab, $post_mime_types;
2719
2720 media_upload_header();
2721
2722 $post_id = isset( $_REQUEST['post_id'] ) ? (int) $_REQUEST['post_id'] : 0;
2723
2724 $form_action_url = admin_url( "media-upload.php?type=$type&tab=library&post_id=$post_id" );
2725 /** This filter is documented in wp-admin/includes/media.php */
2726 $form_action_url = apply_filters( 'media_upload_form_url', $form_action_url, $type );
2727 $form_class = 'media-upload-form validate';
2728
2729 if ( get_user_setting( 'uploader' ) ) {
2730 $form_class .= ' html-uploader';
2731 }
2732
2733 $q = $_GET;
2734 $q['posts_per_page'] = 10;
2735 $q['paged'] = isset( $q['paged'] ) ? (int) $q['paged'] : 0;
2736 if ( $q['paged'] < 1 ) {
2737 $q['paged'] = 1;
2738 }
2739 $q['offset'] = ( $q['paged'] - 1 ) * 10;
2740 if ( $q['offset'] < 1 ) {
2741 $q['offset'] = 0;
2742 }
2743
2744 list($post_mime_types, $avail_post_mime_types) = wp_edit_attachments_query( $q );
2745
2746 ?>
2747 <form id="filter" method="get">
2748 <input type="hidden" name="type" value="<?php echo esc_attr( $type ); ?>" />
2749 <input type="hidden" name="tab" value="<?php echo esc_attr( $tab ); ?>" />
2750 <input type="hidden" name="post_id" value="<?php echo (int) $post_id; ?>" />
2751 <input type="hidden" name="post_mime_type" value="<?php echo isset( $_GET['post_mime_type'] ) ? esc_attr( $_GET['post_mime_type'] ) : ''; ?>" />
2752 <input type="hidden" name="context" value="<?php echo isset( $_GET['context'] ) ? esc_attr( $_GET['context'] ) : ''; ?>" />
2753
2754 <p id="media-search" class="search-box">
2755 <label class="screen-reader-text" for="media-search-input">
2756 <?php
2757 /* translators: Hidden accessibility text. */
2758 _e( 'Search Media:' );
2759 ?>
2760 </label>
2761 <input type="search" id="media-search-input" name="s" value="<?php the_search_query(); ?>" />
2762 <?php submit_button( __( 'Search Media' ), '', '', false ); ?>
2763 </p>
2764
2765 <ul class="subsubsub">
2766 <?php
2767 $type_links = array();
2768 $_num_posts = (array) wp_count_attachments();
2769 $matches = wp_match_mime_types( array_keys( $post_mime_types ), array_keys( $_num_posts ) );
2770 foreach ( $matches as $_type => $reals ) {
2771 foreach ( $reals as $real ) {
2772 if ( isset( $num_posts[ $_type ] ) ) {
2773 $num_posts[ $_type ] += $_num_posts[ $real ];
2774 } else {
2775 $num_posts[ $_type ] = $_num_posts[ $real ];
2776 }
2777 }
2778 }
2779 // If available type specified by media button clicked, filter by that type.
2780 if ( empty( $_GET['post_mime_type'] ) && ! empty( $num_posts[ $type ] ) ) {
2781 $_GET['post_mime_type'] = $type;
2782 list($post_mime_types, $avail_post_mime_types) = wp_edit_attachments_query();
2783 }
2784 if ( empty( $_GET['post_mime_type'] ) || 'all' === $_GET['post_mime_type'] ) {
2785 $class = ' class="current"';
2786 } else {
2787 $class = '';
2788 }
2789 $type_links[] = '<li><a href="' . esc_url(
2790 add_query_arg(
2791 array(
2792 'post_mime_type' => 'all',
2793 'paged' => false,
2794 'm' => false,
2795 )
2796 )
2797 ) . '"' . $class . '>' . __( 'All Types' ) . '</a>';
2798 foreach ( $post_mime_types as $mime_type => $label ) {
2799 $class = '';
2800
2801 if ( ! wp_match_mime_types( $mime_type, $avail_post_mime_types ) ) {
2802 continue;
2803 }
2804
2805 if ( isset( $_GET['post_mime_type'] ) && wp_match_mime_types( $mime_type, $_GET['post_mime_type'] ) ) {
2806 $class = ' class="current"';
2807 }
2808
2809 $type_links[] = '<li><a href="' . esc_url(
2810 add_query_arg(
2811 array(
2812 'post_mime_type' => $mime_type,
2813 'paged' => false,
2814 )
2815 )
2816 ) . '"' . $class . '>' . sprintf( translate_nooped_plural( $label[2], $num_posts[ $mime_type ] ), '<span id="' . $mime_type . '-counter">' . number_format_i18n( $num_posts[ $mime_type ] ) . '</span>' ) . '</a>';
2817 }
2818 /**
2819 * Filters the media upload mime type list items.
2820 *
2821 * Returned values should begin with an `<li>` tag.
2822 *
2823 * @since 3.1.0
2824 *
2825 * @param string[] $type_links An array of list items containing mime type link HTML.
2826 */
2827 echo implode( ' | </li>', apply_filters( 'media_upload_mime_type_links', $type_links ) ) . '</li>';
2828 unset( $type_links );
2829 ?>
2830 </ul>
2831
2832 <div class="tablenav">
2833
2834 <?php
2835 $page_links = paginate_links(
2836 array(
2837 'base' => add_query_arg( 'paged', '%#%' ),
2838 'format' => '',
2839 'prev_text' => __( '&laquo;' ),
2840 'next_text' => __( '&raquo;' ),
2841 'total' => (int) ceil( $wp_query->found_posts / 10 ),
2842 'current' => $q['paged'],
2843 )
2844 );
2845
2846 if ( $page_links ) {
2847 echo "<div class='tablenav-pages'>$page_links</div>";
2848 }
2849 ?>
2850
2851 <div class="alignleft actions">
2852 <?php
2853 $months = $wpdb->get_results(
2854 "SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
2855 FROM $wpdb->posts
2856 WHERE post_type = 'attachment'
2857 ORDER BY post_date DESC"
2858 );
2859
2860 $month_count = count( $months );
2861 $selected_month = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
2862
2863 if ( $month_count && ( 1 !== $month_count || 0 !== (int) $months[0]->month ) ) {
2864 ?>
2865 <select name='m'>
2866 <option<?php selected( $selected_month, 0 ); ?> value='0'><?php _e( 'All dates' ); ?></option>
2867 <?php
2868 foreach ( $months as $arc_row ) {
2869 if ( 0 === (int) $arc_row->year ) {
2870 continue;
2871 }
2872
2873 $month = zeroise( $arc_row->month, 2 );
2874 $year = $arc_row->year;
2875
2876 printf(
2877 "<option %s value='%s'>%s</option>\n",
2878 selected( $selected_month, $year . $month, false ),
2879 esc_attr( $year . $month ),
2880 /* translators: 1: Month name, 2: 4-digit year. */
2881 esc_html( sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year ) )
2882 );
2883 }
2884 ?>
2885 </select>
2886 <?php } ?>
2887
2888 <?php submit_button( __( 'Filter &#187;' ), '', 'post-query-submit', false ); ?>
2889
2890 </div>
2891
2892 <br class="clear" />
2893 </div>
2894 </form>
2895
2896 <form enctype="multipart/form-data" method="post" action="<?php echo esc_url( $form_action_url ); ?>" class="<?php echo $form_class; ?>" id="library-form">
2897 <?php wp_nonce_field( 'media-form' ); ?>
2898
2899 <script type="text/javascript">
2900 jQuery(function($){
2901 var preloaded = $(".media-item.preloaded");
2902 if ( preloaded.length > 0 ) {
2903 preloaded.each(function(){prepareMediaItem({id:this.id.replace(/[^0-9]/g, '')},'');});
2904 updateMediaForm();
2905 }
2906 });
2907 </script>
2908
2909 <div id="media-items">
2910 <?php add_filter( 'attachment_fields_to_edit', 'media_post_single_attachment_fields_to_edit', 10, 2 ); ?>
2911 <?php echo get_media_items( null, $errors ); ?>
2912 </div>
2913 <p class="ml-submit">
2914 <?php submit_button( __( 'Save all changes' ), 'savebutton', 'save', false ); ?>
2915 <input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
2916 </p>
2917 </form>
2918 <?php
2919}
2920
2921/**
2922 * Creates the form for external url.
2923 *
2924 * @since 2.7.0
2925 *
2926 * @param string $default_view
2927 * @return string HTML content of the form.
2928 */
2929function wp_media_insert_url_form( $default_view = 'image' ) {
2930 /** This filter is documented in wp-admin/includes/media.php */
2931 if ( ! apply_filters( 'disable_captions', '' ) ) {
2932 $caption = '
2933 <tr class="image-only">
2934 <th scope="row" class="label">
2935 <label for="caption"><span class="alignleft">' . __( 'Image Caption' ) . '</span></label>
2936 </th>
2937 <td class="field"><textarea id="caption" name="caption"></textarea></td>
2938 </tr>';
2939 } else {
2940 $caption = '';
2941 }
2942
2943 $default_align = get_option( 'image_default_align' );
2944
2945 if ( empty( $default_align ) ) {
2946 $default_align = 'none';
2947 }
2948
2949 if ( 'image' === $default_view ) {
2950 $view = 'image-only';
2951 $table_class = '';
2952 } else {
2953 $view = 'not-image';
2954 $table_class = $view;
2955 }
2956
2957 return '
2958 <p class="media-types"><label><input type="radio" name="media_type" value="image" id="image-only"' . checked( 'image-only', $view, false ) . ' /> ' . __( 'Image' ) . '</label> &nbsp; &nbsp; <label><input type="radio" name="media_type" value="generic" id="not-image"' . checked( 'not-image', $view, false ) . ' /> ' . __( 'Audio, Video, or Other File' ) . '</label></p>
2959 <p class="media-types media-types-required-info">' .
2960 wp_required_field_message() .
2961 '</p>
2962 <table class="describe ' . $table_class . '"><tbody>
2963 <tr>
2964 <th scope="row" class="label" style="width:130px;">
2965 <label for="src"><span class="alignleft">' . __( 'URL' ) . '</span> ' . wp_required_field_indicator() . '</label>
2966 <span class="alignright" id="status_img"></span>
2967 </th>
2968 <td class="field"><input id="src" name="src" value="" type="text" required onblur="addExtImage.getImageData()" /></td>
2969 </tr>
2970
2971 <tr>
2972 <th scope="row" class="label">
2973 <label for="title"><span class="alignleft">' . __( 'Title' ) . '</span> ' . wp_required_field_indicator() . '</label>
2974 </th>
2975 <td class="field"><input id="title" name="title" value="" type="text" required /></td>
2976 </tr>
2977
2978 <tr class="not-image"><td></td><td><p class="help">' . __( 'Link text, e.g. &#8220;Ransom Demands (PDF)&#8221;' ) . '</p></td></tr>
2979
2980 <tr class="image-only">
2981 <th scope="row" class="label">
2982 <label for="alt"><span class="alignleft">' . __( 'Alternative Text' ) . '</span> ' . wp_required_field_indicator() . '</label>
2983 </th>
2984 <td class="field"><input id="alt" name="alt" value="" type="text" required />
2985 <p class="help">' . __( 'Alt text for the image, e.g. &#8220;The Mona Lisa&#8221;' ) . '</p></td>
2986 </tr>
2987 ' . $caption . '
2988 <tr class="align image-only">
2989 <th scope="row" class="label"><p><label for="align">' . __( 'Alignment' ) . '</label></p></th>
2990 <td class="field">
2991 <input name="align" id="align-none" value="none" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ( 'none' === $default_align ? ' checked="checked"' : '' ) . ' />
2992 <label for="align-none" class="align image-align-none-label">' . __( 'None' ) . '</label>
2993 <input name="align" id="align-left" value="left" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ( 'left' === $default_align ? ' checked="checked"' : '' ) . ' />
2994 <label for="align-left" class="align image-align-left-label">' . __( 'Left' ) . '</label>
2995 <input name="align" id="align-center" value="center" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ( 'center' === $default_align ? ' checked="checked"' : '' ) . ' />
2996 <label for="align-center" class="align image-align-center-label">' . __( 'Center' ) . '</label>
2997 <input name="align" id="align-right" value="right" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ( 'right' === $default_align ? ' checked="checked"' : '' ) . ' />
2998 <label for="align-right" class="align image-align-right-label">' . __( 'Right' ) . '</label>
2999 </td>
3000 </tr>
3001
3002 <tr class="image-only">
3003 <th scope="row" class="label">
3004 <label for="url"><span class="alignleft">' . __( 'Link Image To:' ) . '</span></label>
3005 </th>
3006 <td class="field"><input id="url" name="url" value="" type="text" /><br />
3007
3008 <button type="button" class="button" value="" onclick="document.forms[0].url.value=null">' . __( 'None' ) . '</button>
3009 <button type="button" class="button" value="" onclick="document.forms[0].url.value=document.forms[0].src.value">' . __( 'Link to image' ) . '</button>
3010 <p class="help">' . __( 'Enter a link URL or click above for presets.' ) . '</p></td>
3011 </tr>
3012 <tr class="image-only">
3013 <td></td>
3014 <td>
3015 <input type="button" class="button" id="go_button" style="color:#bbb;" onclick="addExtImage.insert()" value="' . esc_attr__( 'Insert into Post' ) . '" />
3016 </td>
3017 </tr>
3018 <tr class="not-image">
3019 <td></td>
3020 <td>
3021 ' . get_submit_button( __( 'Insert into Post' ), '', 'insertonlybutton', false ) . '
3022 </td>
3023 </tr>
3024 </tbody></table>';
3025}
3026
3027/**
3028 * Displays the multi-file uploader message.
3029 *
3030 * @since 2.6.0
3031 */
3032function media_upload_flash_bypass() {
3033 ?>
3034 <p class="upload-flash-bypass">
3035 <?php
3036 printf(
3037 /* translators: %s: HTML attributes for button. */
3038 __( 'You are using the multi-file uploader. Problems? Try the <button %s>browser uploader</button> instead.' ),
3039 'type="button" class="button-link"'
3040 );
3041 ?>
3042 </p>
3043 <?php
3044}
3045
3046/**
3047 * Displays the browser's built-in uploader message.
3048 *
3049 * @since 2.6.0
3050 */
3051function media_upload_html_bypass() {
3052 ?>
3053 <p class="upload-html-bypass hide-if-no-js">
3054 <?php
3055 printf(
3056 /* translators: %s: HTML attributes for button. */
3057 __( 'You are using the browser&#8217;s built-in file uploader. The WordPress uploader includes multiple file selection and drag and drop capability. <button %s>Switch to the multi-file uploader</button>.' ),
3058 'type="button" class="button-link"'
3059 );
3060 ?>
3061 </p>
3062 <?php
3063}
3064
3065/**
3066 * Used to display a "After a file has been uploaded..." help message.
3067 *
3068 * @since 3.3.0
3069 */
3070function media_upload_text_after() {}
3071
3072/**
3073 * Displays the checkbox to scale images.
3074 *
3075 * @since 3.3.0
3076 */
3077function media_upload_max_image_resize() {
3078 $checked = get_user_setting( 'upload_resize' ) ? ' checked="true"' : '';
3079 $a = '';
3080 $end = '';
3081
3082 if ( current_user_can( 'manage_options' ) ) {
3083 $a = '<a href="' . esc_url( admin_url( 'options-media.php' ) ) . '" target="_blank">';
3084 $end = '</a>';
3085 }
3086
3087 ?>
3088 <p class="hide-if-no-js"><label>
3089 <input name="image_resize" type="checkbox" id="image_resize" value="true"<?php echo $checked; ?> />
3090 <?php
3091 /* translators: 1: Link start tag, 2: Link end tag, 3: Width, 4: Height. */
3092 printf( __( 'Scale images to match the large size selected in %1$simage options%2$s (%3$d &times; %4$d).' ), $a, $end, (int) get_option( 'large_size_w', '1024' ), (int) get_option( 'large_size_h', '1024' ) );
3093
3094 ?>
3095 </label></p>
3096 <?php
3097}
3098
3099/**
3100 * Displays the out of storage quota message in Multisite.
3101 *
3102 * @since 3.5.0
3103 */
3104function multisite_over_quota_message() {
3105 echo '<p>' . sprintf(
3106 /* translators: %s: Allowed space allocation. */
3107 __( 'Sorry, you have used your space allocation of %s. Please delete some files to upload more files.' ),
3108 size_format( get_space_allowed() * MB_IN_BYTES )
3109 ) . '</p>';
3110}
3111
3112/**
3113 * Displays the image and editor in the post editor
3114 *
3115 * @since 3.5.0
3116 *
3117 * @param WP_Post $post A post object.
3118 */
3119function edit_form_image_editor( $post ) {
3120 $open = isset( $_GET['image-editor'] );
3121
3122 if ( $open ) {
3123 require_once ABSPATH . 'wp-admin/includes/image-edit.php';
3124 }
3125
3126 $thumb_url = false;
3127 $attachment_id = (int) $post->ID;
3128
3129 if ( $attachment_id ) {
3130 $thumb_url = wp_get_attachment_image_src( $attachment_id, array( 900, 450 ), true );
3131 }
3132
3133 $alt_text = get_post_meta( $post->ID, '_wp_attachment_image_alt', true );
3134
3135 $att_url = wp_get_attachment_url( $post->ID );
3136 ?>
3137 <div class="wp_attachment_holder wp-clearfix">
3138 <?php
3139
3140 if ( wp_attachment_is_image( $post->ID ) ) :
3141 $image_edit_button = '';
3142 if ( wp_image_editor_supports( array( 'mime_type' => $post->post_mime_type ) ) ) {
3143 $nonce = wp_create_nonce( "image_editor-$post->ID" );
3144 $image_edit_button = "<input type='button' id='imgedit-open-btn-$post->ID' onclick='imageEdit.open( $post->ID, \"$nonce\" )' class='button' value='" . esc_attr__( 'Edit Image' ) . "' /> <span class='spinner'></span>";
3145 }
3146
3147 $open_style = '';
3148 $not_open_style = '';
3149
3150 if ( $open ) {
3151 $open_style = ' style="display:none"';
3152 } else {
3153 $not_open_style = ' style="display:none"';
3154 }
3155
3156 ?>
3157 <div class="imgedit-response" id="imgedit-response-<?php echo $attachment_id; ?>"></div>
3158
3159 <div<?php echo $open_style; ?> class="wp_attachment_image wp-clearfix" id="media-head-<?php echo $attachment_id; ?>">
3160 <p id="thumbnail-head-<?php echo $attachment_id; ?>"><img class="thumbnail" src="<?php echo set_url_scheme( $thumb_url[0] ); ?>" style="max-width:100%" alt="" /></p>
3161 <p><?php echo $image_edit_button; ?></p>
3162 </div>
3163 <div<?php echo $not_open_style; ?> class="image-editor" id="image-editor-<?php echo $attachment_id; ?>">
3164 <?php
3165
3166 if ( $open ) {
3167 wp_image_editor( $attachment_id );
3168 }
3169
3170 ?>
3171 </div>
3172 <?php
3173 elseif ( $attachment_id && wp_attachment_is( 'audio', $post ) ) :
3174
3175 wp_maybe_generate_attachment_metadata( $post );
3176
3177 echo wp_audio_shortcode( array( 'src' => $att_url ) );
3178
3179 elseif ( $attachment_id && wp_attachment_is( 'video', $post ) ) :
3180
3181 wp_maybe_generate_attachment_metadata( $post );
3182
3183 $meta = wp_get_attachment_metadata( $attachment_id );
3184 $w = ! empty( $meta['width'] ) ? min( $meta['width'], 640 ) : 0;
3185 $h = ! empty( $meta['height'] ) ? $meta['height'] : 0;
3186
3187 if ( $h && $w < $meta['width'] ) {
3188 $h = round( ( $meta['height'] * $w ) / $meta['width'] );
3189 }
3190
3191 $attr = array( 'src' => $att_url );
3192
3193 if ( ! empty( $w ) && ! empty( $h ) ) {
3194 $attr['width'] = $w;
3195 $attr['height'] = $h;
3196 }
3197
3198 $thumb_id = get_post_thumbnail_id( $attachment_id );
3199
3200 if ( ! empty( $thumb_id ) ) {
3201 $attr['poster'] = wp_get_attachment_url( $thumb_id );
3202 }
3203
3204 echo wp_video_shortcode( $attr );
3205
3206 elseif ( isset( $thumb_url[0] ) ) :
3207 ?>
3208 <div class="wp_attachment_image wp-clearfix" id="media-head-<?php echo $attachment_id; ?>">
3209 <p id="thumbnail-head-<?php echo $attachment_id; ?>">
3210 <img class="thumbnail" src="<?php echo set_url_scheme( $thumb_url[0] ); ?>" style="max-width:100%" alt="" />
3211 </p>
3212 </div>
3213 <?php
3214
3215 else :
3216
3217 /**
3218 * Fires when an attachment type can't be rendered in the edit form.
3219 *
3220 * @since 4.6.0
3221 *
3222 * @param WP_Post $post A post object.
3223 */
3224 do_action( 'wp_edit_form_attachment_display', $post );
3225
3226 endif;
3227
3228 ?>
3229 </div>
3230 <div class="wp_attachment_details edit-form-section">
3231 <?php if ( str_starts_with( $post->post_mime_type, 'image' ) ) : ?>
3232 <p class="attachment-alt-text">
3233 <label for="attachment_alt"><strong><?php _e( 'Alternative Text' ); ?></strong></label><br />
3234 <textarea class="widefat" name="_wp_attachment_image_alt" id="attachment_alt" aria-describedby="alt-text-description"><?php echo esc_attr( $alt_text ); ?></textarea>
3235 </p>
3236 <p class="attachment-alt-text-description" id="alt-text-description">
3237 <?php
3238
3239 printf(
3240 /* translators: 1: Link to tutorial, 2: Additional link attributes, 3: Accessibility text. */
3241 __( '<a href="%1$s" %2$s>Learn how to describe the purpose of the image%3$s</a>. Leave empty if the image is purely decorative.' ),
3242 /* translators: Localized tutorial, if one exists. W3C Web Accessibility Initiative link has list of existing translations. */
3243 esc_url( __( 'https://www.w3.org/WAI/tutorials/images/decision-tree/' ) ),
3244 'target="_blank"',
3245 sprintf(
3246 '<span class="screen-reader-text"> %s</span>',
3247 /* translators: Hidden accessibility text. */
3248 __( '(opens in a new tab)' )
3249 )
3250 );
3251
3252 ?>
3253 </p>
3254 <?php endif; ?>
3255
3256 <p>
3257 <label for="attachment_caption"><strong><?php _e( 'Caption' ); ?></strong></label><br />
3258 <textarea class="widefat" name="excerpt" id="attachment_caption"><?php echo $post->post_excerpt; ?></textarea>
3259 </p>
3260
3261 <?php
3262
3263 $quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,close' );
3264 $editor_args = array(
3265 'textarea_name' => 'content',
3266 'textarea_rows' => 5,
3267 'media_buttons' => false,
3268 /**
3269 * Filters the TinyMCE argument for the media description field on the attachment details screen.
3270 *
3271 * @since 6.6.0
3272 *
3273 * @param bool $tinymce Whether to activate TinyMCE in media description field. Default false.
3274 */
3275 'tinymce' => apply_filters( 'activate_tinymce_for_media_description', false ),
3276 'quicktags' => $quicktags_settings,
3277 );
3278
3279 ?>
3280
3281 <label for="attachment_content" class="attachment-content-description"><strong><?php _e( 'Description' ); ?></strong>
3282 <?php
3283
3284 if ( preg_match( '#^(audio|video)/#', $post->post_mime_type ) ) {
3285 echo ': ' . __( 'Displayed on attachment pages.' );
3286 }
3287
3288 ?>
3289 </label>
3290 <?php wp_editor( format_to_edit( $post->post_content ), 'attachment_content', $editor_args ); ?>
3291
3292 </div>
3293 <?php
3294
3295 $extras = get_compat_media_markup( $post->ID );
3296 echo $extras['item'];
3297 echo '<input type="hidden" id="image-edit-context" value="edit-attachment" />' . "\n";
3298}
3299
3300/**
3301 * Displays non-editable attachment metadata in the publish meta box.
3302 *
3303 * @since 3.5.0
3304 */
3305function attachment_submitbox_metadata() {
3306 $post = get_post();
3307 $attachment_id = $post->ID;
3308
3309 $file = get_attached_file( $attachment_id );
3310 $filename = esc_html( wp_basename( $file ) );
3311
3312 $media_dims = '';
3313 $meta = wp_get_attachment_metadata( $attachment_id );
3314
3315 if ( isset( $meta['width'], $meta['height'] ) ) {
3316 /* translators: 1: A number of pixels wide, 2: A number of pixels tall. */
3317 $media_dims .= "<span id='media-dims-$attachment_id'>" . sprintf( __( '%1$s by %2$s pixels' ), $meta['width'], $meta['height'] ) . '</span>';
3318 }
3319 /** This filter is documented in wp-admin/includes/media.php */
3320 $media_dims = apply_filters( 'media_meta', $media_dims, $post );
3321
3322 $att_url = wp_get_attachment_url( $attachment_id );
3323
3324 $author = new WP_User( $post->post_author );
3325
3326 $uploaded_by_name = __( '(no author)' );
3327 $uploaded_by_link = '';
3328
3329 if ( $author->exists() ) {
3330 $uploaded_by_name = $author->display_name ? $author->display_name : $author->nickname;
3331 $uploaded_by_link = get_edit_user_link( $author->ID );
3332 }
3333 ?>
3334 <div class="misc-pub-section misc-pub-uploadedby word-wrap-break-word">
3335 <?php if ( $uploaded_by_link ) { ?>
3336 <?php _e( 'Uploaded by:' ); ?> <a href="<?php echo $uploaded_by_link; ?>"><strong><?php echo $uploaded_by_name; ?></strong></a>
3337 <?php } else { ?>
3338 <?php _e( 'Uploaded by:' ); ?> <strong><?php echo $uploaded_by_name; ?></strong>
3339 <?php } ?>
3340 </div>
3341
3342 <?php
3343 if ( $post->post_parent ) {
3344 $post_parent = get_post( $post->post_parent );
3345 if ( $post_parent ) {
3346 $uploaded_to_title = $post_parent->post_title ? $post_parent->post_title : __( '(no title)' );
3347 $uploaded_to_link = get_edit_post_link( $post->post_parent, 'raw' );
3348 ?>
3349 <div class="misc-pub-section misc-pub-uploadedto">
3350 <?php if ( $uploaded_to_link ) { ?>
3351 <?php _e( 'Uploaded to:' ); ?> <a href="<?php echo $uploaded_to_link; ?>"><strong><?php echo $uploaded_to_title; ?></strong></a>
3352 <?php } else { ?>
3353 <?php _e( 'Uploaded to:' ); ?> <strong><?php echo $uploaded_to_title; ?></strong>
3354 <?php } ?>
3355 </div>
3356 <?php
3357 }
3358 }
3359 ?>
3360
3361 <div class="misc-pub-section misc-pub-attachment">
3362 <label for="attachment_url"><?php _e( 'File URL:' ); ?></label>
3363 <input type="text" class="widefat urlfield" readonly="readonly" name="attachment_url" id="attachment_url" value="<?php echo esc_attr( $att_url ); ?>" />
3364 <span class="copy-to-clipboard-container">
3365 <button type="button" class="button copy-attachment-url edit-media" data-clipboard-target="#attachment_url"><?php _e( 'Copy URL to clipboard' ); ?></button>
3366 <span class="success hidden" aria-hidden="true"><?php _e( 'Copied!' ); ?></span>
3367 </span>
3368 </div>
3369 <div class="misc-pub-section misc-pub-download">
3370 <a href="<?php echo esc_attr( $att_url ); ?>" download><?php _e( 'Download file' ); ?></a>
3371 </div>
3372 <div class="misc-pub-section misc-pub-filename">
3373 <?php _e( 'File name:' ); ?> <strong><?php echo $filename; ?></strong>
3374 </div>
3375 <div class="misc-pub-section misc-pub-filetype">
3376 <?php _e( 'File type:' ); ?>
3377 <strong>
3378 <?php
3379
3380 if ( preg_match( '/^.*?\.(\w+)$/', get_attached_file( $post->ID ), $matches ) ) {
3381 echo esc_html( strtoupper( $matches[1] ) );
3382 list( $mime_type ) = explode( '/', $post->post_mime_type );
3383 if ( 'image' !== $mime_type && ! empty( $meta['mime_type'] ) ) {
3384 if ( "$mime_type/" . strtolower( $matches[1] ) !== $meta['mime_type'] ) {
3385 echo ' (' . $meta['mime_type'] . ')';
3386 }
3387 }
3388 } else {
3389 echo strtoupper( str_replace( 'image/', '', $post->post_mime_type ) );
3390 }
3391
3392 ?>
3393 </strong>
3394 </div>
3395
3396 <?php
3397
3398 $file_size = false;
3399
3400 if ( isset( $meta['filesize'] ) ) {
3401 $file_size = $meta['filesize'];
3402 } elseif ( file_exists( $file ) ) {
3403 $file_size = wp_filesize( $file );
3404 }
3405
3406 if ( ! empty( $file_size ) ) {
3407 ?>
3408 <div class="misc-pub-section misc-pub-filesize">
3409 <?php _e( 'File size:' ); ?> <strong><?php echo size_format( $file_size ); ?></strong>
3410 </div>
3411 <?php
3412 }
3413
3414 if ( preg_match( '#^(audio|video)/#', $post->post_mime_type ) ) {
3415 $fields = array(
3416 'length_formatted' => __( 'Length:' ),
3417 'bitrate' => __( 'Bitrate:' ),
3418 );
3419
3420 /**
3421 * Filters the audio and video metadata fields to be shown in the publish meta box.
3422 *
3423 * The key for each item in the array should correspond to an attachment
3424 * metadata key, and the value should be the desired label.
3425 *
3426 * @since 3.7.0
3427 * @since 4.9.0 Added the `$post` parameter.
3428 *
3429 * @param array $fields An array of the attachment metadata keys and labels.
3430 * @param WP_Post $post WP_Post object for the current attachment.
3431 */
3432 $fields = apply_filters( 'media_submitbox_misc_sections', $fields, $post );
3433
3434 foreach ( $fields as $key => $label ) {
3435 if ( empty( $meta[ $key ] ) ) {
3436 continue;
3437 }
3438
3439 ?>
3440 <div class="misc-pub-section misc-pub-mime-meta misc-pub-<?php echo sanitize_html_class( $key ); ?>">
3441 <?php echo $label; ?>
3442 <strong>
3443 <?php
3444
3445 switch ( $key ) {
3446 case 'bitrate':
3447 echo round( $meta['bitrate'] / 1000 ) . 'kb/s';
3448 if ( ! empty( $meta['bitrate_mode'] ) ) {
3449 echo ' ' . strtoupper( esc_html( $meta['bitrate_mode'] ) );
3450 }
3451 break;
3452 case 'length_formatted':
3453 echo human_readable_duration( $meta['length_formatted'] );
3454 break;
3455 default:
3456 echo esc_html( $meta[ $key ] );
3457 break;
3458 }
3459
3460 ?>
3461 </strong>
3462 </div>
3463 <?php
3464 }
3465
3466 $fields = array(
3467 'dataformat' => __( 'Audio Format:' ),
3468 'codec' => __( 'Audio Codec:' ),
3469 );
3470
3471 /**
3472 * Filters the audio attachment metadata fields to be shown in the publish meta box.
3473 *
3474 * The key for each item in the array should correspond to an attachment
3475 * metadata key, and the value should be the desired label.
3476 *
3477 * @since 3.7.0
3478 * @since 4.9.0 Added the `$post` parameter.
3479 *
3480 * @param array $fields An array of the attachment metadata keys and labels.
3481 * @param WP_Post $post WP_Post object for the current attachment.
3482 */
3483 $audio_fields = apply_filters( 'audio_submitbox_misc_sections', $fields, $post );
3484
3485 foreach ( $audio_fields as $key => $label ) {
3486 if ( empty( $meta['audio'][ $key ] ) ) {
3487 continue;
3488 }
3489
3490 ?>
3491 <div class="misc-pub-section misc-pub-audio misc-pub-<?php echo sanitize_html_class( $key ); ?>">
3492 <?php echo $label; ?> <strong><?php echo esc_html( $meta['audio'][ $key ] ); ?></strong>
3493 </div>
3494 <?php
3495 }
3496 }
3497
3498 if ( $media_dims ) {
3499 ?>
3500 <div class="misc-pub-section misc-pub-dimensions">
3501 <?php _e( 'Dimensions:' ); ?> <strong><?php echo $media_dims; ?></strong>
3502 </div>
3503 <?php
3504 }
3505
3506 if ( ! empty( $meta['original_image'] ) ) {
3507 ?>
3508 <div class="misc-pub-section misc-pub-original-image word-wrap-break-word">
3509 <?php _e( 'Original image:' ); ?>
3510 <a href="<?php echo esc_url( wp_get_original_image_url( $attachment_id ) ); ?>">
3511 <strong><?php echo esc_html( wp_basename( wp_get_original_image_path( $attachment_id ) ) ); ?></strong>
3512 </a>
3513 </div>
3514 <?php
3515 }
3516}
3517
3518/**
3519 * Parses ID3v2, ID3v1, and getID3 comments to extract usable data.
3520 *
3521 * @since 3.6.0
3522 *
3523 * @param array $metadata An existing array with data.
3524 * @param array $data Data supplied by ID3 tags.
3525 */
3526function wp_add_id3_tag_data( &$metadata, $data ) {
3527 foreach ( array( 'id3v2', 'id3v1' ) as $version ) {
3528 if ( ! empty( $data[ $version ]['comments'] ) ) {
3529 foreach ( $data[ $version ]['comments'] as $key => $list ) {
3530 if ( 'length' !== $key && ! empty( $list ) ) {
3531 $metadata[ $key ] = is_array( $list ) ? wp_kses_post_deep( reset( $list ) ) : wp_kses_post( $list );
3532 // Fix bug in byte stream analysis.
3533 if ( 'terms_of_use' === $key && str_starts_with( $metadata[ $key ], 'yright notice.' ) ) {
3534 $metadata[ $key ] = 'Cop' . $metadata[ $key ];
3535 }
3536 }
3537 }
3538 break;
3539 }
3540 }
3541
3542 if ( ! empty( $data['id3v2']['APIC'] ) ) {
3543 $image = reset( $data['id3v2']['APIC'] );
3544 if ( ! empty( $image['data'] ) ) {
3545 $metadata['image'] = array(
3546 'data' => $image['data'],
3547 'mime' => $image['image_mime'],
3548 'width' => $image['image_width'],
3549 'height' => $image['image_height'],
3550 );
3551 }
3552 } elseif ( ! empty( $data['comments']['picture'] ) ) {
3553 $image = reset( $data['comments']['picture'] );
3554 if ( ! empty( $image['data'] ) ) {
3555 $metadata['image'] = array(
3556 'data' => $image['data'],
3557 'mime' => $image['image_mime'],
3558 );
3559 }
3560 }
3561}
3562
3563/**
3564 * Retrieves metadata from a video file's ID3 tags.
3565 *
3566 * @since 3.6.0
3567 *
3568 * @param string $file Path to file.
3569 * @return array|false Returns array of metadata, if found.
3570 */
3571function wp_read_video_metadata( $file ) {
3572 if ( ! file_exists( $file ) ) {
3573 return false;
3574 }
3575
3576 $metadata = array();
3577
3578 if ( ! defined( 'GETID3_TEMP_DIR' ) ) {
3579 define( 'GETID3_TEMP_DIR', get_temp_dir() );
3580 }
3581
3582 if ( ! class_exists( 'getID3', false ) ) {
3583 require ABSPATH . WPINC . '/ID3/getid3.php';
3584 }
3585
3586 $id3 = new getID3();
3587 // Required to get the `created_timestamp` value.
3588 $id3->options_audiovideo_quicktime_ReturnAtomData = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName
3589
3590 $data = $id3->analyze( $file );
3591
3592 if ( isset( $data['video']['lossless'] ) ) {
3593 $metadata['lossless'] = $data['video']['lossless'];
3594 }
3595
3596 if ( ! empty( $data['video']['bitrate'] ) ) {
3597 $metadata['bitrate'] = (int) $data['video']['bitrate'];
3598 }
3599
3600 if ( ! empty( $data['video']['bitrate_mode'] ) ) {
3601 $metadata['bitrate_mode'] = $data['video']['bitrate_mode'];
3602 }
3603
3604 if ( ! empty( $data['filesize'] ) ) {
3605 $metadata['filesize'] = (int) $data['filesize'];
3606 }
3607
3608 if ( ! empty( $data['mime_type'] ) ) {
3609 $metadata['mime_type'] = $data['mime_type'];
3610 }
3611
3612 if ( ! empty( $data['playtime_seconds'] ) ) {
3613 $metadata['length'] = (int) round( $data['playtime_seconds'] );
3614 }
3615
3616 if ( ! empty( $data['playtime_string'] ) ) {
3617 $metadata['length_formatted'] = $data['playtime_string'];
3618 }
3619
3620 if ( ! empty( $data['video']['resolution_x'] ) ) {
3621 $metadata['width'] = (int) $data['video']['resolution_x'];
3622 }
3623
3624 if ( ! empty( $data['video']['resolution_y'] ) ) {
3625 $metadata['height'] = (int) $data['video']['resolution_y'];
3626 }
3627
3628 if ( ! empty( $data['fileformat'] ) ) {
3629 $metadata['fileformat'] = $data['fileformat'];
3630 }
3631
3632 if ( ! empty( $data['video']['dataformat'] ) ) {
3633 $metadata['dataformat'] = $data['video']['dataformat'];
3634 }
3635
3636 if ( ! empty( $data['video']['encoder'] ) ) {
3637 $metadata['encoder'] = $data['video']['encoder'];
3638 }
3639
3640 if ( ! empty( $data['video']['codec'] ) ) {
3641 $metadata['codec'] = $data['video']['codec'];
3642 }
3643
3644 if ( ! empty( $data['audio'] ) ) {
3645 unset( $data['audio']['streams'] );
3646 $metadata['audio'] = $data['audio'];
3647 }
3648
3649 if ( empty( $metadata['created_timestamp'] ) ) {
3650 $created_timestamp = wp_get_media_creation_timestamp( $data );
3651
3652 if ( false !== $created_timestamp ) {
3653 $metadata['created_timestamp'] = $created_timestamp;
3654 }
3655 }
3656
3657 wp_add_id3_tag_data( $metadata, $data );
3658
3659 $file_format = isset( $metadata['fileformat'] ) ? $metadata['fileformat'] : null;
3660
3661 /**
3662 * Filters the array of metadata retrieved from a video.
3663 *
3664 * In core, usually this selection is what is stored.
3665 * More complete data can be parsed from the `$data` parameter.
3666 *
3667 * @since 4.9.0
3668 *
3669 * @param array $metadata Filtered video metadata.
3670 * @param string $file Path to video file.
3671 * @param string|null $file_format File format of video, as analyzed by getID3.
3672 * Null if unknown.
3673 * @param array $data Raw metadata from getID3.
3674 */
3675 return apply_filters( 'wp_read_video_metadata', $metadata, $file, $file_format, $data );
3676}
3677
3678/**
3679 * Retrieves metadata from an audio file's ID3 tags.
3680 *
3681 * @since 3.6.0
3682 *
3683 * @param string $file Path to file.
3684 * @return array|false Returns array of metadata, if found.
3685 */
3686function wp_read_audio_metadata( $file ) {
3687 if ( ! file_exists( $file ) ) {
3688 return false;
3689 }
3690
3691 $metadata = array();
3692
3693 if ( ! defined( 'GETID3_TEMP_DIR' ) ) {
3694 define( 'GETID3_TEMP_DIR', get_temp_dir() );
3695 }
3696
3697 if ( ! class_exists( 'getID3', false ) ) {
3698 require ABSPATH . WPINC . '/ID3/getid3.php';
3699 }
3700
3701 $id3 = new getID3();
3702 // Required to get the `created_timestamp` value.
3703 $id3->options_audiovideo_quicktime_ReturnAtomData = true; // phpcs:ignore WordPress.NamingConventions.ValidVariableName
3704
3705 $data = $id3->analyze( $file );
3706
3707 if ( ! empty( $data['audio'] ) ) {
3708 unset( $data['audio']['streams'] );
3709 $metadata = $data['audio'];
3710 }
3711
3712 if ( ! empty( $data['fileformat'] ) ) {
3713 $metadata['fileformat'] = $data['fileformat'];
3714 }
3715
3716 if ( ! empty( $data['filesize'] ) ) {
3717 $metadata['filesize'] = (int) $data['filesize'];
3718 }
3719
3720 if ( ! empty( $data['mime_type'] ) ) {
3721 $metadata['mime_type'] = $data['mime_type'];
3722 }
3723
3724 if ( ! empty( $data['playtime_seconds'] ) ) {
3725 $metadata['length'] = (int) round( $data['playtime_seconds'] );
3726 }
3727
3728 if ( ! empty( $data['playtime_string'] ) ) {
3729 $metadata['length_formatted'] = $data['playtime_string'];
3730 }
3731
3732 if ( empty( $metadata['created_timestamp'] ) ) {
3733 $created_timestamp = wp_get_media_creation_timestamp( $data );
3734
3735 if ( false !== $created_timestamp ) {
3736 $metadata['created_timestamp'] = $created_timestamp;
3737 }
3738 }
3739
3740 wp_add_id3_tag_data( $metadata, $data );
3741
3742 $file_format = isset( $metadata['fileformat'] ) ? $metadata['fileformat'] : null;
3743
3744 /**
3745 * Filters the array of metadata retrieved from an audio file.
3746 *
3747 * In core, usually this selection is what is stored.
3748 * More complete data can be parsed from the `$data` parameter.
3749 *
3750 * @since 6.1.0
3751 *
3752 * @param array $metadata Filtered audio metadata.
3753 * @param string $file Path to audio file.
3754 * @param string|null $file_format File format of audio, as analyzed by getID3.
3755 * Null if unknown.
3756 * @param array $data Raw metadata from getID3.
3757 */
3758 return apply_filters( 'wp_read_audio_metadata', $metadata, $file, $file_format, $data );
3759}
3760
3761/**
3762 * Parses creation date from media metadata.
3763 *
3764 * The getID3 library doesn't have a standard method for getting creation dates,
3765 * so the location of this data can vary based on the MIME type.
3766 *
3767 * @since 4.9.0
3768 *
3769 * @link https://github.com/JamesHeinrich/getID3/blob/master/structure.txt
3770 *
3771 * @param array $metadata The metadata returned by getID3::analyze().
3772 * @return int|false A UNIX timestamp for the media's creation date if available
3773 * or a boolean FALSE if a timestamp could not be determined.
3774 */
3775function wp_get_media_creation_timestamp( $metadata ) {
3776 $creation_date = false;
3777
3778 if ( empty( $metadata['fileformat'] ) ) {
3779 return $creation_date;
3780 }
3781
3782 switch ( $metadata['fileformat'] ) {
3783 case 'asf':
3784 if ( isset( $metadata['asf']['file_properties_object']['creation_date_unix'] ) ) {
3785 $creation_date = (int) $metadata['asf']['file_properties_object']['creation_date_unix'];
3786 }
3787 break;
3788
3789 case 'matroska':
3790 case 'webm':
3791 if ( isset( $metadata['matroska']['comments']['creation_time'][0] ) ) {
3792 $creation_date = strtotime( $metadata['matroska']['comments']['creation_time'][0] );
3793 } elseif ( isset( $metadata['matroska']['info'][0]['DateUTC_unix'] ) ) {
3794 $creation_date = (int) $metadata['matroska']['info'][0]['DateUTC_unix'];
3795 }
3796 break;
3797
3798 case 'quicktime':
3799 case 'mp4':
3800 if ( isset( $metadata['quicktime']['moov']['subatoms'][0]['creation_time_unix'] ) ) {
3801 $creation_date = (int) $metadata['quicktime']['moov']['subatoms'][0]['creation_time_unix'];
3802 }
3803 break;
3804 }
3805
3806 return $creation_date;
3807}
3808
3809/**
3810 * Encapsulates the logic for Attach/Detach actions.
3811 *
3812 * @since 4.2.0
3813 *
3814 * @global wpdb $wpdb WordPress database abstraction object.
3815 *
3816 * @param int $parent_id Attachment parent ID.
3817 * @param string $action Optional. Attach/detach action. Accepts 'attach' or 'detach'.
3818 * Default 'attach'.
3819 */
3820function wp_media_attach_action( $parent_id, $action = 'attach' ) {
3821 global $wpdb;
3822
3823 if ( ! $parent_id ) {
3824 return;
3825 }
3826
3827 if ( ! current_user_can( 'edit_post', $parent_id ) ) {
3828 wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
3829 }
3830
3831 $ids = array();
3832
3833 foreach ( (array) $_REQUEST['media'] as $attachment_id ) {
3834 $attachment_id = (int) $attachment_id;
3835
3836 if ( ! current_user_can( 'edit_post', $attachment_id ) ) {
3837 continue;
3838 }
3839
3840 $ids[] = $attachment_id;
3841 }
3842
3843 if ( ! empty( $ids ) ) {
3844 $ids_string = implode( ',', $ids );
3845
3846 if ( 'attach' === $action ) {
3847 $result = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_parent = %d WHERE post_type = 'attachment' AND ID IN ( $ids_string )", $parent_id ) );
3848 } else {
3849 $result = $wpdb->query( "UPDATE $wpdb->posts SET post_parent = 0 WHERE post_type = 'attachment' AND ID IN ( $ids_string )" );
3850 }
3851 }
3852
3853 if ( isset( $result ) ) {
3854 foreach ( $ids as $attachment_id ) {
3855 /**
3856 * Fires when media is attached or detached from a post.
3857 *
3858 * @since 5.5.0
3859 *
3860 * @param string $action Attach/detach action. Accepts 'attach' or 'detach'.
3861 * @param int $attachment_id The attachment ID.
3862 * @param int $parent_id Attachment parent ID.
3863 */
3864 do_action( 'wp_media_attach_action', $action, $attachment_id, $parent_id );
3865
3866 clean_attachment_cache( $attachment_id );
3867 }
3868
3869 $location = 'upload.php';
3870 $referer = wp_get_referer();
3871
3872 if ( $referer ) {
3873 if ( str_contains( $referer, 'upload.php' ) ) {
3874 $location = remove_query_arg( array( 'attached', 'detach' ), $referer );
3875 }
3876 }
3877
3878 $key = 'attach' === $action ? 'attached' : 'detach';
3879 $location = add_query_arg( array( $key => $result ), $location );
3880
3881 wp_redirect( $location );
3882 exit;
3883 }
3884}
3885
Ui Ux Design – Teachers Night Out https://cardgames4educators.com Wed, 16 Oct 2024 22:24:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://cardgames4educators.com/wp-content/uploads/2024/06/cropped-Card-4-Educators-logo-32x32.png Ui Ux Design – Teachers Night Out https://cardgames4educators.com 32 32 Masters In English How English Speaker https://cardgames4educators.com/masters-in-english-how-english-speaker/ https://cardgames4educators.com/masters-in-english-how-english-speaker/#comments Mon, 27 May 2024 08:54:45 +0000 https://themexriver.com/wp/kadu/?p=1

Erat himenaeos neque id sagittis massa. Hac suscipit pulvinar dignissim platea magnis eu. Don tellus a pharetra inceptos efficitur dui pulvinar. Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent pulvinar odio volutpat parturient. Quisque risus finibus suspendisse mus purus magnis facilisi condimentum consectetur dui. Curae elit suspendisse cursus vehicula.

Turpis taciti class non vel pretium quis pulvinar tempor lobortis nunc. Libero phasellus parturient sapien volutpat malesuada ornare. Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae. Porta est tempor ex eget feugiat vulputate ipsum. Justo nec iaculis habitant diam arcu fermentum.

We offer comprehen sive emplo ment services such as assistance wit employer compliance.Our company is your strategic HR partner as instead of HR. john smithson

Cubilia dignissim sollicitudin rhoncus lacinia maximus. Cras lorem fermentum bibendum pellentesque nisl etiam ligula enim cubilia. Vulputate pede sapien torquent montes tempus malesuada in mattis dis turpis vitae.

Exploring Learning Landscapes in Academic

Feugiat facilisis penatibus pulvinar nunc dictumst donec odio platea habitasse. Lacus porta dolor purus elit ante bibendum tortor netus taciti nullam cubilia. Erat per suspendisse placerat morbi egestas pulvinar bibendum sollicitudin nec. Euismod cubilia eleifend velit himenaeos sodales lectus. Leo maximus cras ac porttitor aliquam torquent.

]]>
https://cardgames4educators.com/masters-in-english-how-english-speaker/feed/ 1