Issues (2010)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

wp-admin/includes/media.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

Code
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 array default tabs
15
 */
16
function 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 array $_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
 */
44
function 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 = intval($_REQUEST['post_id']);
53
54
	if ( $post_id )
55
		$attachments = intval( $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
	if ( empty($attachments) ) {
58
		unset($tabs['gallery']);
59
		return $tabs;
60
	}
61
62
	$tabs['gallery'] = sprintf(__('Gallery (%s)'), "<span id='attachments-count'>$attachments</span>");
63
64
	return $tabs;
65
}
66
67
/**
68
 * Outputs the legacy media upload tabs UI.
69
 *
70
 * @since 2.5.0
71
 *
72
 * @global string $redir_tab
73
 */
74
function the_media_upload_tabs() {
75
	global $redir_tab;
76
	$tabs = media_upload_tabs();
77
	$default = 'type';
78
79
	if ( !empty($tabs) ) {
80
		echo "<ul id='sidemenu'>\n";
81
		if ( isset($redir_tab) && array_key_exists($redir_tab, $tabs) ) {
82
			$current = $redir_tab;
83
		} elseif ( isset($_GET['tab']) && array_key_exists($_GET['tab'], $tabs) ) {
84
			$current = $_GET['tab'];
85
		} else {
86
			/** This filter is documented in wp-admin/media-upload.php */
87
			$current = apply_filters( 'media_upload_default_tab', $default );
88
		}
89
90
		foreach ( $tabs as $callback => $text ) {
91
			$class = '';
92
93
			if ( $current == $callback )
94
				$class = " class='current'";
95
96
			$href = add_query_arg(array('tab' => $callback, 's' => false, 'paged' => false, 'post_mime_type' => false, 'm' => false));
97
			$link = "<a href='" . esc_url($href) . "'$class>$text</a>";
98
			echo "\t<li id='" . esc_attr("tab-$callback") . "'>$link</li>\n";
99
		}
100
		echo "</ul>\n";
101
	}
102
}
103
104
/**
105
 * Retrieves the image HTML to send to the editor.
106
 *
107
 * @since 2.5.0
108
 *
109
 * @param int          $id      Image attachment id.
110
 * @param string       $caption Image caption.
111
 * @param string       $title   Image title attribute.
112
 * @param string       $align   Image CSS alignment property.
113
 * @param string       $url     Optional. Image src URL. Default empty.
114
 * @param bool|string  $rel     Optional. Value for rel attribute or whether to add a default value. Default false.
115
 * @param string|array $size    Optional. Image size. Accepts any valid image size, or an array of width
116
 *                              and height values in pixels (in that order). Default 'medium'.
117
 * @param string       $alt     Optional. Image alt attribute. Default empty.
118
 * @return string The HTML output to insert into the editor.
119
 */
120
function get_image_send_to_editor( $id, $caption, $title, $align, $url = '', $rel = false, $size = 'medium', $alt = '' ) {
121
122
	$html = get_image_tag( $id, $alt, '', $align, $size );
123
124
	if ( $rel ) {
125
		if ( is_string( $rel ) ) {
126
			$rel = ' rel="' . esc_attr( $rel ) . '"';
127
		} else {
128
			$rel = ' rel="attachment wp-att-' . intval( $id ) . '"';
129
		}
130
	} else {
131
		$rel = '';
132
	}
133
134
	if ( $url )
135
		$html = '<a href="' . esc_attr( $url ) . '"' . $rel . '>' . $html . '</a>';
136
137
	/**
138
	 * Filters the image HTML markup to send to the editor.
139
	 *
140
	 * @since 2.5.0
141
	 *
142
	 * @param string       $html    The image HTML markup to send.
143
	 * @param int          $id      The attachment id.
144
	 * @param string       $caption The image caption.
145
	 * @param string       $title   The image title.
146
	 * @param string       $align   The image alignment.
147
	 * @param string       $url     The image source URL.
148
	 * @param string|array $size    Size of image. Image size or array of width and height values
149
	 *                              (in that order). Default 'medium'.
150
	 * @param string       $alt     The image alternative, or alt, text.
151
	 */
152
	$html = apply_filters( 'image_send_to_editor', $html, $id, $caption, $title, $align, $url, $size, $alt );
153
154
	return $html;
155
}
156
157
/**
158
 * Adds image shortcode with caption to editor
159
 *
160
 * @since 2.6.0
161
 *
162
 * @param string $html
163
 * @param integer $id
164
 * @param string $caption image caption
165
 * @param string $title image title attribute
166
 * @param string $align image css alignment property
167
 * @param string $url image src url
168
 * @param string $size image size (thumbnail, medium, large, full or added with add_image_size() )
169
 * @param string $alt image alt attribute
170
 * @return string
171
 */
172
function image_add_caption( $html, $id, $caption, $title, $align, $url, $size, $alt = '' ) {
173
174
	/**
175
	 * Filters the caption text.
176
	 *
177
	 * Note: If the caption text is empty, the caption shortcode will not be appended
178
	 * to the image HTML when inserted into the editor.
179
	 *
180
	 * Passing an empty value also prevents the {@see 'image_add_caption_shortcode'}
181
	 * Filters from being evaluated at the end of image_add_caption().
182
	 *
183
	 * @since 4.1.0
184
	 *
185
	 * @param string $caption The original caption text.
186
	 * @param int    $id      The attachment ID.
187
	 */
188
	$caption = apply_filters( 'image_add_caption_text', $caption, $id );
189
190
	/**
191
	 * Filters whether to disable captions.
192
	 *
193
	 * Prevents image captions from being appended to image HTML when inserted into the editor.
194
	 *
195
	 * @since 2.6.0
196
	 *
197
	 * @param bool $bool Whether to disable appending captions. Returning true to the filter
198
	 *                   will disable captions. Default empty string.
199
	 */
200
	if ( empty($caption) || apply_filters( 'disable_captions', '' ) )
201
		return $html;
202
203
	$id = ( 0 < (int) $id ) ? 'attachment_' . $id : '';
204
205
	if ( ! preg_match( '/width=["\']([0-9]+)/', $html, $matches ) )
206
		return $html;
207
208
	$width = $matches[1];
209
210
	$caption = str_replace( array("\r\n", "\r"), "\n", $caption);
211
	$caption = preg_replace_callback( '/<[a-zA-Z0-9]+(?: [^<>]+>)*/', '_cleanup_image_add_caption', $caption );
212
213
	// Convert any remaining line breaks to <br>.
214
	$caption = preg_replace( '/[ \n\t]*\n[ \t]*/', '<br />', $caption );
215
216
	$html = preg_replace( '/(class=["\'][^\'"]*)align(none|left|right|center)\s?/', '$1', $html );
217
	if ( empty($align) )
218
		$align = 'none';
219
220
	$shcode = '[caption id="' . $id . '" align="align' . $align	. '" width="' . $width . '"]' . $html . ' ' . $caption . '[/caption]';
221
222
	/**
223
	 * Filters the image HTML markup including the caption shortcode.
224
	 *
225
	 * @since 2.6.0
226
	 *
227
	 * @param string $shcode The image HTML markup with caption shortcode.
228
	 * @param string $html   The image HTML markup.
229
	 */
230
	return apply_filters( 'image_add_caption_shortcode', $shcode, $html );
231
}
232
233
/**
234
 * Private preg_replace callback used in image_add_caption()
235
 *
236
 * @access private
237
 * @since 3.4.0
238
 */
239
function _cleanup_image_add_caption( $matches ) {
240
	// Remove any line breaks from inside the tags.
241
	return preg_replace( '/[\r\n\t]+/', ' ', $matches[0] );
242
}
243
244
/**
245
 * Adds image html to editor
246
 *
247
 * @since 2.5.0
248
 *
249
 * @param string $html
250
 */
251
function media_send_to_editor($html) {
252
?>
253
<script type="text/javascript">
254
var win = window.dialogArguments || opener || parent || top;
255
win.send_to_editor( <?php echo wp_json_encode( $html ); ?> );
256
</script>
257
<?php
258
	exit;
259
}
260
261
/**
262
 * Save a file submitted from a POST request and create an attachment post for it.
263
 *
264
 * @since 2.5.0
265
 *
266
 * @param string $file_id   Index of the `$_FILES` array that the file was sent. Required.
267
 * @param int    $post_id   The post ID of a post to attach the media item to. Required, but can
268
 *                          be set to 0, creating a media item that has no relationship to a post.
269
 * @param array  $post_data Overwrite some of the attachment. Optional.
270
 * @param array  $overrides Override the wp_handle_upload() behavior. Optional.
271
 * @return int|WP_Error ID of the attachment or a WP_Error object on failure.
272
 */
273
function media_handle_upload($file_id, $post_id, $post_data = array(), $overrides = array( 'test_form' => false )) {
274
275
	$time = current_time('mysql');
276 View Code Duplication
	if ( $post = get_post($post_id) ) {
277
		if ( substr( $post->post_date, 0, 4 ) > 0 )
278
			$time = $post->post_date;
279
	}
280
281
	$name = $_FILES[$file_id]['name'];
282
	$file = wp_handle_upload($_FILES[$file_id], $overrides, $time);
283
284
	if ( isset($file['error']) )
285
		return new WP_Error( 'upload_error', $file['error'] );
286
287
	$basename = pathinfo( $name, PATHINFO_BASENAME );
288
289
	$url = $file['url'];
290
	$type = $file['type'];
291
	$file = $file['file'];
292
	$title = $basename;
293
	$content = '';
294
	$excerpt = '';
295
296
	if ( preg_match( '#^audio#', $type ) ) {
297
		$meta = wp_read_audio_metadata( $file );
298
299
		if ( ! empty( $meta['title'] ) ) {
300
			$title = $meta['title'];
301
		}
302
303
		if ( ! empty( $title ) ) {
304
305
			if ( ! empty( $meta['album'] ) && ! empty( $meta['artist'] ) ) {
306
				/* translators: 1: audio track title, 2: album title, 3: artist name */
307
				$content .= sprintf( __( '"%1$s" from %2$s by %3$s.' ), $title, $meta['album'], $meta['artist'] );
308
			} elseif ( ! empty( $meta['album'] ) ) {
309
				/* translators: 1: audio track title, 2: album title */
310
				$content .= sprintf( __( '"%1$s" from %2$s.' ), $title, $meta['album'] );
311
			} elseif ( ! empty( $meta['artist'] ) ) {
312
				/* translators: 1: audio track title, 2: artist name */
313
				$content .= sprintf( __( '"%1$s" by %2$s.' ), $title, $meta['artist'] );
314
			} else {
315
				$content .= sprintf( __( '"%s".' ), $title );
316
			}
317
318
		} elseif ( ! empty( $meta['album'] ) ) {
319
320
			if ( ! empty( $meta['artist'] ) ) {
321
				/* translators: 1: audio album title, 2: artist name */
322
				$content .= sprintf( __( '%1$s by %2$s.' ), $meta['album'], $meta['artist'] );
323
			} else {
324
				$content .= $meta['album'] . '.';
325
			}
326
327
		} elseif ( ! empty( $meta['artist'] ) ) {
328
329
			$content .= $meta['artist'] . '.';
330
331
		}
332
333
		if ( ! empty( $meta['year'] ) )
334
			$content .= ' ' . sprintf( __( 'Released: %d.' ), $meta['year'] );
335
336
		if ( ! empty( $meta['track_number'] ) ) {
337
			$track_number = explode( '/', $meta['track_number'] );
338
			if ( isset( $track_number[1] ) )
339
				$content .= ' ' . sprintf( __( 'Track %1$s of %2$s.' ), number_format_i18n( $track_number[0] ), number_format_i18n( $track_number[1] ) );
340
			else
341
				$content .= ' ' . sprintf( __( 'Track %1$s.' ), number_format_i18n( $track_number[0] ) );
342
		}
343
344
		if ( ! empty( $meta['genre'] ) )
345
			$content .= ' ' . sprintf( __( 'Genre: %s.' ), $meta['genre'] );
346
347
	// Use image exif/iptc data for title and caption defaults if possible.
348
	} elseif ( 0 === strpos( $type, 'image/' ) && $image_meta = @wp_read_image_metadata( $file ) ) {
349 View Code Duplication
		if ( trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) {
350
			$title = $image_meta['title'];
351
		}
352
353
		if ( trim( $image_meta['caption'] ) ) {
354
			$excerpt = $image_meta['caption'];
355
		}
356
	}
357
358
	// Construct the attachment array
359
	$attachment = array_merge( array(
360
		'post_mime_type' => $type,
361
		'guid' => $url,
362
		'post_parent' => $post_id,
363
		'post_title' => $title,
364
		'post_content' => $content,
365
		'post_excerpt' => $excerpt,
366
	), $post_data );
367
368
	// This should never be set as it would then overwrite an existing attachment.
369
	unset( $attachment['ID'] );
370
371
	// Save the data
372
	$id = wp_insert_attachment($attachment, $file, $post_id);
373
	if ( !is_wp_error($id) ) {
374
		wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
375
	}
376
377
	return $id;
378
379
}
380
381
/**
382
 * Handles a side-loaded file in the same way as an uploaded file is handled by media_handle_upload().
383
 *
384
 * @since 2.6.0
385
 *
386
 * @param array  $file_array Array similar to a `$_FILES` upload array.
387
 * @param int    $post_id    The post ID the media is associated with.
388
 * @param string $desc       Optional. Description of the side-loaded file. Default null.
389
 * @param array  $post_data  Optional. Post data to override. Default empty array.
390
 * @return int|object The ID of the attachment or a WP_Error on failure.
391
 */
392
function media_handle_sideload( $file_array, $post_id, $desc = null, $post_data = array() ) {
393
	$overrides = array('test_form'=>false);
394
395
	$time = current_time( 'mysql' );
396 View Code Duplication
	if ( $post = get_post( $post_id ) ) {
397
		if ( substr( $post->post_date, 0, 4 ) > 0 )
398
			$time = $post->post_date;
399
	}
400
401
	$file = wp_handle_sideload( $file_array, $overrides, $time );
402
	if ( isset($file['error']) )
403
		return new WP_Error( 'upload_error', $file['error'] );
404
405
	$url = $file['url'];
406
	$type = $file['type'];
407
	$file = $file['file'];
408
	$title = preg_replace('/\.[^.]+$/', '', basename($file));
409
	$content = '';
410
411
	// Use image exif/iptc data for title and caption defaults if possible.
412
	if ( $image_meta = @wp_read_image_metadata($file) ) {
413 View Code Duplication
		if ( trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) )
414
			$title = $image_meta['title'];
415
		if ( trim( $image_meta['caption'] ) )
416
			$content = $image_meta['caption'];
417
	}
418
419
	if ( isset( $desc ) )
420
		$title = $desc;
421
422
	// Construct the attachment array.
423
	$attachment = array_merge( array(
424
		'post_mime_type' => $type,
425
		'guid' => $url,
426
		'post_parent' => $post_id,
427
		'post_title' => $title,
428
		'post_content' => $content,
429
	), $post_data );
430
431
	// This should never be set as it would then overwrite an existing attachment.
432
	unset( $attachment['ID'] );
433
434
	// Save the attachment metadata
435
	$id = wp_insert_attachment($attachment, $file, $post_id);
436
	if ( !is_wp_error($id) )
437
		wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
438
439
	return $id;
440
}
441
442
/**
443
 * Adds the iframe to display content for the media upload page
444
 *
445
 * @since 2.5.0
446
 *
447
 * @global int $body_id
448
 *
449
 * @param string|callable $content_func
450
 */
