Completed
Pull Request — 2.x (#4569)
by Scott Kingsley
04:56
created

PodsField_File::validate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
eloc 2
nc 1
nop 7
1
<?php
2
3
/**
4
 * @package Pods\Fields
5
 */
6
class PodsField_File extends PodsField {
7
8
	/**
9
	 * {@inheritdoc}
10
	 */
11
	public static $group = 'Relationships / Media';
12
13
	/**
14
	 * {@inheritdoc}
15
	 */
16
	public static $type = 'file';
17
18
	/**
19
	 * {@inheritdoc}
20
	 */
21
	public static $label = 'File / Image / Video';
22
23
	/**
24
	 * {@inheritdoc}
25
	 */
26
	protected static $api = false;
27
28
	/**
29
	 * {@inheritdoc}
30
	 */
31
	public function setup() {
32
33
		self::$label = __( 'File / Image / Video', 'pods' );
34
35
	}
36
37
	/**
38
	 * {@inheritdoc}
39
	 */
40
	public function admin_init() {
41
42
		// Hook into AJAX for Uploads.
43
		add_action( 'wp_ajax_pods_upload', array( $this, 'admin_ajax_upload' ) );
44
		add_action( 'wp_ajax_nopriv_pods_upload', array( $this, 'admin_ajax_upload' ) );
45
46
	}
47
48
	/**
49
	 * {@inheritdoc}
50
	 */
51
	public function options() {
52
53
		$sizes = get_intermediate_image_sizes();
54
55
		$image_sizes = array();
56
57
		foreach ( $sizes as $size ) {
58
			$image_sizes[ $size ] = ucwords( str_replace( '-', ' ', $size ) );
59
		}
60
61
		$options = array(
62
			static::$type . '_format_type'            => array(
63
				'label'      => __( 'Upload Limit', 'pods' ),
64
				'default'    => 'single',
65
				'type'       => 'pick',
66
				'data'       => array(
67
					'single' => __( 'Single File', 'pods' ),
68
					'multi'  => __( 'Multiple Files', 'pods' ),
69
				),
70
				'dependency' => true,
71
			),
72
			static::$type . '_uploader'               => array(
73
				'label'      => __( 'File Uploader', 'pods' ),
74
				'default'    => 'attachment',
75
				'type'       => 'pick',
76
				'data'       => apply_filters(
77
					'pods_form_ui_field_' . static::$type . '_uploader_options', array(
78
						'attachment' => __( 'Upload and/or Select (Media Library)', 'pods' ),
79
						'plupload'   => __( 'Upload only (Plupload)', 'pods' ),
80
					)
81
				),
82
				'dependency' => true,
83
			),
84
			static::$type . '_attachment_tab'         => array(
85
				'label'      => __( 'Attachments Default Tab', 'pods' ),
86
				'depends-on' => array( static::$type . '_uploader' => 'attachment' ),
87
				'default'    => 'upload',
88
				'type'       => 'pick',
89
				'data'       => array(
90
					// These keys must match WP media modal router names.
91
					'upload' => __( 'Upload File', 'pods' ),
92
					'browse' => __( 'Media Library', 'pods' ),
93
				),
94
			),
95
			static::$type . '_edit_title'             => array(
96
				'label'   => __( 'Editable Title', 'pods' ),
97
				'default' => 1,
98
				'type'    => 'boolean',
99
			),
100
			static::$type . '_show_edit_link'         => array(
101
				'label'   => __( 'Show Edit Link', 'pods' ),
102
				'default' => 0,
103
				'type'    => 'boolean',
104
			),
105
			static::$type . '_linked'                 => array(
106
				'label'   => __( 'Show Download Link', 'pods' ),
107
				'default' => 0,
108
				'type'    => 'boolean',
109
			),
110
			static::$type . '_limit'                  => array(
111
				'label'      => __( 'Max Number of Files', 'pods' ),
112
				'depends-on' => array( static::$type . '_format_type' => 'multi' ),
113
				'default'    => 0,
114
				'type'       => 'number',
115
			),
116
			static::$type . '_restrict_filesize'      => array(
117
				'label'      => __( 'Restrict File Size', 'pods' ),
118
				'help'       => __( 'Valid size suffixes are: GB (gigabytes), MB (megabytes), KB (kilobytes), or B (bytes).  Defaults to the <a href="https://developer.wordpress.org/reference/functions/wp_max_upload_size/">wp_max_upload_size</a> setting.', 'pods' ),
119
				'depends-on' => array( static::$type . '_uploader' => 'plupload' ),
120
				'default'    => '10MB',
121
				'type'       => 'text',
122
			),
123
			static::$type . '_type'                   => array(
124
				'label'      => __( 'Restrict File Types', 'pods' ),
125
				'default'    => apply_filters( 'pods_form_ui_field_' . static::$type . '_type_default', 'images' ),
126
				'type'       => 'pick',
127
				'data'       => apply_filters(
128
					'pods_form_ui_field_' . static::$type . '_type_options', array(
129
						'images' => __( 'Images (jpg, jpeg, png, gif)', 'pods' ),
130
						'video'  => __( 'Video (mpg, mov, flv, mp4, etc..)', 'pods' ),
131
						'audio'  => __( 'Audio (mp3, m4a, wav, wma, etc..)', 'pods' ),
132
						'text'   => __( 'Text (txt, csv, tsv, rtx, etc..)', 'pods' ),
133
						'any'    => __( 'Any Type (no restriction)', 'pods' ),
134
						'other'  => __( 'Other (customize allowed extensions)', 'pods' ),
135
					)
136
				),
137
				'dependency' => true,
138
			),
139
			static::$type . '_allowed_extensions'     => array(
140
				'label'       => __( 'Allowed File Extensions', 'pods' ),
141
				'description' => __( 'Separate file extensions with a comma (ex. jpg,png,mp4,mov)', 'pods' ),
142
				'depends-on'  => array( static::$type . '_type' => 'other' ),
143
				'default'     => apply_filters( 'pods_form_ui_field_' . static::$type . '_extensions_default', '' ),
144
				'type'        => 'text',
145
			),
146
			static::$type . '_field_template'         => array(
147
				'label'      => __( 'List Style', 'pods' ),
148
				'help'       => __( 'You can choose which style you would like the files to appear within the form.', 'pods' ),
149
				'depends-on' => array( static::$type . '_type' => 'images' ),
150
				'default'    => apply_filters( 'pods_form_ui_field_' . static::$type . '_template_default', 'rows' ),
151
				'type'       => 'pick',
152
				'data'       => apply_filters(
153
					'pods_form_ui_field_' . static::$type . '_type_templates', array(
154
						'rows'  => __( 'Rows', 'pods' ),
155
						'tiles' => __( 'Tiles', 'pods' ),
156
					)
157
				),
158
			),
159
			static::$type . '_add_button'             => array(
160
				'label'   => __( 'Add Button Text', 'pods' ),
161
				'default' => __( 'Add File', 'pods' ),
162
				'type'    => 'text',
163
			),
164
			static::$type . '_modal_title'            => array(
165
				'label'      => __( 'Modal Title', 'pods' ),
166
				'depends-on' => array( static::$type . '_uploader' => 'attachment' ),
167
				'default'    => __( 'Attach a file', 'pods' ),
168
				'type'       => 'text',
169
			),
170
			static::$type . '_modal_add_button'       => array(
171
				'label'      => __( 'Modal Add Button Text', 'pods' ),
172
				'depends-on' => array( static::$type . '_uploader' => 'attachment' ),
173
				'default'    => __( 'Add File', 'pods' ),
174
				'type'       => 'text',
175
			),
176
177
			/* WP GALLERY OUTPUT */
178
			static::$type . '_wp_gallery_output'      => array(
179
				'label'      => __( 'Output as a WP Gallery', 'pods' ),
180
				'help'       => sprintf( __( '<a href="%s" target="_blank">Click here for more info</a>', 'pods' ), 'https://codex.wordpress.org/The_WordPress_Gallery' ),
181
				'depends-on' => array( static::$type . '_type' => 'images' ),
182
				'dependency' => true,
183
				'type'       => 'boolean',
184
			),
185
			static::$type . '_wp_gallery_link'        => array(
186
				'label'      => __( 'Gallery image links', 'pods' ),
187
				'depends-on' => array( static::$type . '_wp_gallery_output' => 1 ),
188
				'type'       => 'pick',
189
				'data'       => array(
190
					'post' => __( 'Attachment Page', 'pods' ),
191
					'file' => __( 'Media File', 'pods' ),
192
					'none' => __( 'None', 'pods' ),
193
				),
194
			),
195
			static::$type . '_wp_gallery_columns'     => array(
196
				'label'      => __( 'Gallery image columns', 'pods' ),
197
				'depends-on' => array( static::$type . '_wp_gallery_output' => 1 ),
198
				'type'       => 'pick',
199
				'data'       => array(
200
					'1' => 1,
201
					'2' => 2,
202
					'3' => 3,
203
					'4' => 4,
204
					'5' => 5,
205
					'6' => 6,
206
					'7' => 7,
207
					'8' => 8,
208
					'9' => 9,
209
				),
210
			),
211
			static::$type . '_wp_gallery_random_sort' => array(
212
				'label'      => __( 'Gallery randomized order', 'pods' ),
213
				'depends-on' => array( static::$type . '_wp_gallery_output' => 1 ),
214
				'type'       => 'boolean',
215
			),
216
			static::$type . '_wp_gallery_size'        => array(
217
				'label'      => __( 'Gallery image size', 'pods' ),
218
				'depends-on' => array( static::$type . '_wp_gallery_output' => 1 ),
219
				'type'       => 'pick',
220
				'data'       => $this->data_image_sizes(),
221
			),
222
		);
223
224
		return $options;
225
226
	}
227
228
	/**
229
	 * {@inheritdoc}
230
	 */
231
	public function schema( $options = null ) {
232
233
		$schema = false;
234
235
		return $schema;
236
237
	}
238
239
	/**
240
	 * {@inheritdoc}
241
	 */
242
	public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
243
244
		if ( ! empty( $options[ static::$type . '_wp_gallery_output' ] ) ) {
245
			return $this->do_wp_gallery( $value, $options );
246
		}
247
248
		if ( is_array( $value ) && ! empty( $value ) ) {
249
			if ( isset( $value['ID'] ) ) {
250
				$value = wp_get_attachment_url( $value['ID'] );
251
			} else {
252
				$attachments = $value;
253
				$value       = array();
254
255 View Code Duplication
				foreach ( $attachments as $v ) {
256
					if ( ! is_array( $v ) ) {
257
						$value[] = $v;
258
					} elseif ( isset( $v['ID'] ) ) {
259
						$value[] = wp_get_attachment_url( $v['ID'] );
260
					}
261
				}
262
263
				$value = implode( ' ', $value );
264
			}
265
		}
266
267
		return $value;
268
269
	}
270
271
	/**
272
	 * {@inheritdoc}
273
	 */
274
	public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
275
276
		$options = (array) $options;
277
278
		$type = pods_v( 'type', $options, static::$type );
279
280
		$args = compact( array_keys( get_defined_vars() ) );
281
		$args = (object) $args;
282
283
		/**
284
		 * Access Checking
285
		 */
286
		$is_user_logged_in = is_user_logged_in();
287
288
		$file_upload_requirements = array(
289
			'disabled'          => ( defined( 'PODS_DISABLE_FILE_UPLOAD' ) && true === PODS_DISABLE_FILE_UPLOAD ),
290
			'require_login'     => ( defined( 'PODS_UPLOAD_REQUIRE_LOGIN' ) && true === PODS_UPLOAD_REQUIRE_LOGIN && ! $is_user_logged_in ),
291
			'require_login_cap' => ( defined( 'PODS_UPLOAD_REQUIRE_LOGIN' ) && is_string( PODS_UPLOAD_REQUIRE_LOGIN ) && ( ! $is_user_logged_in || ! current_user_can( PODS_UPLOAD_REQUIRE_LOGIN ) ) ),
292
		);
293
294
		$file_browser_requirements = array(
295
			'disabled'          => ( defined( 'PODS_DISABLE_FILE_BROWSER' ) && true === PODS_DISABLE_FILE_BROWSER ),
296
			'require_login'     => ( defined( 'PODS_FILES_REQUIRE_LOGIN' ) && true === PODS_FILES_REQUIRE_LOGIN && ! $is_user_logged_in ),
297
			'require_login_cap' => ( defined( 'PODS_FILES_REQUIRE_LOGIN' ) && is_string( PODS_FILES_REQUIRE_LOGIN ) && ( ! $is_user_logged_in || ! current_user_can( PODS_FILES_REQUIRE_LOGIN ) ) ),
298
		);
299
300
		$file_upload_requirements  = array_filter( $file_upload_requirements );
301
		$file_browser_requirements = array_filter( $file_browser_requirements );
302
303
		if ( ! empty( $file_upload_requirements ) && ! empty( $file_browser_requirements ) ) {
304
			?>
305
			<p><?php esc_html_e( 'You do not have access to upload / browse files. Contact your website admin to resolve.', 'pods' ); ?></p>
306
			<?php
307
308
			return;
309
		}
310
311
		wp_enqueue_script( 'pods-dfv' );
312
		wp_enqueue_media();
313
314
		// Ensure the media library is initialized
315
		$this->render_input_script( $args );
316
317
		// @todo: we're short-circuiting for prototyping above. The actions below will need to be woven in somehow.
318
		/**
319
		 * $form_field_type . '_uploader' != attachment, plupload, media
320
		 * Run this action 'pods_form_ui_field_' . static::$type . '_uploader_' . static::$type . '_uploader'
321
		 * Run this action 'pods_form_ui_field_' . static::$type . '_uploader', static::$type . '_uploader'
322
		 * Pass these args $name, $value, $options, $pod, $id
323
		 */
324
	}
325
326
	/**
327
	 * {@inheritdoc}
328
	 */
329
	public function build_dfv_field_options( $options, $args ) {
330
331
		if ( ! is_admin() ) {
332
			include_once ABSPATH . '/wp-admin/includes/template.php';
333
334
			if ( is_multisite() ) {
335
				include_once ABSPATH . '/wp-admin/includes/ms.php';
336
			}
337
		}
338
339
		// Handle default template setting.
340
		$file_field_template = pods_v( $args->type . '_field_template', $options, 'rows', true );
341
342
		// Get which file types the field is limited to.
343
		$limit_file_type = pods_v( $args->type . '_type', $options, 'images' );
344
345
		// Non-image file types are forced to rows template right now.
346
		if ( 'images' !== $limit_file_type ) {
347
			$file_field_template = 'rows';
348
		}
349
350
		$options[ $args->type . '_field_template' ] = $file_field_template;
351
352
		// Enforce limit.
353
		$file_limit = 1;
354
355
		if ( 'multi' === pods_v( $args->type . '_format_type', $options, 'single' ) ) {
356
			$file_limit = (int) pods_v( $args->type . '_limit', $options, 0 );
357
358
			if ( $file_limit < 0 ) {
359
				$file_limit = 0;
360
			}
361
		}
362
363
		$options[ $args->type . '_limit' ] = $file_limit;
364
365
		// Build types and extensions to limit by.
366
		if ( 'images' === $limit_file_type ) {
367
			$limit_types      = 'image';
368
			$limit_extensions = 'jpg,jpeg,png,gif';
369
		} elseif ( 'video' === $limit_file_type ) {
370
			$limit_types      = 'video';
371
			$limit_extensions = 'mpg,mov,flv,mp4';
372
		} elseif ( 'audio' === $limit_file_type ) {
373
			$limit_types      = 'audio';
374
			$limit_extensions = 'mp3,m4a,wav,wma';
375
		} elseif ( 'text' === $limit_file_type ) {
376
			$limit_types      = 'text';
377
			$limit_extensions = 'txt,rtx,csv,tsv';
378
		} elseif ( 'any' === $limit_file_type ) {
379
			$limit_types      = '';
380
			$limit_extensions = '*';
381
		} else {
382
			$limit_types = pods_v( $args->type . '_allowed_extensions', $options, '', true );
383
384
			$limit_extensions = $limit_types;
385
		}
386
387
		// Find and replace certain characters to properly split by commas.
388
		$find = array(
389
			' ',
390
			'.',
391
			"\n",
392
			"\t",
393
			';',
394
		);
395
396
		$replace = array(
397
			'',
398
			',',
399
			',',
400
			',',
401
		);
402
403
		$limit_types      = trim( str_replace( $find, $replace, $limit_types ), ',' );
404
		$limit_extensions = trim( str_replace( $find, $replace, $limit_extensions ), ',' );
405
		$mime_types       = wp_get_mime_types();
406
407
		if ( ! in_array( $limit_file_type, array( 'images', 'video', 'audio', 'text', 'any' ), true ) ) {
408
			$new_limit_types = array();
409
410
			$limit_types = explode( ',', $limit_types );
411
412
			foreach ( $limit_types as $k => $limit_type ) {
413
				if ( isset( $mime_types[ $limit_type ] ) ) {
414
					$mime = explode( '/', $mime_types[ $limit_type ] );
415
					$mime = $mime[0];
416
417
					if ( ! in_array( $mime, $new_limit_types, true ) ) {
418
						$new_limit_types[] = $mime;
419
					}
420
				} else {
421
					$found = false;
422
423 View Code Duplication
					foreach ( $mime_types as $type => $mime ) {
424
						if ( false !== strpos( $type, $limit_type ) ) {
425
							$mime = explode( '/', $mime );
426
							$mime = $mime[0];
427
428
							if ( ! in_array( $mime, $new_limit_types, true ) ) {
429
								$new_limit_types[] = $mime;
430
							}
431
432
							$found = true;
433
						}
434
					}
435
436
					if ( ! $found ) {
437
						$new_limit_types[] = $limit_type;
438
					}
439
				}//end if
440
			}//end foreach
441
442
			if ( ! empty( $new_limit_types ) ) {
443
				$limit_types = implode( ',', $new_limit_types );
444
			}
445
		}//end if
446
447
		$options['limit_types']      = $limit_types;
448
		$options['limit_extensions'] = $limit_extensions;
449
450
		$is_user_logged_in = is_user_logged_in();
451
452
		// @todo test frontend media modal
453
		if ( empty( $options[ static::$type . '_uploader' ] ) || ! is_admin() || ! $is_user_logged_in || ( ! current_user_can( 'upload_files' ) && ! current_user_can( 'edit_files' ) ) ) {
454
			$options[ static::$type . '_uploader' ] = 'plupload';
455
		}
456
457
		// @todo: plupload specific options need accommodation
458
		if ( 'plupload' === $options[ static::$type . '_uploader' ] ) {
459
			wp_enqueue_script( 'plupload-all' );
460
461
			if ( $is_user_logged_in ) {
462
				$uid = 'user_' . get_current_user_id();
463
			} else {
464
				// @codingStandardsIgnoreLine
465
				$uid = @session_id();
466
			}
467
468
			$pod_id = '0';
469
470
			if ( is_object( $args->pod ) ) {
471
				$pod_id = $args->pod->pod_id;
472
			}
473
474
			$uri_hash    = wp_create_nonce( 'pods_uri_' . $_SERVER['REQUEST_URI'] );
475
			$field_nonce = wp_create_nonce( 'pods_upload_' . $pod_id . '_' . $uid . '_' . $uri_hash . '_' . $options['id'] );
476
477
			$options['plupload_init'] = array(
478
				'runtimes'            => 'html5,silverlight,flash,html4',
479
				'url'                 => admin_url( 'admin-ajax.php?pods_ajax=1', 'relative' ),
480
				'file_data_name'      => 'Filedata',
481
				'multiple_queues'     => false,
482
				'max_file_size'       => wp_max_upload_size() . 'b',
483
				'flash_swf_url'       => includes_url( 'js/plupload/plupload.flash.swf' ),
484
				'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
485
				'filters'             => array(
486
					array(
487
						'title'      => __( 'Allowed Files', 'pods' ),
488
						'extensions' => '*',
489
					),
490
				),
491
				'multipart'           => true,
492
				'urlstream_upload'    => true,
493
				'multipart_params'    => array(
494
					'_wpnonce' => $field_nonce,
495
					'action'   => 'pods_upload',
496
					'method'   => 'upload',
497
					'pod'      => $pod_id,
498
					'field'    => $options['id'],
499
					'uri'      => $uri_hash,
500
				),
501
			);
502
		}//end if
503
504
		return $options;
505
506
	}