451
function wp_iframe($content_func /* ... */) {
452
	_wp_admin_html_begin();
453
?>
454
<title><?php bloginfo('name') ?> &rsaquo; <?php _e('Uploads'); ?> &#8212; <?php _e('WordPress'); ?></title>
455
<?php
456
457
wp_enqueue_style( 'colors' );
458
// Check callback name for 'media'
459
if ( ( is_array( $content_func ) && ! empty( $content_func[1] ) && 0 === strpos( (string) $content_func[1], 'media' ) )
460
	|| ( ! is_array( $content_func ) && 0 === strpos( $content_func, 'media' ) ) )
461
	wp_enqueue_style( 'deprecated-media' );
462
wp_enqueue_style( 'ie' );
463
?>
464
<script type="text/javascript">
465
addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
466
var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>', pagenow = 'media-upload-popup', adminpage = 'media-upload-popup',
467
isRtl = <?php echo (int) is_rtl(); ?>;
468
</script>
469
<?php
470
	/** This action is documented in wp-admin/admin-header.php */
471
	do_action( 'admin_enqueue_scripts', 'media-upload-popup' );
472
473
	/**
474
	 * Fires when admin styles enqueued for the legacy (pre-3.5.0) media upload popup are printed.
475
	 *
476
	 * @since 2.9.0
477
	 */
478
	do_action( 'admin_print_styles-media-upload-popup' );
479
480
	/** This action is documented in wp-admin/admin-header.php */
481
	do_action( 'admin_print_styles' );
482
483
	/**
484
	 * Fires when admin scripts enqueued for the legacy (pre-3.5.0) media upload popup are printed.
485
	 *
486
	 * @since 2.9.0
487
	 */
488
	do_action( 'admin_print_scripts-media-upload-popup' );
489
490
	/** This action is documented in wp-admin/admin-header.php */
491
	do_action( 'admin_print_scripts' );
492
493
	/**
494
	 * Fires when scripts enqueued for the admin header for the legacy (pre-3.5.0)
495
	 * media upload popup are printed.
496
	 *
497
	 * @since 2.9.0
498
	 */
499
	do_action( 'admin_head-media-upload-popup' );
500
501
	/** This action is documented in wp-admin/admin-header.php */
502
	do_action( 'admin_head' );
503
504
if ( is_string( $content_func ) ) {
505
	/**
506
	 * Fires in the admin header for each specific form tab in the legacy
507
	 * (pre-3.5.0) media upload popup.
508
	 *
509
	 * The dynamic portion of the hook, `$content_func`, refers to the form
510
	 * callback for the media upload type. Possible values include
511
	 * 'media_upload_type_form', 'media_upload_type_url_form', and
512
	 * 'media_upload_library_form'.
513
	 *
514
	 * @since 2.5.0
515
	 */
516
	do_action( "admin_head_{$content_func}" );
517
}
518
?>
519
</head>
520
<body<?php if ( isset($GLOBALS['body_id']) ) echo ' id="' . $GLOBALS['body_id'] . '"'; ?> class="wp-core-ui no-js">
521
<script type="text/javascript">
522
document.body.className = document.body.className.replace('no-js', 'js');
523
</script>
524
<?php
525
	$args = func_get_args();
526
	$args = array_slice($args, 1);
527
	call_user_func_array($content_func, $args);
528
529
	/** This action is documented in wp-admin/admin-footer.php */
530
	do_action( 'admin_print_footer_scripts' );
531
?>
532
<script type="text/javascript">if(typeof wpOnload=='function')wpOnload();</script>
533
</body>
534
</html>
535
<?php
536
}
537
538
/**
539
 * Adds the media button to the editor
540
 *
541
 * @since 2.5.0
542
 *
543
 * @global int $post_ID
544
 *
545
 * @staticvar int $instance
546
 *
547
 * @param string $editor_id
548
 */
549
function media_buttons($editor_id = 'content') {
550
	static $instance = 0;
551
	$instance++;
552
553
	$post = get_post();
554
	if ( ! $post && ! empty( $GLOBALS['post_ID'] ) )
555
		$post = $GLOBALS['post_ID'];
556
557
	wp_enqueue_media( array(
558
		'post' => $post
559
	) );
560
561
	$img = '<span class="wp-media-buttons-icon"></span> ';
562
563
	$id_attribute = $instance === 1 ? ' id="insert-media-button"' : '';
564
	printf( '<button type="button"%s class="button insert-media add_media" data-editor="%s">%s</button>',
565
		$id_attribute,
566
		esc_attr( $editor_id ),
567
		$img . __( 'Add Media' )
568
	);
569
	/**
570
	 * Filters the legacy (pre-3.5.0) media buttons.
571
	 *
572
	 * Use {@see 'media_buttons'} action instead.
573
	 *
574
	 * @since 2.5.0
575
	 * @deprecated 3.5.0 Use {@see 'media_buttons'} action instead.
576
	 *
577
	 * @param string $string Media buttons context. Default empty.
578
	 */
579
	$legacy_filter = apply_filters( 'media_buttons_context', '' );
580
581
	if ( $legacy_filter ) {
582
		// #WP22559. Close <a> if a plugin started by closing <a> to open their own <a> tag.
583
		if ( 0 === stripos( trim( $legacy_filter ), '</a>' ) )
584
			$legacy_filter .= '</a>';
585
		echo $legacy_filter;
586
	}
587
}
588
589
/**
590
 *
591
 * @global int $post_ID
592
 * @param string $type
593
 * @param int $post_id
594
 * @param string $tab
595
 * @return string
596
 */
597
function get_upload_iframe_src( $type = null, $post_id = null, $tab = null ) {
598
	global $post_ID;
599
600
	if ( empty( $post_id ) )
601
		$post_id = $post_ID;
602
603
	$upload_iframe_src = add_query_arg( 'post_id', (int) $post_id, admin_url('media-upload.php') );
604
605
	if ( $type && 'media' != $type )
606
		$upload_iframe_src = add_query_arg('type', $type, $upload_iframe_src);
607
608
	if ( ! empty( $tab ) )
609
		$upload_iframe_src = add_query_arg('tab', $tab, $upload_iframe_src);
610
611
	/**
612
	 * Filters the upload iframe source URL for a specific media type.
613
	 *
614
	 * The dynamic portion of the hook name, `$type`, refers to the type
615
	 * of media uploaded.
616
	 *
617
	 * @since 3.0.0
618
	 *
619
	 * @param string $upload_iframe_src The upload iframe source URL by type.
620
	 */
621
	$upload_iframe_src = apply_filters( "{$type}_upload_iframe_src", $upload_iframe_src );
622
623
	return add_query_arg('TB_iframe', true, $upload_iframe_src);
624
}
625
626
/**
627
 * Handles form submissions for the legacy media uploader.
628
 *
629
 * @since 2.5.0
630
 *
631
 * @return mixed void|object WP_Error on failure
632
 */
633
function media_upload_form_handler() {
634
	check_admin_referer('media-form');
635
636
	$errors = null;
637
638
	if ( isset($_POST['send']) ) {
639
		$keys = array_keys( $_POST['send'] );
640
		$send_id = (int) reset( $keys );
641
	}
642
643
	if ( !empty($_POST['attachments']) ) foreach ( $_POST['attachments'] as $attachment_id => $attachment ) {
644
		$post = $_post = get_post($attachment_id, ARRAY_A);
645
646
		if ( !current_user_can( 'edit_post', $attachment_id ) )
647
			continue;
648
649
		if ( isset($attachment['post_content']) )
650
			$post['post_content'] = $attachment['post_content'];
651
		if ( isset($attachment['post_title']) )
652
			$post['post_title'] = $attachment['post_title'];
653
		if ( isset($attachment['post_excerpt']) )
654
			$post['post_excerpt'] = $attachment['post_excerpt'];
655
		if ( isset($attachment['menu_order']) )
656
			$post['menu_order'] = $attachment['menu_order'];
657
658
		if ( isset($send_id) && $attachment_id == $send_id ) {
659
			if ( isset($attachment['post_parent']) )
660
				$post['post_parent'] = $attachment['post_parent'];
661
		}
662
663
		/**
664
		 * Filters the attachment fields to be saved.
665
		 *
666
		 * @since 2.5.0
667
		 *
668
		 * @see wp_get_attachment_metadata()
669
		 *
670
		 * @param array $post       An array of post data.
671
		 * @param array $attachment An array of attachment metadata.
672
		 */
673
		$post = apply_filters( 'attachment_fields_to_save', $post, $attachment );
674
675 View Code Duplication
		if ( isset($attachment['image_alt']) ) {
676
			$image_alt = wp_unslash( $attachment['image_alt'] );
677
			if ( $image_alt != get_post_meta($attachment_id, '_wp_attachment_image_alt', true) ) {
678
				$image_alt = wp_strip_all_tags( $image_alt, true );
679
680
				// Update_meta expects slashed.
681
				update_post_meta( $attachment_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) );
682
			}
683
		}
684
685
		if ( isset($post['errors']) ) {
686
			$errors[$attachment_id] = $post['errors'];
687
			unset($post['errors']);
688
		}
689
690
		if ( $post != $_post )
691
			wp_update_post($post);
692
693 View Code Duplication
		foreach ( get_attachment_taxonomies($post) as $t ) {
694
			if ( isset($attachment[$t]) )
695
				wp_set_object_terms($attachment_id, array_map('trim', preg_split('/,+/', $attachment[$t])), $t, false);
696
		}
697
	}
698
699
	if ( isset($_POST['insert-gallery']) || isset($_POST['update-gallery']) ) { ?>
700
		<script type="text/javascript">
701
		var win = window.dialogArguments || opener || parent || top;
702
		win.tb_remove();
703
		</script>
704
		<?php
705
		exit;
706
	}
707
708
	if ( isset($send_id) ) {
709
		$attachment = wp_unslash( $_POST['attachments'][$send_id] );
710
711
		$html = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
712
		if ( !empty($attachment['url']) ) {
713
			$rel = '';
714
			if ( strpos($attachment['url'], 'attachment_id') || get_attachment_link($send_id) == $attachment['url'] )
715
				$rel = " rel='attachment wp-att-" . esc_attr($send_id) . "'";
716
			$html = "<a href='{$attachment['url']}'$rel>$html</a>";
717
		}
718
719
		/**
720
		 * Filters the HTML markup for a media item sent to the editor.
721
		 *
722
		 * @since 2.5.0
723
		 *
724
		 * @see wp_get_attachment_metadata()
725
		 *
726
		 * @param string $html       HTML markup for a media item sent to the editor.
727
		 * @param int    $send_id    The first key from the $_POST['send'] data.
728
		 * @param array  $attachment Array of attachment metadata.
729
		 */
730
		$html = apply_filters( 'media_send_to_editor', $html, $send_id, $attachment );
731
		return media_send_to_editor($html);
732
	}
733
734
	return $errors;
735
}
736
737
/**
738
 * Handles the process of uploading media.
739
 *
740
 * @since 2.5.0
741
 *
742
 * @return null|string
743
 */
744
function wp_media_upload_handler() {
745
	$errors = array();
746
	$id = 0;
747
748
	if ( isset($_POST['html-upload']) && !empty($_FILES) ) {
749
		check_admin_referer('media-form');
750
		// Upload File button was clicked
751
		$id = media_handle_upload('async-upload', $_REQUEST['post_id']);
752
		unset($_FILES);
753
		if ( is_wp_error($id) ) {
754
			$errors['upload_error'] = $id;
755
			$id = false;
756
		}
757
	}
758
759
	if ( !empty($_POST['insertonlybutton']) ) {
760
		$src = $_POST['src'];
761
		if ( !empty($src) && !strpos($src, '://') )
762
			$src = "http://$src";
763
764
		if ( isset( $_POST['media_type'] ) && 'image' != $_POST['media_type'] ) {
765
			$title = esc_html( wp_unslash( $_POST['title'] ) );
766
			if ( empty( $title ) )
767
				$title = esc_html( basename( $src ) );
768
769
			if ( $title && $src )
770
				$html = "<a href='" . esc_url($src) . "'>$title</a>";
771
772
			$type = 'file';
773 View Code Duplication
			if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
774
				&& ( 'audio' == $ext_type || 'video' == $ext_type ) )
775
					$type = $ext_type;
776
777
			/**
778
			 * Filters the URL sent to the editor for a specific media type.
779
			 *
780
			 * The dynamic portion of the hook name, `$type`, refers to the type
781
			 * of media being sent.
782
			 *
783
			 * @since 3.3.0
784
			 *
785
			 * @param string $html  HTML markup sent to the editor.
786
			 * @param string $src   Media source URL.
787
			 * @param string $title Media title.
788
			 */
789
			$html = apply_filters( "{$type}_send_to_editor_url", $html, esc_url_raw( $src ), $title );
790
		} else {
791
			$align = '';
792
			$alt = esc_attr( wp_unslash( $_POST['alt'] ) );
793
			if ( isset($_POST['align']) ) {
794
				$align = esc_attr( wp_unslash( $_POST['align'] ) );
795
				$class = " class='align$align'";
796
			}
797
			if ( !empty($src) )
798
				$html = "<img src='" . esc_url($src) . "' alt='$alt'$class />";
799
800
			/**
801
			 * Filters the image URL sent to the editor.
802
			 *
803
			 * @since 2.8.0
804
			 *
805
			 * @param string $html  HTML markup sent to the editor for an image.
806
			 * @param string $src   Image source URL.
807
			 * @param string $alt   Image alternate, or alt, text.
808
			 * @param string $align The image alignment. Default 'alignnone'. Possible values include
809
			 *                      'alignleft', 'aligncenter', 'alignright', 'alignnone'.
810
			 */
811
			$html = apply_filters( 'image_send_to_editor_url', $html, esc_url_raw( $src ), $alt, $align );
812
		}
813
814
		return media_send_to_editor($html);
815
	}
816
817
	if ( isset( $_POST['save'] ) ) {
818
		$errors['upload_notice'] = __('Saved.');
819
		wp_enqueue_script( 'admin-gallery' );
820
 		return wp_iframe( 'media_upload_gallery_form', $errors );
821
822
	} elseif ( ! empty( $_POST ) ) {
823
		$return = media_upload_form_handler();
824
825
		if ( is_string($return) )
826
			return $return;
827
		if ( is_array($return) )
828
			$errors = $return;
829
	}
830
831
	if ( isset($_GET['tab']) && $_GET['tab'] == 'type_url' ) {
832
		$type = 'image';
833
		if ( isset( $_GET['type'] ) && in_array( $_GET['type'], array( 'video', 'audio', 'file' ) ) )
834
			$type = $_GET['type'];
835
		return wp_iframe( 'media_upload_type_url_form', $type, $errors, $id );
836
	}
837
838
	return wp_iframe( 'media_upload_type_form', 'image', $errors, $id );
839
}
840
841
/**
842
 * Downloads an image from the specified URL and attaches it to a post.
843
 *
844
 * @since 2.6.0
845
 * @since 4.2.0 Introduced the `$return` parameter.
846
 *
847
 * @param string $file    The URL of the image to download.
848
 * @param int    $post_id The post ID the media is to be associated with.
849
 * @param string $desc    Optional. Description of the image.
850
 * @param string $return  Optional. Accepts 'html' (image tag html) or 'src' (URL). Default 'html'.
851
 * @return string|WP_Error Populated HTML img tag on success, WP_Error object otherwise.
852
 */
853
function media_sideload_image( $file, $post_id, $desc = null, $return = 'html' ) {
854
	if ( ! empty( $file ) ) {
855
856
		// Set variables for storage, fix file filename for query strings.
857
		preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
858
		if ( ! $matches ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $matches of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
859
			return new WP_Error( 'image_sideload_failed', __( 'Invalid image URL' ) );
860
		}
861
862
		$file_array = array();
863
		$file_array['name'] = basename( $matches[0] );
864
865
		// Download file to temp location.
866
		$file_array['tmp_name'] = download_url( $file );
867
868
		// If error storing temporarily, return the error.
869
		if ( is_wp_error( $file_array['tmp_name'] ) ) {
870
			return $file_array['tmp_name'];
871
		}
872
873
		// Do the validation and storage stuff.
874
		$id = media_handle_sideload( $file_array, $post_id, $desc );
875
876
		// If error storing permanently, unlink.
877
		if ( is_wp_error( $id ) ) {
878
			@unlink( $file_array['tmp_name'] );
879
			return $id;
880
		}
881
882
		$src = wp_get_attachment_url( $id );
883
	}
884
885
	// Finally, check to make sure the file has been saved, then return the HTML.
886
	if ( ! empty( $src ) ) {
887
		if ( $return === 'src' ) {
888
			return $src;
889
		}
890
891
		$alt = isset( $desc ) ? esc_attr( $desc ) : '';
892
		$html = "<img src='$src' alt='$alt' />";
893
		return $html;
894
	} else {
895
		return new WP_Error( 'image_sideload_failed' );
896
	}
897
}
898
899
/**
900
 * Retrieves the legacy media uploader form in an iframe.
901
 *
902
 * @since 2.5.0
903
 *
904
 * @return string|null
905
 */