507
508
	/**
509
	 * {@inheritdoc}
510
	 */
511
	public function build_dfv_field_attributes( $attributes, $args ) {
512
513
		// Add template class.
514
		$attributes['class'] .= ' pods-field-template-' . $args->options[ $args->type . '_field_template' ];
515
516
		return $attributes;
517
518
	}
519
520
	/**
521
	 * {@inheritdoc}
522
	 */
523
	public function build_dfv_field_item_data( $args ) {
524
525
		$data = array();
526
527
		$title_editable = (int) pods_v( $args->type . '_edit_title', $args->options, 0 );
528
529
		$value = $args->value;
530
531
		if ( empty( $value ) ) {
532
			$value = array();
533
		} else {
534
			$value = (array) $value;
535
		}
536
537
		foreach ( $value as $id ) {
538
			$attachment = get_post( $id );
539
540
			if ( empty( $attachment ) ) {
541
				continue;
542
			}
543
544
			$icon = '';
545
546
			// @todo Add access check
547
			$edit_link = get_edit_post_link( $attachment->ID, 'raw' );
548
549
			$link     = get_permalink( $attachment->ID );
550
			$download = wp_get_attachment_url( $attachment->ID );
551
552
			$thumb = wp_get_attachment_image_src( $id, 'thumbnail', true );
553
554
			if ( ! empty( $thumb[0] ) ) {
555
				$icon = $thumb[0];
556
			}
557
558
			$title = $attachment->post_title;
559
560
			if ( 0 === $title_editable ) {
561
				$title = basename( $attachment->guid );
562
			}
563
564
			$data[] = array(
565
				'id'        => $id,
566
				'icon'      => $icon,
567
				'name'      => $title,
568
				'edit_link' => $edit_link,
569
				'link'      => $link,
570
				'download'  => $download,
571
			);
572
		}//end foreach
573
574
		return $data;
575
576
	}