906 View Code Duplication
function media_upload_gallery() {
907
	$errors = array();
908
909
	if ( !empty($_POST) ) {
910
		$return = media_upload_form_handler();
911
912
		if ( is_string($return) )
913
			return $return;
914
		if ( is_array($return) )
915
			$errors = $return;
916
	}
917
918
	wp_enqueue_script('admin-gallery');
919
	return wp_iframe( 'media_upload_gallery_form', $errors );
920
}
921
922
/**
923
 * Retrieves the legacy media library form in an iframe.
924
 *
925
 * @since 2.5.0
926
 *
927
 * @return string|null
928
 */
929 View Code Duplication
function media_upload_library() {
930
	$errors = array();
931
	if ( !empty($_POST) ) {
932
		$return = media_upload_form_handler();
933
934
		if ( is_string($return) )
935
			return $return;
936
		if ( is_array($return) )
937
			$errors = $return;
938
	}
939
940
	return wp_iframe( 'media_upload_library_form', $errors );
941
}
942
943
/**
944
 * Retrieve HTML for the image alignment radio buttons with the specified one checked.
945
 *
946
 * @since 2.7.0
947
 *
948
 * @param WP_Post $post
949
 * @param string $checked
950
 * @return string
951
 */
952
function image_align_input_fields( $post, $checked = '' ) {
953
954
	if ( empty($checked) )
955
		$checked = get_user_setting('align', 'none');
956
957
	$alignments = array('none' => __('None'), 'left' => __('Left'), 'center' => __('Center'), 'right' => __('Right'));
958
	if ( !array_key_exists( (string) $checked, $alignments ) )
959
		$checked = 'none';
960
961
	$out = array();
962
	foreach ( $alignments as $name => $label ) {
963
		$name = esc_attr($name);
964
		$out[] = "<input type='radio' name='attachments[{$post->ID}][align]' id='image-align-{$name}-{$post->ID}' value='$name'".
965
			( $checked == $name ? " checked='checked'" : "" ) .
966
			" /><label for='image-align-{$name}-{$post->ID}' class='align image-align-{$name}-label'>$label</label>";
967
	}
968
	return join("\n", $out);
969
}
970
971
/**
972
 * Retrieve HTML for the size radio buttons with the specified one checked.
973
 *
974
 * @since 2.7.0
975
 *
976
 * @param WP_Post $post
977
 * @param bool|string $check
978
 * @return array
979
 */
980
function image_size_input_fields( $post, $check = '' ) {
981
	/**
982
	 * Filters the names and labels of the default image sizes.
983
	 *
984
	 * @since 3.3.0
985
	 *
986
	 * @param array $size_names Array of image sizes and their names. Default values
987
	 *                          include 'Thumbnail', 'Medium', 'Large', 'Full Size'.
988
	 */
989
	$size_names = apply_filters( 'image_size_names_choose', array(
990
		'thumbnail' => __( 'Thumbnail' ),
991
		'medium'    => __( 'Medium' ),
992
		'large'     => __( 'Large' ),
993
		'full'      => __( 'Full Size' )
994
	) );
995
996
	if ( empty( $check ) ) {
997
		$check = get_user_setting('imgsize', 'medium');
998
	}
999
	$out = array();
1000
1001
	foreach ( $size_names as $size => $label ) {
1002
		$downsize = image_downsize( $post->ID, $size );
1003
		$checked = '';
1004
1005
		// Is this size selectable?
1006
		$enabled = ( $downsize[3] || 'full' == $size );
1007
		$css_id = "image-size-{$size}-{$post->ID}";
1008
1009
		// If this size is the default but that's not available, don't select it.
1010
		if ( $size == $check ) {
1011
			if ( $enabled ) {
1012
				$checked = " checked='checked'";
1013
			} else {
1014
				$check = '';
1015
			}
1016
		} elseif ( ! $check && $enabled && 'thumbnail' != $size ) {
1017
			/*
1018
			 * If $check is not enabled, default to the first available size
1019
			 * that's bigger than a thumbnail.
1020
			 */
1021
			$check = $size;
1022
			$checked = " checked='checked'";
1023
		}
1024
1025
		$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 />";
1026
1027
		$html .= "<label for='{$css_id}'>$label</label>";
1028
1029
		// Only show the dimensions if that choice is available.
1030
		if ( $enabled ) {
1031
			$html .= " <label for='{$css_id}' class='help'>" . sprintf( "(%d&nbsp;&times;&nbsp;%d)", $downsize[1], $downsize[2] ). "</label>";
1032
		}
1033
		$html .= '</div>';
1034
1035
		$out[] = $html;
1036
	}
1037
1038
	return array(
1039
		'label' => __( 'Size' ),
1040
		'input' => 'html',
1041
		'html'  => join( "\n", $out ),
1042
	);
1043
}
1044
1045
/**
1046
 * Retrieve HTML for the Link URL buttons with the default link type as specified.
1047
 *
1048
 * @since 2.7.0
1049
 *
1050
 * @param WP_Post $post
1051
 * @param string $url_type
1052
 * @return string
1053
 */
1054
function image_link_input_fields($post, $url_type = '') {
1055
1056
	$file = wp_get_attachment_url($post->ID);
1057
	$link = get_attachment_link($post->ID);
1058
1059
	if ( empty($url_type) )
1060
		$url_type = get_user_setting('urlbutton', 'post');
1061
1062
	$url = '';
1063
	if ( $url_type == 'file' )
1064
		$url = $file;
1065
	elseif ( $url_type == 'post' )
1066
		$url = $link;
1067
1068
	return "
1069
	<input type='text' class='text urlfield' name='attachments[$post->ID][url]' value='" . esc_attr($url) . "' /><br />
1070
	<button type='button' class='button urlnone' data-link-url=''>" . __('None') . "</button>
1071
	<button type='button' class='button urlfile' data-link-url='" . esc_attr($file) . "'>" . __('File URL') . "</button>
1072
	<button type='button' class='button urlpost' data-link-url='" . esc_attr($link) . "'>" . __('Attachment Post URL') . "</button>
1073
";
1074
}
1075
1076
/**
1077
 * Output a textarea element for inputting an attachment caption.
1078
 *
1079
 * @since 3.4.0
1080
 *
1081
 * @param WP_Post $edit_post Attachment WP_Post object.
1082
 * @return string HTML markup for the textarea element.
1083
 */
1084
function wp_caption_input_textarea($edit_post) {
1085
	// Post data is already escaped.
1086
	$name = "attachments[{$edit_post->ID}][post_excerpt]";
1087
1088
	return '<textarea name="' . $name . '" id="' . $name . '">' . $edit_post->post_excerpt . '</textarea>';
1089
}
1090
1091
/**
1092
 * Retrieves the image attachment fields to edit form fields.
1093
 *
1094
 * @since 2.5.0
1095
 *
1096
 * @param array $form_fields
1097
 * @param object $post
1098
 * @return array
1099
 */
1100
function image_attachment_fields_to_edit($form_fields, $post) {
1101
	return $form_fields;
1102
}
1103
1104
/**
1105
 * Retrieves the single non-image attachment fields to edit form fields.
1106
 *
1107
 * @since 2.5.0
1108
 *
1109
 * @param array   $form_fields An array of attachment form fields.
1110
 * @param WP_Post $post        The WP_Post attachment object.
1111
 * @return array Filtered attachment form fields.
1112
 */
1113
function media_single_attachment_fields_to_edit( $form_fields, $post ) {
1114
	unset($form_fields['url'], $form_fields['align'], $form_fields['image-size']);
1115
	return $form_fields;
1116
}
1117
1118
/**
1119
 * Retrieves the post non-image attachment fields to edito form fields.
1120
 *
1121
 * @since 2.8.0
1122
 *
1123
 * @param array   $form_fields An array of attachment form fields.
1124
 * @param WP_Post $post        The WP_Post attachment object.
1125
 * @return array Filtered attachment form fields.
1126
 */
1127
function media_post_single_attachment_fields_to_edit( $form_fields, $post ) {
1128
	unset($form_fields['image_url']);
1129
	return $form_fields;
1130
}
1131
1132
/**
1133
 * Filters input from media_upload_form_handler() and assigns a default
1134
 * post_title from the file name if none supplied.
1135
 *
1136
 * Illustrates the use of the {@see 'attachment_fields_to_save'} filter
1137
 * which can be used to add default values to any field before saving to DB.
1138
 *
1139
 * @since 2.5.0
1140
 *
1141
 * @param array $post       The WP_Post attachment object converted to an array.
1142
 * @param array $attachment An array of attachment metadata.
1143
 * @return array Filtered attachment post object.
1144
 */
1145
function image_attachment_fields_to_save( $post, $attachment ) {
1146
	if ( substr( $post['post_mime_type'], 0, 5 ) == 'image' ) {
1147
		if ( strlen( trim( $post['post_title'] ) ) == 0 ) {
1148
			$attachment_url = ( isset( $post['attachment_url'] ) ) ? $post['attachment_url'] : $post['guid'];
1149
			$post['post_title'] = preg_replace( '/\.\w+$/', '', wp_basename( $attachment_url ) );
1150
			$post['errors']['post_title']['errors'][] = __( 'Empty Title filled from filename.' );
1151
		}
1152
	}
1153
1154
	return $post;
1155
}
1156
1157
/**
1158
 * Retrieves the media element HTML to send to the editor.
1159
 *
1160
 * @since 2.5.0
1161
 *
1162
 * @param string $html
1163
 * @param integer $attachment_id
1164
 * @param array $attachment
1165
 * @return string
1166
 */
1167
function image_media_send_to_editor($html, $attachment_id, $attachment) {
1168
	$post = get_post($attachment_id);
1169
	if ( substr($post->post_mime_type, 0, 5) == 'image' ) {
1170
		$url = $attachment['url'];
1171
		$align = !empty($attachment['align']) ? $attachment['align'] : 'none';
1172
		$size = !empty($attachment['image-size']) ? $attachment['image-size'] : 'medium';
1173
		$alt = !empty($attachment['image_alt']) ? $attachment['image_alt'] : '';
1174
		$rel = ( strpos( $url, 'attachment_id') || $url === get_attachment_link( $attachment_id ) );
1175
1176
		return get_image_send_to_editor($attachment_id, $attachment['post_excerpt'], $attachment['post_title'], $align, $url, $rel, $size, $alt);
1177
	}
1178
1179
	return $html;
1180
}
1181
1182
/**
1183
 * Retrieves the attachment fields to edit form fields.
1184
 *
1185
 * @since 2.5.0
1186
 *
1187
 * @param WP_Post $post
1188
 * @param array $errors
1189
 * @return array
1190
 */
1191
function get_attachment_fields_to_edit($post, $errors = null) {
1192
	if ( is_int($post) )
1193
		$post = get_post($post);
1194
	if ( is_array($post) )
1195
		$post = new WP_Post( (object) $post );
1196
1197
	$image_url = wp_get_attachment_url($post->ID);
1198
1199
	$edit_post = sanitize_post($post, 'edit');
1200
1201
	$form_fields = array(
1202
		'post_title'   => array(
1203
			'label'      => __('Title'),
1204
			'value'      => $edit_post->post_title
1205
		),
1206
		'image_alt'   => array(),
1207
		'post_excerpt' => array(
1208
			'label'      => __('Caption'),
1209
			'input'      => 'html',
1210
			'html'       => wp_caption_input_textarea($edit_post)
1211
		),
1212
		'post_content' => array(
1213
			'label'      => __('Description'),
1214
			'value'      => $edit_post->post_content,
1215
			'input'      => 'textarea'
1216
		),
1217
		'url'          => array(
1218
			'label'      => __('Link URL'),
1219
			'input'      => 'html',
1220
			'html'       => image_link_input_fields($post, get_option('image_default_link_type')),
1221
			'helps'      => __('Enter a link URL or click above for presets.')
1222
		),
1223
		'menu_order'   => array(
1224
			'label'      => __('Order'),
1225
			'value'      => $edit_post->menu_order
1226
		),
1227
		'image_url'	=> array(
1228
			'label'      => __('File URL'),
1229
			'input'      => 'html',
1230
			'html'       => "<input type='text' class='text urlfield' readonly='readonly' name='attachments[$post->ID][url]' value='" . esc_attr($image_url) . "' /><br />",
1231
			'value'      => wp_get_attachment_url($post->ID),
1232
			'helps'      => __('Location of the uploaded file.')
1233
		)
1234
	);
1235
1236 View Code Duplication
	foreach ( get_attachment_taxonomies($post) as $taxonomy ) {
1237
		$t = (array) get_taxonomy($taxonomy);
1238
		if ( ! $t['public'] || ! $t['show_ui'] )
1239
			continue;
1240
		if ( empty($t['label']) )
1241
			$t['label'] = $taxonomy;
1242
		if ( empty($t['args']) )
1243
			$t['args'] = array();
1244
1245
		$terms = get_object_term_cache($post->ID, $taxonomy);
1246
		if ( false === $terms )
1247
			$terms = wp_get_object_terms($post->ID, $taxonomy, $t['args']);
1248
1249
		$values = array();
1250
1251
		foreach ( $terms as $term )
1252
			$values[] = $term->slug;
1253
		$t['value'] = join(', ', $values);
1254
1255
		$form_fields[$taxonomy] = $t;
1256
	}
1257
1258
	// Merge default fields with their errors, so any key passed with the error (e.g. 'error', 'helps', 'value') will replace the default
1259
	// The recursive merge is easily traversed with array casting: foreach ( (array) $things as $thing )
1260
	$form_fields = array_merge_recursive($form_fields, (array) $errors);
1261
1262
	// This was formerly in image_attachment_fields_to_edit().
1263
	if ( substr($post->post_mime_type, 0, 5) == 'image' ) {
1264
		$alt = get_post_meta($post->ID, '_wp_attachment_image_alt', true);
1265
		if ( empty($alt) )
1266
			$alt = '';
1267
1268
		$form_fields['post_title']['required'] = true;
1269
1270
		$form_fields['image_alt'] = array(
1271
			'value' => $alt,
1272
			'label' => __('Alternative Text'),
1273
			'helps' => __('Alt text for the image, e.g. &#8220;The Mona Lisa&#8221;')
1274
		);
1275
1276
		$form_fields['align'] = array(
1277
			'label' => __('Alignment'),
1278
			'input' => 'html',
1279
			'html'  => image_align_input_fields($post, get_option('image_default_align')),
1280
		);
1281
1282
		$form_fields['image-size'] = image_size_input_fields( $post, get_option('image_default_size', 'medium') );
1283
1284
	} else {
1285
		unset( $form_fields['image_alt'] );
1286
	}
1287
1288
	/**
1289
	 * Filters the attachment fields to edit.
1290
	 *
1291
	 * @since 2.5.0
1292
	 *
1293
	 * @param array   $form_fields An array of attachment form fields.
1294
	 * @param WP_Post $post        The WP_Post attachment object.
1295
	 */
1296
	$form_fields = apply_filters( 'attachment_fields_to_edit', $form_fields, $post );
1297
1298
	return $form_fields;
1299
}
1300
1301
/**
1302
 * Retrieve HTML for media items of post gallery.
1303
 *
1304
 * The HTML markup retrieved will be created for the progress of SWF Upload
1305
 * component. Will also create link for showing and hiding the form to modify
1306
 * the image attachment.
1307
 *
1308
 * @since 2.5.0
1309
 *
1310
 * @global WP_Query $wp_the_query
1311
 *
1312
 * @param int $post_id Optional. Post ID.
1313
 * @param array $errors Errors for attachment, if any.
1314
 * @return string
1315
 */