577
578
	/**
579
	 * {@inheritdoc}
580
	 */
581
	public function regex( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
582
583
		return false;
584
585
	}
586
587
	/**
588
	 * {@inheritdoc}
589
	 */
590
	public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
591
592
		// @todo Check file size
593
		// @todo Check file extensions
594
		return true;
595
596
	}
597
598
	/**
599
	 * {@inheritdoc}
600
	 */
601
	public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
602
603
		return $value;
604
605
	}
606
607
	/**
608
	 * {@inheritdoc}
609
	 */
610
	public function save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
611
612
		if ( empty( self::$api ) ) {
613
			self::$api = pods_api();
614
		}
615
616
		// Handle File title saving.
617
		foreach ( $value as $id ) {
618
			$title = false;
619
620
			if ( is_array( $id ) ) {
621
				if ( isset( $id['title'] ) && 0 < strlen( trim( $id['title'] ) ) ) {
622
					$title = trim( $id['title'] );
623
				}
624
625
				if ( isset( $id['id'] ) ) {
626
					$id = (int) $id['id'];
627
				} else {
628
					$id = 0;
629
				}
630
			}
631
632
			if ( empty( $id ) ) {
633
				continue;
634
			}
635
636
			$attachment_data = array();
637
638
			// Update the title if set.
639
			if ( false !== $title && 1 === (int) pods_v( static::$type . '_edit_title', $options, 0 ) ) {
640
				$attachment_data['post_title'] = $title;
641
			}
642
643
			// Update attachment parent if it's not set yet and we're updating a post.
644
			if ( ! empty( $params->id ) && ! empty( $pod['type'] ) && 'post_type' === $pod['type'] ) {
645
				$attachment = get_post( $id );
646
647
				if ( isset( $attachment->post_parent ) && 0 === (int) $attachment->post_parent ) {
648
					$attachment_data['post_parent'] = (int) $params->id;
649
				}
650
			}
651
652
			// Update the attachment if it the data array is not still empty.
653
			if ( ! empty( $attachment_data ) ) {
654
				$attachment_data['ID'] = $id;
655
656
				self::$api->save_wp_object( 'media', $attachment_data );
657
			}
658
		}//end foreach
659
660
	}
661
662
	/**
663
	 * {@inheritdoc}
664
	 */
665
	public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
666
667
		if ( empty( $value ) ) {
668
			return;
669
		}
670
671
		if ( ! empty( $value ) && isset( $value['ID'] ) ) {
672
			$value = array( $value );
673
		}
674
675
		$image_size = apply_filters( 'pods_form_ui_field_' . static::$type . '_ui_image_size', 'thumbnail', $id, $value, $name, $options, $pod );
676
677
		return $this->images( $id, $value, $name, $options, $pod, $image_size );
678
679
	}
680
681
	/**
682
	 * Return image(s) markup.
683
	 *
684
	 * @param int    $id         Item ID.
685
	 * @param mixed  $value      Field value.
686
	 * @param string $name       Field name.
687
	 * @param array  $options    Field options.
688
	 * @param array  $pod        Pod options.
689
	 * @param string $image_size Image size.
690
	 *
691
	 * @return string
692
	 * @since 2.3
693
	 */
694
	public function images( $id, $value, $name = null, $options = null, $pod = null, $image_size = null ) {
695
696
		$images = '';
697
698
		if ( empty( $value ) || ! is_array( $value ) ) {
699
			return $images;
700
		}
701
702
		foreach ( $value as $v ) {
703
			$images .= pods_image( $v, $image_size );
704
		}
705
706
		return $images;
707
708
	}
709
710
	/**
711
	 * Data callback for Image Sizes.
712
	 *
713
	 * @param string       $name    The name of the field.
714
	 * @param string|array $value   The value of the field.
715
	 * @param array        $options Field options.
716
	 * @param array        $pod     Pod data.
717
	 * @param int          $id      Item ID.
718
	 *
719
	 * @return array
720
	 *
721
	 * @since 2.3
722
	 */
723 View Code Duplication
	public function data_image_sizes( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
724
725
		$data = array();
726
727
		$image_sizes = get_intermediate_image_sizes();
728
729
		foreach ( $image_sizes as $image_size ) {
730
			$data[ $image_size ] = ucwords( str_replace( '-', ' ', $image_size ) );
731
		}
732
733
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
734
735
	}
736
737
	/**
738
	 * Create a WP Gallery from the passed values (need to be attachments)
739
	 *
740
	 * @since  2.7
741
	 *
742
	 * @param  string|array $value   The value(s).
743
	 * @param  array        $options The field options.
744
	 *
745
	 * @return string
746
	 */
747
	public function do_wp_gallery( $value, $options ) {
748
749
		$shortcode_args = array();
750
751
		if ( ! empty( $options[ static::$type . '_wp_gallery_columns' ] ) ) {
752
			$shortcode_args['columns'] = absint( $options[ static::$type . '_wp_gallery_columns' ] );
753
		}
754
755
		if ( ! empty( $options[ static::$type . '_wp_gallery_random_sort' ] ) ) {
756
			$shortcode_args['orderby'] = 'rand';
757
		}
758
759 View Code Duplication
		if ( ! empty( $options[ static::$type . '_wp_gallery_link' ] ) ) {
760
			$shortcode_args['link'] = $options[ static::$type . '_wp_gallery_link' ];
761
		}
762
763 View Code Duplication
		if ( ! empty( $options[ static::$type . '_wp_gallery_size' ] ) ) {
764
			$shortcode_args['size'] = $options[ static::$type . '_wp_gallery_size' ];
765
		}
766
767
		if ( isset( $value['ID'] ) ) {
768
			$shortcode_args['ids'] = $value['ID'];
769
		} else {
770
			$images = array();
771
772 View Code Duplication
			foreach ( $value as $v ) {
0 ignored issues
show
Bug introduced by
The expression $value of type string|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
773
				if ( ! is_array( $v ) ) {
774
					$images[] = (int) $v;
775
				} elseif ( isset( $v['ID'] ) ) {
776
					$images[] = (int) $v['ID'];
777
				}
778
			}
779
780
			$shortcode_args['ids'] = implode( ',', $images );
781
		}
782
783
		if ( is_callable( 'gallery_shortcode' ) ) {
784
			return gallery_shortcode( $shortcode_args );
785
		} else {
786
			$shortcode = '[gallery';
787
788
			foreach ( $shortcode_args as $key => $shortcode_arg ) {
789
				$shortcode .= ' ' . esc_attr( $key ) . '="' . esc_attr( $shortcode_arg ) . '"';
790
			}
791
792
			$shortcode .= ']';
793
794
			return do_shortcode( $shortcode );
795
		}
796
797
	}