1316
function get_media_items( $post_id, $errors ) {
1317
	$attachments = array();
1318
	if ( $post_id ) {
1319
		$post = get_post($post_id);
1320
		if ( $post && $post->post_type == 'attachment' )
1321
			$attachments = array($post->ID => $post);
1322
		else
1323
			$attachments = get_children( array( 'post_parent' => $post_id, 'post_type' => 'attachment', 'orderby' => 'menu_order ASC, ID', 'order' => 'DESC') );
1324
	} else {
1325
		if ( is_array($GLOBALS['wp_the_query']->posts) )
1326
			foreach ( $GLOBALS['wp_the_query']->posts as $attachment )
1327
				$attachments[$attachment->ID] = $attachment;
1328
	}
1329
1330
	$output = '';
1331
	foreach ( (array) $attachments as $id => $attachment ) {
1332
		if ( $attachment->post_status == 'trash' )
1333
			continue;
1334
		if ( $item = get_media_item( $id, array( 'errors' => isset($errors[$id]) ? $errors[$id] : null) ) )
1335
			$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>";
1336
	}
1337
1338
	return $output;
1339
}
1340
1341
/**
1342
 * Retrieve HTML form for modifying the image attachment.
1343
 *
1344
 * @since 2.5.0
1345
 *
1346
 * @global string $redir_tab
1347
 *
1348
 * @param int $attachment_id Attachment ID for modification.
1349
 * @param string|array $args Optional. Override defaults.
1350
 * @return string HTML form for attachment.
1351
 */
1352
function get_media_item( $attachment_id, $args = null ) {
1353
	global $redir_tab;
1354
1355
	if ( ( $attachment_id = intval( $attachment_id ) ) && $thumb_url = wp_get_attachment_image_src( $attachment_id, 'thumbnail', true ) )
1356
		$thumb_url = $thumb_url[0];
1357
	else
1358
		$thumb_url = false;
1359
1360
	$post = get_post( $attachment_id );
1361
	$current_post_id = !empty( $_GET['post_id'] ) ? (int) $_GET['post_id'] : 0;
1362
1363
	$default_args = array(
1364
		'errors' => null,
1365
		'send' => $current_post_id ? post_type_supports( get_post_type( $current_post_id ), 'editor' ) : true,
1366
		'delete' => true,
1367
		'toggle' => true,
1368
		'show_title' => true
1369
	);
1370
	$args = wp_parse_args( $args, $default_args );
1371
1372
	/**
1373
	 * Filters the arguments used to retrieve an image for the edit image form.
1374
	 *
1375
	 * @since 3.1.0
1376
	 *
1377
	 * @see get_media_item
1378
	 *
1379
	 * @param array $args An array of arguments.
1380
	 */
1381
	$r = apply_filters( 'get_media_item_args', $args );
1382
1383
	$toggle_on  = __( 'Show' );
1384
	$toggle_off = __( 'Hide' );
1385
1386
	$file = get_attached_file( $post->ID );
1387
	$filename = esc_html( wp_basename( $file ) );
1388
	$title = esc_attr( $post->post_title );
1389
1390
	$post_mime_types = get_post_mime_types();
1391
	$keys = array_keys( wp_match_mime_types( array_keys( $post_mime_types ), $post->post_mime_type ) );
1392
	$type = reset( $keys );
1393
	$type_html = "<input type='hidden' id='type-of-$attachment_id' value='" . esc_attr( $type ) . "' />";
1394
1395
	$form_fields = get_attachment_fields_to_edit( $post, $r['errors'] );
1396
1397
	if ( $r['toggle'] ) {
1398
		$class = empty( $r['errors'] ) ? 'startclosed' : 'startopen';
1399
		$toggle_links = "
1400
	<a class='toggle describe-toggle-on' href='#'>$toggle_on</a>
1401
	<a class='toggle describe-toggle-off' href='#'>$toggle_off</a>";
1402
	} else {
1403
		$class = '';
1404
		$toggle_links = '';
1405
	}
1406
1407
	$display_title = ( !empty( $title ) ) ? $title : $filename; // $title shouldn't ever be empty, but just in case
1408
	$display_title = $r['show_title'] ? "<div class='filename new'><span class='title'>" . wp_html_excerpt( $display_title, 60, '&hellip;' ) . "</span></div>" : '';
1409
1410
	$gallery = ( ( isset( $_REQUEST['tab'] ) && 'gallery' == $_REQUEST['tab'] ) || ( isset( $redir_tab ) && 'gallery' == $redir_tab ) );
1411
	$order = '';
1412
1413
	foreach ( $form_fields as $key => $val ) {
1414
		if ( 'menu_order' == $key ) {
1415
			if ( $gallery )
1416
				$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>";
1417
			else
1418
				$order = "<input type='hidden' name='attachments[$attachment_id][menu_order]' value='" . esc_attr( $val['value'] ) . "' />";
1419
1420
			unset( $form_fields['menu_order'] );
1421
			break;
1422
		}
1423
	}
1424
1425
	$media_dims = '';
1426
	$meta = wp_get_attachment_metadata( $post->ID );
1427 View Code Duplication
	if ( isset( $meta['width'], $meta['height'] ) )
1428
		$media_dims .= "<span id='media-dims-$post->ID'>{$meta['width']}&nbsp;&times;&nbsp;{$meta['height']}</span> ";
1429
1430
	/**
1431
	 * Filters the media metadata.
1432
	 *
1433
	 * @since 2.5.0
1434
	 *
1435
	 * @param string  $media_dims The HTML markup containing the media dimensions.
1436
	 * @param WP_Post $post       The WP_Post attachment object.
1437
	 */
1438
	$media_dims = apply_filters( 'media_meta', $media_dims, $post );
1439
1440
	$image_edit_button = '';
1441 View Code Duplication
	if ( wp_attachment_is_image( $post->ID ) && wp_image_editor_supports( array( 'mime_type' => $post->post_mime_type ) ) ) {
1442
		$nonce = wp_create_nonce( "image_editor-$post->ID" );
1443
		$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>";
1444
	}
1445
1446
	$attachment_url = get_permalink( $attachment_id );
1447
1448
	$item = "
1449
	$type_html
1450
	$toggle_links
1451
	$order
1452
	$display_title
1453
	<table class='slidetoggle describe $class'>
1454
		<thead class='media-item-info' id='media-head-$post->ID'>
1455
		<tr>
1456
			<td class='A1B1' id='thumbnail-head-$post->ID'>
1457
			<p><a href='$attachment_url' target='_blank'><img class='thumbnail' src='$thumb_url' alt='' /></a></p>
1458
			<p>$image_edit_button</p>
1459
			</td>
1460
			<td>
1461
			<p><strong>" . __('File name:') . "</strong> $filename</p>
1462
			<p><strong>" . __('File type:') . "</strong> $post->post_mime_type</p>
1463
			<p><strong>" . __('Upload date:') . "</strong> " . mysql2date( __( 'F j, Y' ), $post->post_date ). '</p>';
1464
			if ( !empty( $media_dims ) )
1465
				$item .= "<p><strong>" . __('Dimensions:') . "</strong> $media_dims</p>\n";
1466
1467
			$item .= "</td></tr>\n";
1468
1469
	$item .= "
1470
		</thead>
1471
		<tbody>
1472
		<tr><td colspan='2' class='imgedit-response' id='imgedit-response-$post->ID'></td></tr>\n
1473
		<tr><td style='display:none' colspan='2' class='image-editor' id='image-editor-$post->ID'></td></tr>\n
1474
		<tr><td colspan='2'><p class='media-types media-types-required-info'>" . sprintf( __( 'Required fields are marked %s' ), '<span class="required">*</span>' ) . "</p></td></tr>\n";
1475
1476
	$defaults = array(
1477
		'input'      => 'text',
1478
		'required'   => false,
1479
		'value'      => '',
1480
		'extra_rows' => array(),
1481
	);
1482
1483
	if ( $r['send'] ) {
1484
		$r['send'] = get_submit_button( __( 'Insert into Post' ), 'button', "send[$attachment_id]", false );
1485
	}
1486
1487
	$delete = empty( $r['delete'] ) ? '' : $r['delete'];
1488
	if ( $delete && current_user_can( 'delete_post', $attachment_id ) ) {
1489
		if ( !EMPTY_TRASH_DAYS ) {
1490
			$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>';
1491
		} elseif ( !MEDIA_TRASH ) {
1492
			$delete = "<a href='#' class='del-link' onclick=\"document.getElementById('del_attachment_$attachment_id').style.display='block';return false;\">" . __( 'Delete' ) . "</a>
1493
			 <div id='del_attachment_$attachment_id' class='del-attachment' style='display:none;'>" .
1494
			 /* translators: %s: file name */
1495
			'<p>' . sprintf( __( 'You are about to delete %s.' ), '<strong>' . $filename . '</strong>' ) . "</p>
1496
			 <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>
1497
			 <a href='#' class='button' onclick=\"this.parentNode.style.display='none';return false;\">" . __( 'Cancel' ) . "</a>
1498
			 </div>";
1499
		} else {
1500
			$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>
1501
			<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>";
1502
		}
1503
	} else {
1504
		$delete = '';
1505
	}
1506
1507
	$thumbnail = '';
1508
	$calling_post_id = 0;
1509
	if ( isset( $_GET['post_id'] ) ) {
1510
		$calling_post_id = absint( $_GET['post_id'] );
1511
	} elseif ( isset( $_POST ) && count( $_POST ) ) {// Like for async-upload where $_GET['post_id'] isn't set
1512
		$calling_post_id = $post->post_parent;
1513
	}
1514
	if ( 'image' == $type && $calling_post_id && current_theme_supports( 'post-thumbnails', get_post_type( $calling_post_id ) )
1515
		&& post_type_supports( get_post_type( $calling_post_id ), 'thumbnail' ) && get_post_thumbnail_id( $calling_post_id ) != $attachment_id ) {
1516
1517
		$calling_post = get_post( $calling_post_id );
1518
		$calling_post_type_object = get_post_type_object( $calling_post->post_type );
1519
1520
		$ajax_nonce = wp_create_nonce( "set_post_thumbnail-$calling_post_id" );
1521
		$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>";
1522
	}
1523
1524
	if ( ( $r['send'] || $thumbnail || $delete ) && !isset( $form_fields['buttons'] ) ) {
1525
		$form_fields['buttons'] = array( 'tr' => "\t\t<tr class='submit'><td></td><td class='savesend'>" . $r['send'] . " $thumbnail $delete</td></tr>\n" );
1526
	}
1527
	$hidden_fields = array();
1528
1529
	foreach ( $form_fields as $id => $field ) {
1530
		if ( $id[0] == '_' )
1531
			continue;
1532
1533
		if ( !empty( $field['tr'] ) ) {
1534
			$item .= $field['tr'];
1535
			continue;
1536
		}
1537
1538
		$field = array_merge( $defaults, $field );
1539
		$name = "attachments[$attachment_id][$id]";
1540
1541
		if ( $field['input'] == 'hidden' ) {
1542
			$hidden_fields[$name] = $field['value'];
1543
			continue;
1544
		}
1545
1546
		$required      = $field['required'] ? '<span class="required">*</span>' : '';
1547
		$required_attr = $field['required'] ? ' required' : '';
1548
		$aria_required = $field['required'] ? " aria-required='true'" : '';
1549
		$class  = $id;
1550
		$class .= $field['required'] ? ' form-required' : '';
1551
1552
		$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'>";
1553 View Code Duplication
		if ( !empty( $field[ $field['input'] ] ) )
1554
			$item .= $field[ $field['input'] ];
1555
		elseif ( $field['input'] == 'textarea' ) {
1556
			if ( 'post_content' == $id && user_can_richedit() ) {
1557
				// Sanitize_post() skips the post_content when user_can_richedit.
1558
				$field['value'] = htmlspecialchars( $field['value'], ENT_QUOTES );
1559
			}
1560
			// Post_excerpt is already escaped by sanitize_post() in get_attachment_fields_to_edit().
1561
			$item .= "<textarea id='$name' name='$name'{$required_attr}{$aria_required}>" . $field['value'] . '</textarea>';
1562
		} else {
1563
			$item .= "<input type='text' class='text' id='$name' name='$name' value='" . esc_attr( $field['value'] ) . "'{$required_attr}{$aria_required} />";
1564
		}
1565 View Code Duplication
		if ( !empty( $field['helps'] ) )
1566
			$item .= "<p class='help'>" . join( "</p>\n<p class='help'>", array_unique( (array) $field['helps'] ) ) . '</p>';
1567
		$item .= "</td>\n\t\t</tr>\n";
1568
1569
		$extra_rows = array();
1570
1571 View Code Duplication
		if ( !empty( $field['errors'] ) )
1572
			foreach ( array_unique( (array) $field['errors'] ) as $error )
1573
				$extra_rows['error'][] = $error;
1574
1575 View Code Duplication
		if ( !empty( $field['extra_rows'] ) )
1576
			foreach ( $field['extra_rows'] as $class => $rows )
1577
				foreach ( (array) $rows as $html )
1578
					$extra_rows[$class][] = $html;
1579
1580
		foreach ( $extra_rows as $class => $rows )
1581
			foreach ( $rows as $html )
1582
				$item .= "\t\t<tr><td></td><td class='$class'>$html</td></tr>\n";
1583
	}
1584
1585
	if ( !empty( $form_fields['_final'] ) )
1586
		$item .= "\t\t<tr class='final'><td colspan='2'>{$form_fields['_final']}</td></tr>\n";
1587
	$item .= "\t</tbody>\n";
1588
	$item .= "\t</table>\n";
1589
1590
	foreach ( $hidden_fields as $name => $value )
1591
		$item .= "\t<input type='hidden' name='$name' id='$name' value='" . esc_attr( $value ) . "' />\n";
1592
1593
	if ( $post->post_parent < 1 && isset( $_REQUEST['post_id'] ) ) {
1594
		$parent = (int) $_REQUEST['post_id'];
1595
		$parent_name = "attachments[$attachment_id][post_parent]";
1596
		$item .= "\t<input type='hidden' name='$parent_name' id='$parent_name' value='$parent' />\n";
1597
	}
1598
1599
	return $item;
1600
}
1601
1602
/**
1603
 * @since 3.5.0
1604
 *
1605
 * @param int   $attachment_id
1606
 * @param array $args
1607
 * @return array
1608
 */