798
799
	/**
800
	 * Handle file row output for uploaders
801
	 *
802
	 * @param array           $attributes Field options.
803
	 * @param int             $limit      List limit.
804
	 * @param bool            $editable   Whether the items should be editable.
805
	 * @param null|int|string $id         Item ID.
806
	 * @param null|string     $icon       Icon URL.
807
	 * @param null|string     $name       File name.
808
	 * @param bool            $linked     Whether the items should be linked.
809
	 * @param null|string     $link       Link URL.
810
	 *
811
	 * @return string
812
	 * @since      2.0
813
	 *
814
	 * @deprecated 2.7
815
	 */
816
	public function markup( $attributes, $limit = 1, $editable = true, $id = null, $icon = null, $name = null, $linked = false, $link = null ) {
817
818
		_doing_it_wrong( 'PodsField_File::markup', esc_html__( 'This method has been deprecated and will be removed from Pods 3.0', 'pods' ), '2.7' );
819
820
		// Preserve current file type.
821
		$field_type = PodsForm::$field_type;
822
823
		ob_start();
824
825
		if ( empty( $id ) ) {
826
			$id = '{{id}}';
827
		}
828
829
		if ( empty( $icon ) ) {
830
			$icon = '{{icon}}';
831
		}
832
833
		if ( empty( $name ) ) {
834
			$name = '{{name}}';
835
		}
836
837
		if ( empty( $link ) ) {
838
			$link = '{{link}}';
839
		}
840
841
		$editable = (boolean) $editable;
842
		$linked   = (boolean) $linked;
843
		?>
844
		<li class="pods-file hidden" id="pods-file-<?php echo esc_attr( $id ); ?>">
845
			<?php
846
				// @codingStandardsIgnoreLine
847
				echo PodsForm::field( $attributes['name'] . '[' . $id . '][id]', $id, 'hidden' );
848
			?>
849
850
			<ul class="pods-file-meta media-item">
851
				<?php if ( 1 !== (int) $limit ) { ?>
852
					<li class="pods-file-col pods-file-handle">Handle</li>
853
				<?php } ?>
854
855
				<li class="pods-file-col pods-file-icon">
856
					<img class="pinkynail" src="<?php echo esc_url( $icon ); ?>" alt="Icon" />
857
				</li>
858
859
				<li class="pods-file-col pods-file-name">
860
					<?php
861
					if ( $editable ) {
862
						// @codingStandardsIgnoreLine
863
						echo PodsForm::field( $attributes['name'] . '[' . $id . '][title]', $name, 'text' );
864
					} else {
865
						echo esc_html( $name );
866
					}
867
					?>
868
				</li>
869
870
				<li class="pods-file-col pods-file-actions">
871
					<ul>
872
						<li class="pods-file-col pods-file-delete"><a href="#delete">Delete</a></li>
873
						<?php
874
						if ( $linked ) {
875
							?>
876
							<li class="pods-file-col pods-file-download">
877
								<a href="<?php echo esc_url( $link ); ?>" target="_blank">Download</a></li>
878
							<?php
879
						}
880
						?>
881
					</ul>
882
				</li>
883
			</ul>
884
		</li>
885
		<?php
886
		PodsForm::$field_type = $field_type;
887
888
		return ob_get_clean();
889
890
	}
891
892
	/**
893
	 * Handle AJAX plupload calls.
894
	 *
895
	 * @since 2.3
896
	 */
897
	public function admin_ajax_upload() {
898
899
		pods_session_start();
900
901
		// Sanitize input @codingStandardsIgnoreLine
902
		$params = pods_unslash( (array) $_POST );
903
904 View Code Duplication
		foreach ( $params as $key => $value ) {
905
			if ( 'action' === $key ) {
906
				continue;
907
			}
908
909
			unset( $params[ $key ] );
910
911
			$params[ str_replace( '_podsfix_', '', $key ) ] = $value;
912
		}
913
914
		$params = (object) $params;
915
916
		$methods = array(
917
			'upload',
918
		);
919
920
		if ( ! isset( $params->method ) || ! in_array( $params->method, $methods, true ) || ! isset( $params->pod ) || ! isset( $params->field ) || ! isset( $params->uri ) || empty( $params->uri ) ) {
921
			pods_error( 'Invalid AJAX request', PodsInit::$admin );
922
		} elseif ( ! empty( $params->pod ) && empty( $params->field ) ) {
923
			pods_error( 'Invalid AJAX request', PodsInit::$admin );
924
		} elseif ( empty( $params->pod ) && ! current_user_can( 'upload_files' ) ) {
925
			pods_error( 'Invalid AJAX request', PodsInit::$admin );
926
		}
927
928
		// Flash often fails to send cookies with the POST or upload, so we need to pass it in GET or POST instead
929
		// @codingStandardsIgnoreLine
930
		if ( is_ssl() && empty( $_COOKIE[ SECURE_AUTH_COOKIE ] ) && ! empty( $_REQUEST['auth_cookie'] ) ) {
931
			// @codingStandardsIgnoreLine
932
			$_COOKIE[ SECURE_AUTH_COOKIE ] = $_REQUEST['auth_cookie'];
933
			// @codingStandardsIgnoreLine
934
		} elseif ( empty( $_COOKIE[ AUTH_COOKIE ] ) && ! empty( $_REQUEST['auth_cookie'] ) ) {
935
			// @codingStandardsIgnoreLine
936
			$_COOKIE[ AUTH_COOKIE ] = $_REQUEST['auth_cookie'];
937
		}
938
939
		// @codingStandardsIgnoreLine
940
		if ( empty( $_COOKIE[ LOGGED_IN_COOKIE ] ) && ! empty( $_REQUEST['logged_in_cookie'] ) ) {
941
			// @codingStandardsIgnoreLine
942
			$_COOKIE[ LOGGED_IN_COOKIE ] = $_REQUEST['logged_in_cookie'];
943
		}
944
945
		global $current_user;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
946
		unset( $current_user );
947
948
		/**
949
		 * Access Checking
950
		 */
951
		$upload_disabled   = false;
952
		$is_user_logged_in = is_user_logged_in();
953
954
		if ( defined( 'PODS_DISABLE_FILE_UPLOAD' ) && true === PODS_DISABLE_FILE_UPLOAD ) {
955
			$upload_disabled = true;
956
		} elseif ( ! $is_user_logged_in && defined( 'PODS_UPLOAD_REQUIRE_LOGIN' ) ) {
957
			if ( true === PODS_UPLOAD_REQUIRE_LOGIN ) {
958
				$upload_disabled = true;
959
			} elseif ( is_string( PODS_UPLOAD_REQUIRE_LOGIN ) && ! current_user_can( PODS_UPLOAD_REQUIRE_LOGIN ) ) {
960
				$upload_disabled = true;
961
			}
962
		}
963
964
		$uid = @session_id();
965
966
		if ( $is_user_logged_in ) {
967
			$uid = 'user_' . get_current_user_id();
968
		}
969
970
		$nonce_check = 'pods_upload_' . (int) $params->pod . '_' . $uid . '_' . $params->uri . '_' . (int) $params->field;
971
972 View Code Duplication
		if ( true === $upload_disabled || ! isset( $params->_wpnonce ) || false === wp_verify_nonce( $params->_wpnonce, $nonce_check ) ) {
973
			pods_error( __( 'Unauthorized request', 'pods' ), PodsInit::$admin );
974
		}
975
976
		$pod   = array();
977
		$field = array(
978
			'type'    => 'file',
979
			'options' => array(),
980
		);
981
982
		if ( empty( self::$api ) ) {
983
			self::$api = pods_api();
984
		}
985
986
		self::$api->display_errors = false;
987
988
		if ( ! empty( $params->pod ) ) {
989
			$pod   = self::$api->load_pod( array( 'id' => (int) $params->pod ) );
990
			$field = self::$api->load_field( array( 'id' => (int) $params->field ) );
991
992 View Code Duplication
			if ( empty( $pod ) || empty( $field ) || (int) $pod['id'] !== (int) $field['pod_id'] || ! isset( $pod['fields'][ $field['name'] ] ) ) {
993
				pods_error( __( 'Invalid field request', 'pods' ), PodsInit::$admin );
994
			}
995
996
			if ( ! in_array( $field['type'], PodsForm::file_field_types(), true ) ) {
997
				pods_error( __( 'Invalid field', 'pods' ), PodsInit::$admin );
998
			}
999
		}
1000
1001
		$method = $params->method;
1002
1003
		// Cleaning up $params
1004
		unset( $params->action, $params->method, $params->_wpnonce );
1005
1006
		$params->post_id = (int) pods_v( 'post_id', $params, 0 );
1007
1008
		/**
1009
		 * Upload a new file (advanced - returns URL and ID)
1010
		 */
1011
		if ( 'upload' === $method ) {
1012
			$file = $_FILES['Filedata'];
1013
1014
			$limit_size = pods_v( $field['type'] . '_restrict_filesize', $field['options'] );
1015
1016
			if ( ! empty( $limit_size ) ) {
1017
				if ( false !== stripos( $limit_size, 'GB' ) ) {
1018
					$limit_size = (float) trim( str_ireplace( 'GB', '', $limit_size ) );
1019
					$limit_size = $limit_size * 1025 * 1025 * 1025;
1020
					// convert to MB to KB to B
1021
				} elseif ( false !== stripos( $limit_size, 'MB' ) ) {
1022
					$limit_size = (float) trim( str_ireplace( 'MB', '', $limit_size ) );
1023
					$limit_size = $limit_size * 1025 * 1025;
1024
					// convert to KB to B
1025
				} elseif ( false !== stripos( $limit_size, 'KB' ) ) {
1026
					$limit_size  = (float) trim( str_ireplace( 'KB', '', $limit_size ) );
1027
					$limit_size *= 1025;
1028
					// convert to B
1029
				} elseif ( false !== stripos( $limit_size, 'B' ) ) {
1030
					$limit_size = (float) trim( str_ireplace( 'B', '', $limit_size ) );
1031
				} else {
1032
					$limit_size = wp_max_upload_size();
1033
				}
1034
1035
				if ( 0 < $limit_size && $limit_size < $file['size'] ) {
1036
					$error = __( 'File size too large, max size is %s', 'pods' );
1037
					$error = sprintf( $error, pods_v( $field['type'] . '_restrict_filesize', $field['options'] ) );
1038
1039
					pods_error( '<div style="color:#FF0000">Error: ' . $error . '</div>' );
1040
				}
1041
			}//end if
1042
1043
			$limit_file_type = pods_v( $field['type'] . '_type', $field['options'], 'images' );
1044
1045
			if ( 'images' === $limit_file_type ) {
1046
				$limit_types = 'jpg,jpeg,png,gif';
1047
			} elseif ( 'video' === $limit_file_type ) {
1048
				$limit_types = 'mpg,mov,flv,mp4';
1049
			} elseif ( 'audio' === $limit_file_type ) {
1050
				$limit_types = 'mp3,m4a,wav,wma';
1051
			} elseif ( 'text' === $limit_file_type ) {
1052
				$limit_types = 'txt,rtx,csv,tsv';
1053
			} elseif ( 'any' === $limit_file_type ) {
1054
				$limit_types = '';
1055
			} else {
1056
				$limit_types = pods_v( $field['type'] . '_allowed_extensions', $field['options'], '', true );
1057
			}
1058
1059
			$limit_types = trim(
1060
				str_replace(
1061
					array( ' ', '.', "\n", "\t", ';' ), array(
1062
						'',
1063
						',',
1064
						',',
1065
						',',
1066
					), $limit_types
1067
				), ','
1068
			);
1069
1070
			$mime_types = wp_get_mime_types();
1071
1072
			if ( in_array( $limit_file_type, array( 'images', 'audio', 'video' ), true ) ) {
1073
				$new_limit_types = array();
1074
1075
				foreach ( $mime_types as $type => $mime ) {
1076
					if ( 0 === strpos( $mime, $limit_file_type ) ) {
1077
						$type = explode( '|', $type );
1078
1079
						$new_limit_types = array_merge( $new_limit_types, $type );
1080
					}
1081
				}
1082
1083
				if ( ! empty( $new_limit_types ) ) {
1084
					$limit_types = implode( ',', $new_limit_types );
1085
				}
1086
			} elseif ( 'any' !== $limit_file_type ) {
1087
				$new_limit_types = array();
1088
1089
				$limit_types = explode( ',', $limit_types );
1090
1091
				foreach ( $limit_types as $k => $limit_type ) {
1092
					$found = false;
1093
1094 View Code Duplication
					foreach ( $mime_types as $type => $mime ) {
1095
						if ( 0 === strpos( $mime, $limit_type ) ) {
1096
							$type = explode( '|', $type );
1097
1098
							foreach ( $type as $t ) {
1099
								if ( ! in_array( $t, $new_limit_types, true ) ) {
1100
									$new_limit_types[] = $t;
1101
								}
1102
							}
1103
1104
							$found = true;
1105
						}
1106
					}
1107
1108
					if ( ! $found ) {
1109
						$new_limit_types[] = $limit_type;
1110
					}
1111
				}//end foreach
1112
1113
				if ( ! empty( $new_limit_types ) ) {
1114
					$limit_types = implode( ',', $new_limit_types );
1115
				}
1116
			}//end if
1117
1118
			$limit_types = explode( ',', $limit_types );
1119
1120
			$limit_types = array_filter( array_unique( $limit_types ) );
1121
1122
			if ( ! empty( $limit_types ) ) {
1123
				$ok = false;
1124
1125
				foreach ( $limit_types as $limit_type ) {
1126
					$limit_type = '.' . trim( $limit_type, ' .' );
1127
1128
					$pos = ( strlen( $file['name'] ) - strlen( $limit_type ) );
1129
1130
					if ( stripos( $file['name'], $limit_type ) === $pos ) {
1131
						$ok = true;
1132
1133
						break;
1134
					}
1135
				}
1136
1137
				if ( false === $ok ) {
1138
					$error = __( 'File type not allowed, please use one of the following: %s', 'pods' );
1139
					$error = sprintf( $error, '.' . implode( ', .', $limit_types ) );
1140
1141
					pods_error( '<div style="color:#FF0000">Error: ' . $error . '</div>' );
1142
				}
1143
			}//end if
1144
1145
			$custom_handler = apply_filters( 'pods_upload_handle', null, 'Filedata', $params->post_id, $params, $field );
1146
1147
			if ( null === $custom_handler ) {
1148
				$attachment_id = media_handle_upload( 'Filedata', $params->post_id );
1149
1150
				if ( is_object( $attachment_id ) ) {
1151
					$errors = array();
1152
1153
					foreach ( $attachment_id->errors['upload_error'] as $error_code => $error_message ) {
1154
						$errors[] = '[' . $error_code . '] ' . $error_message;
1155
					}
1156
1157
					pods_error( '<div style="color:#FF0000">Error: ' . implode( '</div><div>', $errors ) . '</div>' );
1158
				} else {
1159
					$attachment = get_post( $attachment_id, ARRAY_A );
1160
1161
					$attachment['filename'] = basename( $attachment['guid'] );
1162
1163
					$thumb = wp_get_attachment_image_src( $attachment['ID'], 'thumbnail', true );
1164
1165
					$attachment['thumbnail'] = '';
1166
1167
					if ( ! empty( $thumb[0] ) ) {
1168
						$attachment['thumbnail'] = $thumb[0];
1169
					}
1170
1171
					$attachment['link']      = get_permalink( $attachment['ID'] );
1172
					$attachment['edit_link'] = get_edit_post_link( $attachment['ID'] );
1173
					$attachment['download']  = wp_get_attachment_url( $attachment['ID'] );
1174
1175
					$attachment = apply_filters( 'pods_upload_attachment', $attachment, $params->post_id );
1176
1177
					wp_send_json( $attachment );
1178
				}//end if
1179
			}//end if
1180
		}//end if
1181
1182
		die();
1183
		// KBAI!
1184
	}
1185
1186
}
1187