1609
function get_compat_media_markup( $attachment_id, $args = null ) {
1610
	$post = get_post( $attachment_id );
1611
1612
	$default_args = array(
1613
		'errors' => null,
1614
		'in_modal' => false,
1615
	);
1616
1617
	$user_can_edit = current_user_can( 'edit_post', $attachment_id );
1618
1619
	$args = wp_parse_args( $args, $default_args );
1620
1621
	/** This filter is documented in wp-admin/includes/media.php */
1622
	$args = apply_filters( 'get_media_item_args', $args );
1623
1624
	$form_fields = array();
1625
1626
	if ( $args['in_modal'] ) {
1627 View Code Duplication
		foreach ( get_attachment_taxonomies($post) as $taxonomy ) {
1628
			$t = (array) get_taxonomy($taxonomy);
1629
			if ( ! $t['public'] || ! $t['show_ui'] )
1630
				continue;
1631
			if ( empty($t['label']) )
1632
				$t['label'] = $taxonomy;
1633
			if ( empty($t['args']) )
1634
				$t['args'] = array();
1635
1636
			$terms = get_object_term_cache($post->ID, $taxonomy);
1637
			if ( false === $terms )
1638
				$terms = wp_get_object_terms($post->ID, $taxonomy, $t['args']);
1639
1640
			$values = array();
1641
1642
			foreach ( $terms as $term )
1643
				$values[] = $term->slug;
1644
			$t['value'] = join(', ', $values);
1645
			$t['taxonomy'] = true;
1646
1647
			$form_fields[$taxonomy] = $t;
1648
		}
1649
	}
1650
1651
	// Merge default fields with their errors, so any key passed with the error (e.g. 'error', 'helps', 'value') will replace the default
1652
	// The recursive merge is easily traversed with array casting: foreach ( (array) $things as $thing )
1653
	$form_fields = array_merge_recursive($form_fields, (array) $args['errors'] );
1654
1655
	/** This filter is documented in wp-admin/includes/media.php */
1656
	$form_fields = apply_filters( 'attachment_fields_to_edit', $form_fields, $post );
1657
1658
	unset( $form_fields['image-size'], $form_fields['align'], $form_fields['image_alt'],
1659
		$form_fields['post_title'], $form_fields['post_excerpt'], $form_fields['post_content'],
1660
		$form_fields['url'], $form_fields['menu_order'], $form_fields['image_url'] );
1661
1662
	/** This filter is documented in wp-admin/includes/media.php */
1663
	$media_meta = apply_filters( 'media_meta', '', $post );
1664
1665
	$defaults = array(
1666
		'input'         => 'text',
1667
		'required'      => false,
1668
		'value'         => '',
1669
		'extra_rows'    => array(),
1670
		'show_in_edit'  => true,
1671
		'show_in_modal' => true,
1672
	);
1673
1674
	$hidden_fields = array();
1675
1676
	$item = '';
1677
	foreach ( $form_fields as $id => $field ) {
1678
		if ( $id[0] == '_' )
1679
			continue;
1680
1681
		$name = "attachments[$attachment_id][$id]";
1682
		$id_attr = "attachments-$attachment_id-$id";
1683
1684
		if ( !empty( $field['tr'] ) ) {
1685
			$item .= $field['tr'];
1686
			continue;
1687
		}
1688
1689
		$field = array_merge( $defaults, $field );
1690
1691
		if ( ( ! $field['show_in_edit'] && ! $args['in_modal'] ) || ( ! $field['show_in_modal'] && $args['in_modal'] ) )
1692
			continue;
1693
1694
		if ( $field['input'] == 'hidden' ) {
1695
			$hidden_fields[$name] = $field['value'];
1696
			continue;
1697
		}
1698
1699
		$readonly      = ! $user_can_edit && ! empty( $field['taxonomy'] ) ? " readonly='readonly' " : '';
1700
		$required      = $field['required'] ? '<span class="required">*</span>' : '';
1701
		$required_attr = $field['required'] ? ' required' : '';
1702
		$aria_required = $field['required'] ? " aria-required='true'" : '';
1703
		$class  = 'compat-field-' . $id;
1704
		$class .= $field['required'] ? ' form-required' : '';
1705
1706
		$item .= "\t\t<tr class='$class'>";
1707
		$item .= "\t\t\t<th scope='row' class='label'><label for='$id_attr'><span class='alignleft'>{$field['label']}</span>$required<br class='clear' /></label>";
1708
		$item .= "</th>\n\t\t\t<td class='field'>";
1709
1710 View Code Duplication
		if ( !empty( $field[ $field['input'] ] ) )
1711
			$item .= $field[ $field['input'] ];
1712
		elseif ( $field['input'] == 'textarea' ) {
1713
			if ( 'post_content' == $id && user_can_richedit() ) {
1714
				// sanitize_post() skips the post_content when user_can_richedit.
1715
				$field['value'] = htmlspecialchars( $field['value'], ENT_QUOTES );
1716
			}
1717
			$item .= "<textarea id='$id_attr' name='$name'{$required_attr}{$aria_required}>" . $field['value'] . '</textarea>';
1718
		} else {
1719
			$item .= "<input type='text' class='text' id='$id_attr' name='$name' value='" . esc_attr( $field['value'] ) . "' $readonly{$required_attr}{$aria_required} />";
1720
		}
1721 View Code Duplication
		if ( !empty( $field['helps'] ) )
1722
			$item .= "<p class='help'>" . join( "</p>\n<p class='help'>", array_unique( (array) $field['helps'] ) ) . '</p>';
1723
		$item .= "</td>\n\t\t</tr>\n";
1724
1725
		$extra_rows = array();
1726
1727 View Code Duplication
		if ( !empty( $field['errors'] ) )
1728
			foreach ( array_unique( (array) $field['errors'] ) as $error )
1729
				$extra_rows['error'][] = $error;
1730
1731 View Code Duplication
		if ( !empty( $field['extra_rows'] ) )
1732
			foreach ( $field['extra_rows'] as $class => $rows )
1733
				foreach ( (array) $rows as $html )
1734
					$extra_rows[$class][] = $html;
1735
1736
		foreach ( $extra_rows as $class => $rows )
1737
			foreach ( $rows as $html )
1738
				$item .= "\t\t<tr><td></td><td class='$class'>$html</td></tr>\n";
1739
	}
1740
1741
	if ( !empty( $form_fields['_final'] ) )
1742
		$item .= "\t\t<tr class='final'><td colspan='2'>{$form_fields['_final']}</td></tr>\n";
1743
1744 View Code Duplication
	if ( $item ) {
1745
		$item = '<p class="media-types media-types-required-info">' .
1746
			sprintf( __( 'Required fields are marked %s' ), '<span class="required">*</span>' ) . '</p>
1747
			<table class="compat-attachment-fields">' . $item . '</table>';
1748
	}
1749
1750
	foreach ( $hidden_fields as $hidden_field => $value ) {
1751
		$item .= '<input type="hidden" name="' . esc_attr( $hidden_field ) . '" value="' . esc_attr( $value ) . '" />' . "\n";
1752
	}
1753
1754
	if ( $item )
1755
		$item = '<input type="hidden" name="attachments[' . $attachment_id . '][menu_order]" value="' . esc_attr( $post->menu_order ) . '" />' . $item;
1756
1757
	return array(
1758
		'item'   => $item,
1759
		'meta'   => $media_meta,
1760
	);
1761
}
1762
1763
/**
1764
 * Outputs the legacy media upload header.
1765
 *
1766
 * @since 2.5.0
1767
 */
1768
function media_upload_header() {
1769
	$post_id = isset( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
1770
1771
	echo '<script type="text/javascript">post_id = ' . $post_id . ';</script>';
1772
	if ( empty( $_GET['chromeless'] ) ) {
1773
		echo '<div id="media-upload-header">';
1774
		the_media_upload_tabs();
1775
		echo '</div>';
1776
	}
1777
}
1778
1779
/**
1780
 * Outputs the legacy media upload form.
1781
 *
1782
 * @since 2.5.0
1783
 *
1784
 * @global string $type
1785
 * @global string $tab
1786
 * @global bool   $is_IE
1787
 * @global bool   $is_opera
1788
 *
1789
 * @param array $errors
1790
 */
1791
function media_upload_form( $errors = null ) {
1792
	global $type, $tab, $is_IE, $is_opera;
1793
1794
	if ( ! _device_can_upload() ) {
1795
		echo '<p>' . sprintf( __('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.'), 'https://apps.wordpress.org/' ) . '</p>';
1796
		return;
1797
	}
1798
1799
	$upload_action_url = admin_url('async-upload.php');
1800
	$post_id = isset($_REQUEST['post_id']) ? intval($_REQUEST['post_id']) : 0;
1801
	$_type = isset($type) ? $type : '';
1802
	$_tab = isset($tab) ? $tab : '';
1803
1804
	$max_upload_size = wp_max_upload_size();
1805
	if ( ! $max_upload_size ) {
1806
		$max_upload_size = 0;
1807
	}
1808
?>
1809
1810
<div id="media-upload-notice"><?php
1811
1812
	if (isset($errors['upload_notice']) )
1813
		echo $errors['upload_notice'];
1814
1815
?></div>
1816
<div id="media-upload-error"><?php
1817
1818
	if (isset($errors['upload_error']) && is_wp_error($errors['upload_error']))
1819
		echo $errors['upload_error']->get_error_message();
1820
1821
?></div>
1822
<?php
1823
if ( is_multisite() && !is_upload_space_available() ) {
1824
	/**
1825
	 * Fires when an upload will exceed the defined upload space quota for a network site.
1826
	 *
1827
	 * @since 3.5.0
1828
	 */
1829
	do_action( 'upload_ui_over_quota' );
1830
	return;
1831
}
1832
1833
/**
1834
 * Fires just before the legacy (pre-3.5.0) upload interface is loaded.
1835
 *
1836
 * @since 2.6.0
1837
 */
1838
do_action( 'pre-upload-ui' );
1839
1840
$post_params = array(
1841
	"post_id" => $post_id,
1842
	"_wpnonce" => wp_create_nonce('media-form'),
1843
	"type" => $_type,
1844
	"tab" => $_tab,
1845
	"short" => "1",
1846
);
1847
1848
/**
1849
 * Filters the media upload post parameters.
1850
 *
1851
 * @since 3.1.0 As 'swfupload_post_params'
1852
 * @since 3.3.0
1853
 *
1854
 * @param array $post_params An array of media upload parameters used by Plupload.
1855
 */
1856
$post_params = apply_filters( 'upload_post_params', $post_params );
1857
1858
$plupload_init = array(
1859
	'runtimes'            => 'html5,flash,silverlight,html4',
1860
	'browse_button'       => 'plupload-browse-button',
1861
	'container'           => 'plupload-upload-ui',
1862
	'drop_element'        => 'drag-drop-area',
1863
	'file_data_name'      => 'async-upload',
1864
	'url'                 => $upload_action_url,
1865
	'flash_swf_url'       => includes_url( 'js/plupload/plupload.flash.swf' ),
1866
	'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
1867
	'filters' => array(
1868
		'max_file_size'   => $max_upload_size . 'b',
1869
	),
1870
	'multipart_params'    => $post_params,
1871
);
1872
1873
// Currently only iOS Safari supports multiple files uploading but iOS 7.x has a bug that prevents uploading of videos
1874
// when enabled. See #29602.
1875 View Code Duplication
if ( wp_is_mobile() && strpos( $_SERVER['HTTP_USER_AGENT'], 'OS 7_' ) !== false &&
1876
	strpos( $_SERVER['HTTP_USER_AGENT'], 'like Mac OS X' ) !== false ) {
1877
1878
	$plupload_init['multi_selection'] = false;
1879
}
1880
1881
/**
1882
 * Filters the default Plupload settings.
1883
 *
1884
 * @since 3.3.0
1885
 *
1886
 * @param array $plupload_init An array of default settings used by Plupload.
1887
 */
1888
$plupload_init = apply_filters( 'plupload_init', $plupload_init );
1889
1890
?>
1891
1892
<script type="text/javascript">
1893
<?php
1894
// Verify size is an int. If not return default value.
1895
$large_size_h = absint( get_option('large_size_h') );
1896
if( !$large_size_h )
1897
	$large_size_h = 1024;
1898
$large_size_w = absint( get_option('large_size_w') );
1899
if( !$large_size_w )
1900
	$large_size_w = 1024;
1901
?>
1902
var resize_height = <?php echo $large_size_h; ?>, resize_width = <?php echo $large_size_w; ?>,
1903
wpUploaderInit = <?php echo wp_json_encode( $plupload_init ); ?>;
1904
</script>
1905
1906
<div id="plupload-upload-ui" class="hide-if-no-js">
1907
<?php
1908
/**
1909
 * Fires before the upload interface loads.
1910
 *
1911
 * @since 2.6.0 As 'pre-flash-upload-ui'
1912
 * @since 3.3.0
1913
 */
1914
do_action( 'pre-plupload-upload-ui' ); ?>
1915
<div id="drag-drop-area">
1916
	<div class="drag-drop-inside">
1917
	<p class="drag-drop-info"><?php _e('Drop files here'); ?></p>
1918
	<p><?php _ex('or', 'Uploader: Drop files here - or - Select Files'); ?></p>
1919
	<p class="drag-drop-buttons"><input id="plupload-browse-button" type="button" value="<?php esc_attr_e('Select Files'); ?>" class="button" /></p>
1920
	</div>
1921
</div>
1922
<?php
1923
/**
1924
 * Fires after the upload interface loads.
1925
 *
1926
 * @since 2.6.0 As 'post-flash-upload-ui'
1927
 * @since 3.3.0
1928
 */
1929
do_action( 'post-plupload-upload-ui' ); ?>
1930
</div>
1931
1932
<div id="html-upload-ui" class="hide-if-js">
1933
	<?php
1934
	/**
1935
	 * Fires before the upload button in the media upload interface.
1936
	 *
1937
	 * @since 2.6.0
1938
	 */
1939
	do_action( 'pre-html-upload-ui' );
1940
	?>
1941
	<p id="async-upload-wrap">
1942
		<label class="screen-reader-text" for="async-upload"><?php _e('Upload'); ?></label>
1943
		<input type="file" name="async-upload" id="async-upload" />
1944
		<?php submit_button( __( 'Upload' ), 'primary', 'html-upload', false ); ?>
1945
		<a href="#" onclick="try{top.tb_remove();}catch(e){}; return false;"><?php _e('Cancel'); ?></a>
1946
	</p>
1947
	<div class="clear"></div>
1948
<?php
1949
/**
1950
 * Fires after the upload button in the media upload interface.
1951
 *
1952
 * @since 2.6.0
1953
 */
1954
do_action( 'post-html-upload-ui' );
1955
?>
1956
</div>
1957
1958
<p class="max-upload-size"><?php printf( __( 'Maximum upload file size: %s.' ), esc_html( size_format( $max_upload_size ) ) ); ?></p>
1959
<?php
1960
1961
	/**
1962
	 * Fires on the post upload UI screen.
1963
	 *
1964
	 * Legacy (pre-3.5.0) media workflow hook.
1965
	 *
1966
	 * @since 2.6.0
1967
	 */
1968
	do_action( 'post-upload-ui' );
1969
}
1970
1971
/**
1972
 * Outputs the legacy media upload form for a given media type.
1973
 *
1974
 * @since 2.5.0
1975
 *
1976
 * @param string $type
1977
 * @param object $errors
1978
 * @param integer $id
1979
 */
1980
function media_upload_type_form($type = 'file', $errors = null, $id = null) {
1981
1982
	media_upload_header();
1983
1984
	$post_id = isset( $_REQUEST['post_id'] )? intval( $_REQUEST['post_id'] ) : 0;
1985
1986
	$form_action_url = admin_url("media-upload.php?type=$type&tab=type&post_id=$post_id");
1987
1988
	/**
1989
	 * Filters the media upload form action URL.
1990
	 *
1991
	 * @since 2.6.0
1992
	 *
1993
	 * @param string $form_action_url The media upload form action URL.
1994
	 * @param string $type            The type of media. Default 'file'.
1995
	 */
1996
	$form_action_url = apply_filters( 'media_upload_form_url', $form_action_url, $type );
1997
	$form_class = 'media-upload-form type-form validate';
1998
1999
	if ( get_user_setting('uploader') )
2000
		$form_class .= ' html-uploader';
2001
?>
2002
2003
<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">
2004
<?php submit_button( '', 'hidden', 'save', false ); ?>
2005
<input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
2006
<?php wp_nonce_field('media-form'); ?>
2007
2008
<h3 class="media-title"><?php _e('Add media files from your computer'); ?></h3>
2009
2010
<?php media_upload_form( $errors ); ?>
2011
2012
<script type="text/javascript">
2013
jQuery(function($){
2014
	var preloaded = $(".media-item.preloaded");
2015
	if ( preloaded.length > 0 ) {
2016
		preloaded.each(function(){prepareMediaItem({id:this.id.replace(/[^0-9]/g, '')},'');});
2017
	}
2018
	updateMediaForm();
2019
});
2020
</script>
2021
<div id="media-items"><?php
2022
2023
if ( $id ) {
2024
	if ( !is_wp_error($id) ) {
2025
		add_filter('attachment_fields_to_edit', 'media_post_single_attachment_fields_to_edit', 10, 2);
2026
		echo get_media_items( $id, $errors );
2027
	} else {
2028
		echo '<div id="media-upload-error">'.esc_html($id->get_error_message()).'</div></div>';
2029
		exit;
2030
	}
2031
}
2032
?></div>
2033
2034
<p class="savebutton ml-submit">
2035
<?php submit_button( __( 'Save all changes' ), 'button', 'save', false ); ?>
2036
</p>
2037
</form>
2038
<?php
2039
}
2040
2041
/**
2042
 * Outputs the legacy media upload form for external media.
2043
 *
2044
 * @since 2.7.0
2045
 *
2046
 * @param string $type
2047
 * @param object $errors
2048
 * @param integer $id
2049
 */
2050
function media_upload_type_url_form($type = null, $errors = null, $id = null) {
2051
	if ( null === $type )
2052
		$type = 'image';
2053
2054
	media_upload_header();
2055
2056
	$post_id = isset( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
2057
2058
	$form_action_url = admin_url("media-upload.php?type=$type&tab=type&post_id=$post_id");
2059
	/** This filter is documented in wp-admin/includes/media.php */
2060
	$form_action_url = apply_filters( 'media_upload_form_url', $form_action_url, $type );
2061
	$form_class = 'media-upload-form type-form validate';
2062
2063
	if ( get_user_setting('uploader') )
2064
		$form_class .= ' html-uploader';
2065
?>
2066
2067
<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">
2068
<input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
2069
<?php wp_nonce_field('media-form'); ?>
2070
2071
<h3 class="media-title"><?php _e('Insert media from another website'); ?></h3>
2072
2073
<script type="text/javascript">
2074
var addExtImage = {
2075
2076
	width : '',
2077
	height : '',
2078
	align : 'alignnone',
2079
2080
	insert : function() {
2081
		var t = this, html, f = document.forms[0], cls, title = '', alt = '', caption = '';
2082
2083
		if ( '' == f.src.value || '' == t.width )
2084
			return false;
2085
2086
		if ( f.alt.value )
2087
			alt = f.alt.value.replace(/'/g, '&#039;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
2088
2089
<?php
2090
	/** This filter is documented in wp-admin/includes/media.php */
2091
	if ( ! apply_filters( 'disable_captions', '' ) ) {
2092
		?>
2093
		if ( f.caption.value ) {
2094
			caption = f.caption.value.replace(/\r\n|\r/g, '\n');
2095
			caption = caption.replace(/<[a-zA-Z0-9]+( [^<>]+)?>/g, function(a){
2096
				return a.replace(/[\r\n\t]+/, ' ');
2097
			});
2098
2099
			caption = caption.replace(/\s*\n\s*/g, '<br />');
2100
		}
2101
<?php } ?>
2102
2103
		cls = caption ? '' : ' class="'+t.align+'"';
2104
2105
		html = '<img alt="'+alt+'" src="'+f.src.value+'"'+cls+' width="'+t.width+'" height="'+t.height+'" />';
2106
2107
		if ( f.url.value ) {
2108
			url = f.url.value.replace(/'/g, '&#039;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
2109
			html = '<a href="'+url+'">'+html+'</a>';
2110
		}
2111
2112
		if ( caption )
2113
			html = '[caption id="" align="'+t.align+'" width="'+t.width+'"]'+html+caption+'[/caption]';
2114
2115
		var win = window.dialogArguments || opener || parent || top;
2116
		win.send_to_editor(html);
2117
		return false;
2118
	},
2119
2120
	resetImageData : function() {
2121
		var t = addExtImage;
2122
2123
		t.width = t.height = '';
2124
		document.getElementById('go_button').style.color = '#bbb';
2125
		if ( ! document.forms[0].src.value )
2126
			document.getElementById('status_img').innerHTML = '';
2127
		else document.getElementById('status_img').innerHTML = '<img src="<?php echo esc_url( admin_url( 'images/no.png' ) ); ?>" alt="" />';
2128
	},
2129
2130
	updateImageData : function() {
2131
		var t = addExtImage;
2132
2133
		t.width = t.preloadImg.width;
2134
		t.height = t.preloadImg.height;
2135
		document.getElementById('go_button').style.color = '#333';
2136
		document.getElementById('status_img').innerHTML = '<img src="<?php echo esc_url( admin_url( 'images/yes.png' ) ); ?>" alt="" />';
2137
	},
2138
2139
	getImageData : function() {
2140
		if ( jQuery('table.describe').hasClass('not-image') )
2141
			return;
2142
2143
		var t = addExtImage, src = document.forms[0].src.value;
2144
2145
		if ( ! src ) {
2146
			t.resetImageData();
2147
			return false;
2148
		}
2149
2150
		document.getElementById('status_img').innerHTML = '<img src="<?php echo esc_url( admin_url( 'images/spinner-2x.gif' ) ); ?>" alt="" width="16" height="16" />';
2151
		t.preloadImg = new Image();
2152
		t.preloadImg.onload = t.updateImageData;
2153
		t.preloadImg.onerror = t.resetImageData;
2154
		t.preloadImg.src = src;
2155
	}
2156
};
2157
2158
jQuery(document).ready( function($) {
2159
	$('.media-types input').click( function() {
2160
		$('table.describe').toggleClass('not-image', $('#not-image').prop('checked') );
2161
	});
2162
});
2163
</script>
2164
2165
<div id="media-items">
2166
<div class="media-item media-blank">
2167
<?php
2168
/**
2169
 * Filters the insert media from URL form HTML.
2170
 *
2171
 * @since 3.3.0
2172
 *
2173
 * @param string $form_html The insert from URL form HTML.
2174
 */
2175
echo apply_filters( 'type_url_form_media', wp_media_insert_url_form( $type ) );
2176
?>
2177
</div>
2178
</div>
2179
</form>
2180
<?php
2181
}
2182
2183
/**
2184
 * Adds gallery form to upload iframe
2185
 *
2186
 * @since 2.5.0
2187
 *
2188
 * @global string $redir_tab
2189
 * @global string $type
2190
 * @global string $tab
2191
 *
2192
 * @param array $errors
2193
 */
2194
function media_upload_gallery_form($errors) {
2195
	global $redir_tab, $type;
2196
2197
	$redir_tab = 'gallery';
2198
	media_upload_header();
2199
2200
	$post_id = intval($_REQUEST['post_id']);
2201
	$form_action_url = admin_url("media-upload.php?type=$type&tab=gallery&post_id=$post_id");
2202
	/** This filter is documented in wp-admin/includes/media.php */
2203
	$form_action_url = apply_filters( 'media_upload_form_url', $form_action_url, $type );
2204
	$form_class = 'media-upload-form validate';
2205
2206
	if ( get_user_setting('uploader') )
2207
		$form_class .= ' html-uploader';
2208
?>
2209
2210
<script type="text/javascript">
2211
jQuery(function($){
2212
	var preloaded = $(".media-item.preloaded");
2213
	if ( preloaded.length > 0 ) {
2214
		preloaded.each(function(){prepareMediaItem({id:this.id.replace(/[^0-9]/g, '')},'');});
2215
		updateMediaForm();
2216
	}
2217
});
2218
</script>
2219
<div id="sort-buttons" class="hide-if-no-js">
2220
<span>
2221
<?php _e('All Tabs:'); ?>
2222
<a href="#" id="showall"><?php _e('Show'); ?></a>
2223
<a href="#" id="hideall" style="display:none;"><?php _e('Hide'); ?></a>
2224
</span>
2225
<?php _e('Sort Order:'); ?>
2226
<a href="#" id="asc"><?php _e('Ascending'); ?></a> |
2227
<a href="#" id="desc"><?php _e('Descending'); ?></a> |
2228
<a href="#" id="clear"><?php _ex('Clear', 'verb'); ?></a>
2229
</div>
2230
<form enctype="multipart/form-data" method="post" action="<?php echo esc_url( $form_action_url ); ?>" class="<?php echo $form_class; ?>" id="gallery-form">
2231
<?php wp_nonce_field('media-form'); ?>
2232
<?php //media_upload_form( $errors ); ?>
2233
<table class="widefat">
2234
<thead><tr>
2235
<th><?php _e('Media'); ?></th>
2236
<th class="order-head"><?php _e('Order'); ?></th>
2237
<th class="actions-head"><?php _e('Actions'); ?></th>
2238
</tr></thead>
2239
</table>
2240
<div id="media-items">
2241
<?php add_filter('attachment_fields_to_edit', 'media_post_single_attachment_fields_to_edit', 10, 2); ?>
2242
<?php echo get_media_items($post_id, $errors); ?>
2243
</div>
2244
2245
<p class="ml-submit">
2246
<?php submit_button( __( 'Save all changes' ), 'button savebutton', 'save', false, array( 'id' => 'save-all', 'style' => 'display: none;' ) ); ?>
2247
<input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
2248
<input type="hidden" name="type" value="<?php echo esc_attr( $GLOBALS['type'] ); ?>" />
2249
<input type="hidden" name="tab" value="<?php echo esc_attr( $GLOBALS['tab'] ); ?>" />
2250
</p>
2251
2252
<div id="gallery-settings" style="display:none;">
2253
<div class="title"><?php _e('Gallery Settings'); ?></div>
2254
<table id="basic" class="describe"><tbody>
2255
	<tr>
2256
	<th scope="row" class="label">
2257
		<label>
2258
		<span class="alignleft"><?php _e('Link thumbnails to:'); ?></span>
2259
		</label>
2260
	</th>
2261
	<td class="field">
2262
		<input type="radio" name="linkto" id="linkto-file" value="file" />
2263
		<label for="linkto-file" class="radio"><?php _e('Image File'); ?></label>
2264
2265
		<input type="radio" checked="checked" name="linkto" id="linkto-post" value="post" />
2266
		<label for="linkto-post" class="radio"><?php _e('Attachment Page'); ?></label>
2267
	</td>
2268
	</tr>
2269
2270
	<tr>
2271
	<th scope="row" class="label">
2272
		<label>
2273
		<span class="alignleft"><?php _e('Order images by:'); ?></span>
2274
		</label>
2275
	</th>
2276
	<td class="field">
2277
		<select id="orderby" name="orderby">
2278
			<option value="menu_order" selected="selected"><?php _e('Menu order'); ?></option>
2279
			<option value="title"><?php _e('Title'); ?></option>
2280
			<option value="post_date"><?php _e('Date/Time'); ?></option>
2281
			<option value="rand"><?php _e('Random'); ?></option>
2282
		</select>
2283
	</td>
2284
	</tr>
2285
2286
	<tr>
2287
	<th scope="row" class="label">
2288
		<label>
2289
		<span class="alignleft"><?php _e('Order:'); ?></span>
2290
		</label>
2291
	</th>
2292
	<td class="field">
2293
		<input type="radio" checked="checked" name="order" id="order-asc" value="asc" />
2294
		<label for="order-asc" class="radio"><?php _e('Ascending'); ?></label>
2295
2296
		<input type="radio" name="order" id="order-desc" value="desc" />
2297
		<label for="order-desc" class="radio"><?php _e('Descending'); ?></label>
2298
	</td>
2299
	</tr>
2300
2301
	<tr>
2302
	<th scope="row" class="label">
2303
		<label>
2304
		<span class="alignleft"><?php _e('Gallery columns:'); ?></span>
2305
		</label>
2306
	</th>
2307
	<td class="field">
2308
		<select id="columns" name="columns">
2309
			<option value="1">1</option>
2310
			<option value="2">2</option>
2311
			<option value="3" selected="selected">3</option>
2312
			<option value="4">4</option>
2313
			<option value="5">5</option>
2314
			<option value="6">6</option>
2315
			<option value="7">7</option>
2316
			<option value="8">8</option>
2317
			<option value="9">9</option>
2318
		</select>
2319
	</td>
2320
	</tr>
2321
</tbody></table>
2322
2323
<p class="ml-submit">
2324
<input type="button" class="button" style="display:none;" onMouseDown="wpgallery.update();" name="insert-gallery" id="insert-gallery" value="<?php esc_attr_e( 'Insert gallery' ); ?>" />
2325
<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' ); ?>" />
2326
</p>
2327
</div>
2328
</form>
2329
<?php
2330
}
2331
2332
/**
2333
 * Outputs the legacy media upload form for the media library.
2334
 *
2335
 * @since 2.5.0
2336
 *
2337
 * @global wpdb      $wpdb
2338
 * @global WP_Query  $wp_query
2339
 * @global WP_Locale $wp_locale
2340
 * @global string    $type
2341
 * @global string    $tab
2342
 * @global array     $post_mime_types
2343
 *
2344
 * @param array $errors
2345
 */
2346
function media_upload_library_form($errors) {
2347
	global $wpdb, $wp_query, $wp_locale, $type, $tab, $post_mime_types;
2348
2349
	media_upload_header();
2350
2351
	$post_id = isset( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
2352
2353
	$form_action_url = admin_url("media-upload.php?type=$type&tab=library&post_id=$post_id");
2354
	/** This filter is documented in wp-admin/includes/media.php */
2355
	$form_action_url = apply_filters( 'media_upload_form_url', $form_action_url, $type );
2356
	$form_class = 'media-upload-form validate';
2357
2358
	if ( get_user_setting('uploader') )
2359
		$form_class .= ' html-uploader';
2360
2361
	$q = $_GET;
2362
	$q['posts_per_page'] = 10;
2363
	$q['paged'] = isset( $q['paged'] ) ? intval( $q['paged'] ) : 0;
2364
	if ( $q['paged'] < 1 ) {
2365
		$q['paged'] = 1;
2366
	}
2367
	$q['offset'] = ( $q['paged'] - 1 ) * 10;
2368
	if ( $q['offset'] < 1 ) {
2369
		$q['offset'] = 0;
2370
	}
2371
2372
	list($post_mime_types, $avail_post_mime_types) = wp_edit_attachments_query( $q );
2373
2374
?>
2375
2376
<form id="filter" method="get">
2377
<input type="hidden" name="type" value="<?php echo esc_attr( $type ); ?>" />
2378
<input type="hidden" name="tab" value="<?php echo esc_attr( $tab ); ?>" />
2379
<input type="hidden" name="post_id" value="<?php echo (int) $post_id; ?>" />
2380
<input type="hidden" name="post_mime_type" value="<?php echo isset( $_GET['post_mime_type'] ) ? esc_attr( $_GET['post_mime_type'] ) : ''; ?>" />
2381
<input type="hidden" name="context" value="<?php echo isset( $_GET['context'] ) ? esc_attr( $_GET['context'] ) : ''; ?>" />
2382
2383
<p id="media-search" class="search-box">
2384
	<label class="screen-reader-text" for="media-search-input"><?php _e('Search Media');?>:</label>
2385
	<input type="search" id="media-search-input" name="s" value="<?php the_search_query(); ?>" />
2386
	<?php submit_button( __( 'Search Media' ), 'button', '', false ); ?>
2387
</p>
2388
2389
<ul class="subsubsub">
2390
<?php
2391
$type_links = array();
2392
$_num_posts = (array) wp_count_attachments();
2393
$matches = wp_match_mime_types(array_keys($post_mime_types), array_keys($_num_posts));
2394
foreach ( $matches as $_type => $reals )
2395
	foreach ( $reals as $real )
2396
		if ( isset($num_posts[$_type]) )
2397
			$num_posts[$_type] += $_num_posts[$real];
2398
		else
2399
			$num_posts[$_type] = $_num_posts[$real];
2400
// If available type specified by media button clicked, filter by that type
2401
if ( empty($_GET['post_mime_type']) && !empty($num_posts[$type]) ) {
2402
	$_GET['post_mime_type'] = $type;
2403
	list($post_mime_types, $avail_post_mime_types) = wp_edit_attachments_query();
2404
}
2405
if ( empty($_GET['post_mime_type']) || $_GET['post_mime_type'] == 'all' )
2406
	$class = ' class="current"';
2407
else
2408
	$class = '';
2409
$type_links[] = '<li><a href="' . esc_url(add_query_arg(array('post_mime_type'=>'all', 'paged'=>false, 'm'=>false))) . '"' . $class . '>' . __('All Types') . '</a>';
2410
foreach ( $post_mime_types as $mime_type => $label ) {
2411
	$class = '';
2412
2413
	if ( !wp_match_mime_types($mime_type, $avail_post_mime_types) )
2414
		continue;
2415
2416
	if ( isset($_GET['post_mime_type']) && wp_match_mime_types($mime_type, $_GET['post_mime_type']) )
2417
		$class = ' class="current"';
2418
2419
	$type_links[] = '<li><a href="' . esc_url(add_query_arg(array('post_mime_type'=>$mime_type, 'paged'=>false))) . '"' . $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>';
2420
}
2421
/**
2422
 * Filters the media upload mime type list items.
2423
 *
2424
 * Returned values should begin with an `<li>` tag.
2425
 *
2426
 * @since 3.1.0
2427
 *
2428
 * @param array $type_links An array of list items containing mime type link HTML.
2429
 */
2430
echo implode(' | </li>', apply_filters( 'media_upload_mime_type_links', $type_links ) ) . '</li>';
2431
unset($type_links);
2432
?>
2433
</ul>
2434
2435
<div class="tablenav">
2436
2437
<?php
2438
$page_links = paginate_links( array(
2439
	'base' => add_query_arg( 'paged', '%#%' ),
2440
	'format' => '',
2441
	'prev_text' => __('&laquo;'),
2442
	'next_text' => __('&raquo;'),
2443
	'total' => ceil($wp_query->found_posts / 10),
2444
	'current' => $q['paged'],
2445
));
2446
2447
if ( $page_links )
2448
	echo "<div class='tablenav-pages'>$page_links</div>";
2449
?>
2450
2451
<div class="alignleft actions">
2452
<?php
2453
2454
$arc_query = "SELECT DISTINCT YEAR(post_date) AS yyear, MONTH(post_date) AS mmonth FROM $wpdb->posts WHERE post_type = 'attachment' ORDER BY post_date DESC";
2455
2456
$arc_result = $wpdb->get_results( $arc_query );
2457
2458
$month_count = count($arc_result);
2459
$selected_month = isset( $_GET['m'] ) ? $_GET['m'] : 0;
2460
2461
if ( $month_count && !( 1 == $month_count && 0 == $arc_result[0]->mmonth ) ) { ?>
2462
<select name='m'>
2463
<option<?php selected( $selected_month, 0 ); ?> value='0'><?php _e( 'All dates' ); ?></option>
2464
<?php
2465
foreach ($arc_result as $arc_row) {
2466
	if ( $arc_row->yyear == 0 )
2467
		continue;
2468
	$arc_row->mmonth = zeroise( $arc_row->mmonth, 2 );
2469
2470
	if ( $arc_row->yyear . $arc_row->mmonth == $selected_month )
2471
		$default = ' selected="selected"';
2472
	else
2473
		$default = '';
2474
2475
	echo "<option$default value='" . esc_attr( $arc_row->yyear . $arc_row->mmonth ) . "'>";
2476
	echo esc_html( $wp_locale->get_month($arc_row->mmonth) . " $arc_row->yyear" );
2477
	echo "</option>\n";
2478
}
2479
?>
2480
</select>
2481
<?php } ?>
2482
2483
<?php submit_button( __( 'Filter &#187;' ), 'button', 'post-query-submit', false ); ?>
2484
2485
</div>
2486
2487
<br class="clear" />
2488
</div>
2489
</form>
2490
2491
<form enctype="multipart/form-data" method="post" action="<?php echo esc_url( $form_action_url ); ?>" class="<?php echo $form_class; ?>" id="library-form">
2492
2493
<?php wp_nonce_field('media-form'); ?>
2494
<?php //media_upload_form( $errors ); ?>
2495
2496
<script type="text/javascript">
2497
<!--
2498
jQuery(function($){
2499
	var preloaded = $(".media-item.preloaded");
2500
	if ( preloaded.length > 0 ) {
2501
		preloaded.each(function(){prepareMediaItem({id:this.id.replace(/[^0-9]/g, '')},'');});
2502
		updateMediaForm();
2503
	}
2504
});
2505
-->
2506
</script>
2507
2508
<div id="media-items">
2509
<?php add_filter('attachment_fields_to_edit', 'media_post_single_attachment_fields_to_edit', 10, 2); ?>
2510
<?php echo get_media_items(null, $errors); ?>
2511
</div>
2512
<p class="ml-submit">
2513
<?php submit_button( __( 'Save all changes' ), 'button savebutton', 'save', false ); ?>
2514
<input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
2515
</p>
2516
</form>
2517
<?php
2518
}
2519
2520
/**
2521
 * Creates the form for external url
2522
 *
2523
 * @since 2.7.0
2524
 *
2525
 * @param string $default_view
2526
 * @return string the form html
2527
 */
2528
function wp_media_insert_url_form( $default_view = 'image' ) {
2529
	/** This filter is documented in wp-admin/includes/media.php */
2530
	if ( ! apply_filters( 'disable_captions', '' ) ) {
2531
		$caption = '
2532
		<tr class="image-only">
2533
			<th scope="row" class="label">
2534
				<label for="caption"><span class="alignleft">' . __('Image Caption') . '</span></label>
2535
			</th>
2536
			<td class="field"><textarea id="caption" name="caption"></textarea></td>
2537
		</tr>
2538
';
2539
	} else {
2540
		$caption = '';
2541
	}
2542
2543
	$default_align = get_option('image_default_align');
2544
	if ( empty($default_align) )
2545
		$default_align = 'none';
2546
2547
	if ( 'image' == $default_view ) {
2548
		$view = 'image-only';
2549
		$table_class = '';
2550
	} else {
2551
		$view = $table_class = 'not-image';
2552
	}
2553
2554
	return '
2555
	<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>
2556
	<p class="media-types media-types-required-info">' . sprintf( __( 'Required fields are marked %s' ), '<span class="required">*</span>' ) . '</p>
2557
	<table class="describe ' . $table_class . '"><tbody>
2558
		<tr>
2559
			<th scope="row" class="label" style="width:130px;">
2560
				<label for="src"><span class="alignleft">' . __( 'URL' ) . '</span> <span class="required">*</span></label>
2561
				<span class="alignright" id="status_img"></span>
2562
			</th>
2563
			<td class="field"><input id="src" name="src" value="" type="text" required aria-required="true" onblur="addExtImage.getImageData()" /></td>
2564
		</tr>
2565
2566
		<tr>
2567
			<th scope="row" class="label">
2568
				<label for="title"><span class="alignleft">' . __( 'Title' ) . '</span> <span class="required">*</span></label>
2569
			</th>
2570
			<td class="field"><input id="title" name="title" value="" type="text" required aria-required="true" /></td>
2571
		</tr>
2572
2573
		<tr class="not-image"><td></td><td><p class="help">' . __('Link text, e.g. &#8220;Ransom Demands (PDF)&#8221;') . '</p></td></tr>
2574
2575
		<tr class="image-only">
2576
			<th scope="row" class="label">
2577
				<label for="alt"><span class="alignleft">' . __('Alternative Text') . '</span></label>
2578
			</th>
2579
			<td class="field"><input id="alt" name="alt" value="" type="text" aria-required="true" />
2580
			<p class="help">' . __('Alt text for the image, e.g. &#8220;The Mona Lisa&#8221;') . '</p></td>
2581
		</tr>
2582
		' . $caption . '
2583
		<tr class="align image-only">
2584
			<th scope="row" class="label"><p><label for="align">' . __('Alignment') . '</label></p></th>
2585
			<td class="field">
2586
				<input name="align" id="align-none" value="none" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ($default_align == 'none' ? ' checked="checked"' : '').' />
2587
				<label for="align-none" class="align image-align-none-label">' . __('None') . '</label>
2588
				<input name="align" id="align-left" value="left" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ($default_align == 'left' ? ' checked="checked"' : '').' />
2589
				<label for="align-left" class="align image-align-left-label">' . __('Left') . '</label>
2590
				<input name="align" id="align-center" value="center" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ($default_align == 'center' ? ' checked="checked"' : '').' />
2591
				<label for="align-center" class="align image-align-center-label">' . __('Center') . '</label>
2592
				<input name="align" id="align-right" value="right" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ($default_align == 'right' ? ' checked="checked"' : '').' />
2593
				<label for="align-right" class="align image-align-right-label">' . __('Right') . '</label>
2594
			</td>
2595
		</tr>
2596
2597
		<tr class="image-only">
2598
			<th scope="row" class="label">
2599
				<label for="url"><span class="alignleft">' . __('Link Image To:') . '</span></label>
2600
			</th>
2601
			<td class="field"><input id="url" name="url" value="" type="text" /><br />
2602
2603
			<button type="button" class="button" value="" onclick="document.forms[0].url.value=null">' . __('None') . '</button>
2604
			<button type="button" class="button" value="" onclick="document.forms[0].url.value=document.forms[0].src.value">' . __('Link to image') . '</button>
2605
			<p class="help">' . __('Enter a link URL or click above for presets.') . '</p></td>
2606
		</tr>
2607
		<tr class="image-only">
2608
			<td></td>
2609
			<td>
2610
				<input type="button" class="button" id="go_button" style="color:#bbb;" onclick="addExtImage.insert()" value="' . esc_attr__('Insert into Post') . '" />
2611
			</td>
2612
		</tr>
2613
		<tr class="not-image">
2614
			<td></td>
2615
			<td>
2616
				' . get_submit_button( __( 'Insert into Post' ), 'button', 'insertonlybutton', false ) . '
2617
			</td>
2618
		</tr>
2619
	</tbody></table>
2620
';
2621
2622
}
2623
2624
/**
2625
 * Displays the multi-file uploader message.
2626
 *
2627
 * @since 2.6.0
2628
 *
2629
 * @global int $post_ID
2630
 */
2631
function media_upload_flash_bypass() {
2632
	$browser_uploader = admin_url( 'media-new.php?browser-uploader' );
2633
2634
	if ( $post = get_post() )
2635
		$browser_uploader .= '&amp;post_id=' . intval( $post->ID );
2636
	elseif ( ! empty( $GLOBALS['post_ID'] ) )
2637
		$browser_uploader .= '&amp;post_id=' . intval( $GLOBALS['post_ID'] );
2638
2639
	?>
2640
	<p class="upload-flash-bypass">
2641
	<?php printf( __( 'You are using the multi-file uploader. Problems? Try the <a href="%1$s" target="%2$s">browser uploader</a> instead.' ), $browser_uploader, '_blank' ); ?>
2642
	</p>
2643
	<?php
2644
}
2645
2646
/**
2647
 * Displays the browser's built-in uploader message.
2648
 *
2649
 * @since 2.6.0
2650
 */
2651
function media_upload_html_bypass() {
2652
	?>
2653
	<p class="upload-html-bypass hide-if-no-js">
2654
	   <?php _e('You are using the browser&#8217;s built-in file uploader. The WordPress uploader includes multiple file selection and drag and drop capability. <a href="#">Switch to the multi-file uploader</a>.'); ?>
2655
	</p>
2656
	<?php
2657
}
2658
2659
/**
2660
 * Used to display a "After a file has been uploaded..." help message.
2661
 *
2662
 * @since 3.3.0
2663
 */
2664
function media_upload_text_after() {}
2665
2666
/**
2667
 * Displays the checkbox to scale images.
2668
 *
2669
 * @since 3.3.0
2670
 */
2671
function media_upload_max_image_resize() {
2672
	$checked = get_user_setting('upload_resize') ? ' checked="true"' : '';
2673
	$a = $end = '';
2674
2675
	if ( current_user_can( 'manage_options' ) ) {
2676
		$a = '<a href="' . esc_url( admin_url( 'options-media.php' ) ) . '" target="_blank">';
2677
		$end = '</a>';
2678
	}
2679
?>
2680
<p class="hide-if-no-js"><label>
2681
<input name="image_resize" type="checkbox" id="image_resize" value="true"<?php echo $checked; ?> />
2682
<?php
2683
	/* translators: %1$s is link start tag, %2$s is link end tag, %3$d is width, %4$d is height*/
2684
	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' ) );
2685
?>
2686
</label></p>
2687
<?php
2688
}
2689
2690
/**
2691
 * Displays the out of storage quota message in Multisite.
2692
 *
2693
 * @since 3.5.0
2694
 */
2695
function multisite_over_quota_message() {
2696
	echo '<p>' . sprintf( __( 'Sorry, you have used all of your storage quota of %s MB.' ), get_space_allowed() ) . '</p>';
2697
}
2698
2699
/**
2700
 * Displays the image and editor in the post editor
2701
 *
2702
 * @since 3.5.0
2703
 *
2704
 * @param WP_Post $post A post object.
2705
 */
2706
function edit_form_image_editor( $post ) {
2707
	$open = isset( $_GET['image-editor'] );
2708
	if ( $open )
2709
		require_once ABSPATH . 'wp-admin/includes/image-edit.php';
2710
2711
	$thumb_url = false;
2712
	if ( $attachment_id = intval( $post->ID ) )
2713
		$thumb_url = wp_get_attachment_image_src( $attachment_id, array( 900, 450 ), true );
2714
2715
	$alt_text = get_post_meta( $post->ID, '_wp_attachment_image_alt', true );
2716
2717
	$att_url = wp_get_attachment_url( $post->ID ); ?>
2718
	<div class="wp_attachment_holder wp-clearfix">
2719
	<?php
2720
	if ( wp_attachment_is_image( $post->ID ) ) :
2721
		$image_edit_button = '';
2722 View Code Duplication
		if ( wp_image_editor_supports( array( 'mime_type' => $post->post_mime_type ) ) ) {
2723
			$nonce = wp_create_nonce( "image_editor-$post->ID" );
2724
			$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>";
2725
		}
2726
	?>
2727
2728
		<div class="imgedit-response" id="imgedit-response-<?php echo $attachment_id; ?>"></div>
2729
2730
		<div<?php if ( $open ) echo ' style="display:none"'; ?> class="wp_attachment_image wp-clearfix" id="media-head-<?php echo $attachment_id; ?>">
2731
			<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>
2732
			<p><?php echo $image_edit_button; ?></p>
2733
		</div>
2734
		<div<?php if ( ! $open ) echo ' style="display:none"'; ?> class="image-editor" id="image-editor-<?php echo $attachment_id; ?>">
2735
			<?php if ( $open ) wp_image_editor( $attachment_id ); ?>
2736
		</div>
2737
	<?php
2738
	elseif ( $attachment_id && wp_attachment_is( 'audio', $post ) ):
2739
2740
		wp_maybe_generate_attachment_metadata( $post );
2741
2742
		echo wp_audio_shortcode( array( 'src' => $att_url ) );
2743
2744
	elseif ( $attachment_id && wp_attachment_is( 'video', $post ) ):
2745
2746
		wp_maybe_generate_attachment_metadata( $post );
2747
2748
		$meta = wp_get_attachment_metadata( $attachment_id );
2749
		$w = ! empty( $meta['width'] ) ? min( $meta['width'], 640 ) : 0;
2750
		$h = ! empty( $meta['height'] ) ? $meta['height'] : 0;
2751
		if ( $h && $w < $meta['width'] ) {
2752
			$h = round( ( $meta['height'] * $w ) / $meta['width'] );
2753
		}
2754
2755
		$attr = array( 'src' => $att_url );
2756
		if ( ! empty( $w ) && ! empty( $h ) ) {
2757
			$attr['width'] = $w;
2758
			$attr['height'] = $h;
2759
		}
2760
2761
		$thumb_id = get_post_thumbnail_id( $attachment_id );
2762
		if ( ! empty( $thumb_id ) ) {
2763
			$attr['poster'] = wp_get_attachment_url( $thumb_id );
2764
		}
2765
2766
		echo wp_video_shortcode( $attr );
2767
2768
	else :
2769
2770
		/**
2771
		 * Fires when an attachment type can't be rendered in the edit form.
2772
		 *
2773
		 * @since 4.6.0
2774
		 *
2775
		 * @param WP_Post $post A post object.
2776
		 */
2777
		do_action( 'wp_edit_form_attachment_display', $post );
2778
2779
	endif; ?>
2780
	</div>
2781
	<div class="wp_attachment_details edit-form-section">
2782
		<p>
2783
			<label for="attachment_caption"><strong><?php _e( 'Caption' ); ?></strong></label><br />
2784
			<textarea class="widefat" name="excerpt" id="attachment_caption"><?php echo $post->post_excerpt; ?></textarea>
2785
		</p>
2786
2787
2788
	<?php if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) : ?>
2789
		<p>
2790
			<label for="attachment_alt"><strong><?php _e( 'Alternative Text' ); ?></strong></label><br />
2791
			<input type="text" class="widefat" name="_wp_attachment_image_alt" id="attachment_alt" value="<?php echo esc_attr( $alt_text ); ?>" />
2792
		</p>
2793
	<?php endif; ?>
2794
2795
	<?php
2796
		$quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,close' );
2797
		$editor_args = array(
2798
			'textarea_name' => 'content',
2799
			'textarea_rows' => 5,
2800
			'media_buttons' => false,
2801
			'tinymce' => false,
2802
			'quicktags' => $quicktags_settings,
2803
		);
2804
	?>
2805
2806
	<label for="attachment_content"><strong><?php _e( 'Description' ); ?></strong><?php
2807
	if ( preg_match( '#^(audio|video)/#', $post->post_mime_type ) ) {
2808
		echo ': ' . __( 'Displayed on attachment pages.' );
2809
	} ?></label>
2810
	<?php wp_editor( $post->post_content, 'attachment_content', $editor_args ); ?>
2811
2812
	</div>
2813
	<?php
2814
	$extras = get_compat_media_markup( $post->ID );
2815
	echo $extras['item'];
2816
	echo '<input type="hidden" id="image-edit-context" value="edit-attachment" />' . "\n";
2817
}
2818
2819
/**
2820
 * Displays non-editable attachment metadata in the publish meta box.
2821
 *
2822
 * @since 3.5.0
2823
 */
2824
function attachment_submitbox_metadata() {
2825
	$post = get_post();
2826
2827
	$file = get_attached_file( $post->ID );
2828
	$filename = esc_html( wp_basename( $file ) );
2829
2830
	$media_dims = '';
2831
	$meta = wp_get_attachment_metadata( $post->ID );
2832 View Code Duplication
	if ( isset( $meta['width'], $meta['height'] ) )
2833
		$media_dims .= "<span id='media-dims-$post->ID'>{$meta['width']}&nbsp;&times;&nbsp;{$meta['height']}</span> ";
2834
	/** This filter is documented in wp-admin/includes/media.php */
2835
	$media_dims = apply_filters( 'media_meta', $media_dims, $post );
2836
2837
	$att_url = wp_get_attachment_url( $post->ID );
2838
?>
2839
	<div class="misc-pub-section misc-pub-attachment">
2840
		<label for="attachment_url"><?php _e( 'File URL:' ); ?></label>
2841
		<input type="text" class="widefat urlfield" readonly="readonly" name="attachment_url" id="attachment_url" value="<?php echo esc_attr( $att_url ); ?>" />
2842
	</div>
2843
	<div class="misc-pub-section misc-pub-filename">
2844
		<?php _e( 'File name:' ); ?> <strong><?php echo $filename; ?></strong>
2845
	</div>
2846
	<div class="misc-pub-section misc-pub-filetype">
2847
		<?php _e( 'File type:' ); ?> <strong><?php
2848
			if ( preg_match( '/^.*?\.(\w+)$/', get_attached_file( $post->ID ), $matches ) ) {
2849
				echo esc_html( strtoupper( $matches[1] ) );
2850
				list( $mime_type ) = explode( '/', $post->post_mime_type );
2851
				if ( $mime_type !== 'image' && ! empty( $meta['mime_type'] ) ) {
2852
					if ( $meta['mime_type'] !== "$mime_type/" . strtolower( $matches[1] ) ) {
2853
						echo ' (' . $meta['mime_type'] . ')';
2854
					}
2855
				}
2856
			} else {
2857
				echo strtoupper( str_replace( 'image/', '', $post->post_mime_type ) );
2858
			}
2859
		?></strong>
2860
	</div>
2861
2862
	<?php
2863
		$file_size = false;
2864
2865
		if ( isset( $meta['filesize'] ) )
2866
			$file_size = $meta['filesize'];
2867
		elseif ( file_exists( $file ) )
2868
			$file_size = filesize( $file );
2869
2870
		if ( ! empty( $file_size ) ) : ?>
2871
			<div class="misc-pub-section misc-pub-filesize">
2872
				<?php _e( 'File size:' ); ?> <strong><?php echo size_format( $file_size ); ?></strong>
2873
			</div>
2874
			<?php
2875
		endif;
2876
2877
	if ( preg_match( '#^(audio|video)/#', $post->post_mime_type ) ) {
2878
2879
		/**
2880
		 * Filters the audio and video metadata fields to be shown in the publish meta box.
2881
		 *
2882
		 * The key for each item in the array should correspond to an attachment
2883
		 * metadata key, and the value should be the desired label.
2884
		 *
2885
		 * @since 3.7.0
2886
		 *
2887
		 * @param array $fields An array of the attachment metadata keys and labels.
2888
		 */
2889
		$fields = apply_filters( 'media_submitbox_misc_sections', array(
2890
			'length_formatted' => __( 'Length:' ),
2891
			'bitrate'          => __( 'Bitrate:' ),
2892
		) );
2893
2894
		foreach ( $fields as $key => $label ) {
2895
			if ( empty( $meta[ $key ] ) ) {
2896
				continue;
2897
			}
2898
	?>
2899
		<div class="misc-pub-section misc-pub-mime-meta misc-pub-<?php echo sanitize_html_class( $key ); ?>">
2900
			<?php echo $label ?> <strong><?php
2901
				switch ( $key ) {
2902
					case 'bitrate' :
2903
						echo round( $meta['bitrate'] / 1000 ) . 'kb/s';
2904
						if ( ! empty( $meta['bitrate_mode'] ) ) {
2905
							echo ' ' . strtoupper( esc_html( $meta['bitrate_mode'] ) );
2906
						}
2907
						break;
2908
					default:
2909
						echo esc_html( $meta[ $key ] );
2910
						break;
2911
				}
2912
			?></strong>
2913
		</div>
2914
	<?php
2915
		}
2916
2917
		/**
2918
		 * Filters the audio attachment metadata fields to be shown in the publish meta box.
2919
		 *
2920
		 * The key for each item in the array should correspond to an attachment
2921
		 * metadata key, and the value should be the desired label.
2922
		 *
2923
		 * @since 3.7.0
2924
		 *
2925
		 * @param array $fields An array of the attachment metadata keys and labels.
2926
		 */
2927
		$audio_fields = apply_filters( 'audio_submitbox_misc_sections', array(
2928
			'dataformat' => __( 'Audio Format:' ),
2929
			'codec'      => __( 'Audio Codec:' )
2930
		) );
2931
2932
		foreach ( $audio_fields as $key => $label ) {
2933
			if ( empty( $meta['audio'][ $key ] ) ) {
2934
				continue;
2935
			}
2936
	?>
2937
		<div class="misc-pub-section misc-pub-audio misc-pub-<?php echo sanitize_html_class( $key ); ?>">
2938
			<?php echo $label; ?> <strong><?php echo esc_html( $meta['audio'][$key] ); ?></strong>
2939
		</div>
2940
	<?php
2941
		}
2942
2943
	}
2944
2945
	if ( $media_dims ) : ?>
2946
	<div class="misc-pub-section misc-pub-dimensions">
2947
		<?php _e( 'Dimensions:' ); ?> <strong><?php echo $media_dims; ?></strong>
2948
	</div>
2949
<?php
2950
	endif;
2951
}
2952
2953
/**
2954
 * Parse ID3v2, ID3v1, and getID3 comments to extract usable data
2955
 *
2956
 * @since 3.6.0
2957
 *
2958
 * @param array $metadata An existing array with data
2959
 * @param array $data Data supplied by ID3 tags
2960
 */
2961
function wp_add_id3_tag_data( &$metadata, $data ) {
2962
	foreach ( array( 'id3v2', 'id3v1' ) as $version ) {
2963
		if ( ! empty( $data[$version]['comments'] ) ) {
2964
			foreach ( $data[$version]['comments'] as $key => $list ) {
2965
				if ( 'length' !== $key && ! empty( $list ) ) {
2966
					$metadata[$key] = reset( $list );
2967
					// Fix bug in byte stream analysis.
2968
					if ( 'terms_of_use' === $key && 0 === strpos( $metadata[$key], 'yright notice.' ) )
2969
						$metadata[$key] = 'Cop' . $metadata[$key];
2970
				}
2971
			}
2972
			break;
2973
		}
2974
	}
2975
2976
	if ( ! empty( $data['id3v2']['APIC'] ) ) {
2977
		$image = reset( $data['id3v2']['APIC']);
2978
		if ( ! empty( $image['data'] ) ) {
2979
			$metadata['image'] = array(
2980
				'data' => $image['data'],
2981
				'mime' => $image['image_mime'],
2982
				'width' => $image['image_width'],
2983
				'height' => $image['image_height']
2984
			);
2985
		}
2986
	} elseif ( ! empty( $data['comments']['picture'] ) ) {
2987
		$image = reset( $data['comments']['picture'] );
2988
		if ( ! empty( $image['data'] ) ) {
2989
			$metadata['image'] = array(
2990
				'data' => $image['data'],
2991
				'mime' => $image['image_mime']
2992
			);
2993
		}
2994
	}
2995
}
2996
2997
/**
2998
 * Retrieve metadata from a video file's ID3 tags
2999
 *
3000
 * @since 3.6.0
3001
 *
3002
 * @param string $file Path to file.
3003
 * @return array|bool Returns array of metadata, if found.
3004
 */
3005
function wp_read_video_metadata( $file ) {
3006
	if ( ! file_exists( $file ) ) {
3007
		return false;
3008
	}
3009
3010
	$metadata = array();
3011
3012
	if ( ! defined( 'GETID3_TEMP_DIR' ) ) {
3013
		define( 'GETID3_TEMP_DIR', get_temp_dir() );
3014
	}
3015
3016
	if ( ! class_exists( 'getID3', false ) ) {
3017
		require( ABSPATH . WPINC . '/ID3/getid3.php' );
3018
	}
3019
	$id3 = new getID3();
3020
	$data = $id3->analyze( $file );
3021
3022
	if ( isset( $data['video']['lossless'] ) )
3023
		$metadata['lossless'] = $data['video']['lossless'];
3024
	if ( ! empty( $data['video']['bitrate'] ) )
3025
		$metadata['bitrate'] = (int) $data['video']['bitrate'];
3026
	if ( ! empty( $data['video']['bitrate_mode'] ) )
3027
		$metadata['bitrate_mode'] = $data['video']['bitrate_mode'];
3028
	if ( ! empty( $data['filesize'] ) )
3029
		$metadata['filesize'] = (int) $data['filesize'];
3030
	if ( ! empty( $data['mime_type'] ) )
3031
		$metadata['mime_type'] = $data['mime_type'];
3032 View Code Duplication
	if ( ! empty( $data['playtime_seconds'] ) )
3033
		$metadata['length'] = (int) round( $data['playtime_seconds'] );
3034
	if ( ! empty( $data['playtime_string'] ) )
3035
		$metadata['length_formatted'] = $data['playtime_string'];
3036
	if ( ! empty( $data['video']['resolution_x'] ) )
3037
		$metadata['width'] = (int) $data['video']['resolution_x'];
3038
	if ( ! empty( $data['video']['resolution_y'] ) )
3039
		$metadata['height'] = (int) $data['video']['resolution_y'];
3040
	if ( ! empty( $data['fileformat'] ) )
3041
		$metadata['fileformat'] = $data['fileformat'];
3042
	if ( ! empty( $data['video']['dataformat'] ) )
3043
		$metadata['dataformat'] = $data['video']['dataformat'];
3044
	if ( ! empty( $data['video']['encoder'] ) )
3045
		$metadata['encoder'] = $data['video']['encoder'];
3046
	if ( ! empty( $data['video']['codec'] ) )
3047
		$metadata['codec'] = $data['video']['codec'];
3048
3049 View Code Duplication
	if ( ! empty( $data['audio'] ) ) {
3050
		unset( $data['audio']['streams'] );
3051
		$metadata['audio'] = $data['audio'];
3052
	}
3053
3054
	wp_add_id3_tag_data( $metadata, $data );
3055
3056
	return $metadata;
3057
}
3058
3059
/**
3060
 * Retrieve metadata from a audio file's ID3 tags
3061
 *
3062
 * @since 3.6.0
3063
 *
3064
 * @param string $file Path to file.
3065
 * @return array|bool Returns array of metadata, if found.
3066
 */
3067
function wp_read_audio_metadata( $file ) {
3068
	if ( ! file_exists( $file ) ) {
3069
		return false;
3070
	}
3071
	$metadata = array();
3072
3073
	if ( ! defined( 'GETID3_TEMP_DIR' ) ) {
3074
		define( 'GETID3_TEMP_DIR', get_temp_dir() );
3075
	}
3076
3077
	if ( ! class_exists( 'getID3', false ) ) {
3078
		require( ABSPATH . WPINC . '/ID3/getid3.php' );
3079
	}
3080
	$id3 = new getID3();
3081
	$data = $id3->analyze( $file );
3082
3083 View Code Duplication
	if ( ! empty( $data['audio'] ) ) {
3084
		unset( $data['audio']['streams'] );
3085
		$metadata = $data['audio'];
3086
	}
3087
3088
	if ( ! empty( $data['fileformat'] ) )
3089
		$metadata['fileformat'] = $data['fileformat'];
3090
	if ( ! empty( $data['filesize'] ) )
3091
		$metadata['filesize'] = (int) $data['filesize'];
3092
	if ( ! empty( $data['mime_type'] ) )
3093
		$metadata['mime_type'] = $data['mime_type'];
3094 View Code Duplication
	if ( ! empty( $data['playtime_seconds'] ) )
3095
		$metadata['length'] = (int) round( $data['playtime_seconds'] );
3096
	if ( ! empty( $data['playtime_string'] ) )
3097
		$metadata['length_formatted'] = $data['playtime_string'];
3098
3099
	wp_add_id3_tag_data( $metadata, $data );
3100
3101
	return $metadata;
3102
}
3103
3104
/**
3105
 * Encapsulate logic for Attach/Detach actions
3106
 *
3107
 * @since 4.2.0
3108
 *
3109
 * @global wpdb $wpdb WordPress database abstraction object.
3110
 *
3111
 * @param int    $parent_id Attachment parent ID.
3112
 * @param string $action    Optional. Attach/detach action. Accepts 'attach' or 'detach'.
3113
 *                          Default 'attach'.
3114
 */
3115
function wp_media_attach_action( $parent_id, $action = 'attach' ) {
3116
	global $wpdb;
3117
3118
	if ( ! $parent_id ) {
3119
		return;
3120
	}
3121
3122
	if ( ! current_user_can( 'edit_post', $parent_id ) ) {
3123
		wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
3124
	}
3125
	$ids = array();
3126
	foreach ( (array) $_REQUEST['media'] as $att_id ) {
3127
		$att_id = (int) $att_id;
3128
3129
		if ( ! current_user_can( 'edit_post', $att_id ) ) {
3130
			continue;
3131
		}
3132
3133
		$ids[] = $att_id;
3134
	}
3135
3136
	if ( ! empty( $ids ) ) {
3137
		$ids_string = implode( ',', $ids );
3138
		if ( 'attach' === $action ) {
3139
			$result = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_parent = %d WHERE post_type = 'attachment' AND ID IN ( $ids_string )", $parent_id ) );
3140
		} else {
3141
			$result = $wpdb->query( "UPDATE $wpdb->posts SET post_parent = 0 WHERE post_type = 'attachment' AND ID IN ( $ids_string )" );
3142
		}
3143
3144
		foreach ( $ids as $att_id ) {
3145
			clean_attachment_cache( $att_id );
3146
		}
3147
	}
3148
3149
	if ( isset( $result ) ) {
3150
		$location = 'upload.php';
3151
		if ( $referer = wp_get_referer() ) {
3152
			if ( false !== strpos( $referer, 'upload.php' ) ) {
3153
				$location = remove_query_arg( array( 'attached', 'detach' ), $referer );
3154
			}
3155
		}
3156
3157
		$key = 'attach' === $action ? 'attached' : 'detach';
3158
		$location = add_query_arg( array( $key => $result ), $location );
3159
		wp_redirect( $location );
3160
		exit;
3161
	}
3162
}
3163