PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 4.0.0
Tutor LMS – eLearning and online course solution v4.0.0
4.0.0 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / components / FileUploader.php
tutor / components Last commit date
Constants 17 hours ago Accordion.php 17 hours ago Alert.php 17 hours ago AttachmentCard.php 17 hours ago Avatar.php 17 hours ago Badge.php 17 hours ago BaseComponent.php 17 hours ago Button.php 17 hours ago ConfirmationModal.php 17 hours ago CourseFilter.php 17 hours ago DateFilter.php 17 hours ago DropdownFilter.php 17 hours ago EmptyState.php 17 hours ago FileUploader.php 17 hours ago InputField.php 17 hours ago Modal.php 17 hours ago Nav.php 17 hours ago Pagination.php 17 hours ago Popover.php 17 hours ago PreviewTrigger.php 17 hours ago Progress.php 17 hours ago SearchFilter.php 17 hours ago Sorting.php 17 hours ago StarRating.php 17 hours ago StarRatingInput.php 17 hours ago StatusSelect.php 17 hours ago SvgIcon.php 17 hours ago Table.php 17 hours ago Tabs.php 17 hours ago Tooltip.php 17 hours ago WPEditor.php 17 hours ago
FileUploader.php
669 lines
1 <?php
2 /**
3 * FileUploader Component Class.
4 *
5 * @package Tutor\Components
6 * @author Themeum
7 * @link https://themeum.com
8 * @since 4.0.0
9 */
10
11 namespace Tutor\Components;
12
13 defined( 'ABSPATH' ) || exit;
14
15 use Tutor\Components\Constants\Size;
16 use Tutor\Components\Constants\Variant;
17 use TUTOR\Icon;
18 use Tutor\Components\Button;
19 use Tutor\Components\AttachmentCard;
20
21
22 /**
23 * Class FileUploader
24 *
25 * Example Usage (Native Multiple):
26 * FileUploader::make()
27 * ->name( 'course_attachments' )
28 * ->uploader_title( __( 'Upload Assignments', 'tutor' ) )
29 * ->uploader_subtitle( __( 'Support PDF, DOCX (Max 20MB)', 'tutor' ) )
30 * ->accept( '.pdf,.docx' )
31 * ->multiple( true )
32 * ->max_files( 3 )
33 * ->max_size( 20 * 1024 * 1024 )
34 * ->render();
35 *
36 * Example Usage (Native Single):
37 * FileUploader::make()
38 * ->name( 'resume' )
39 * ->accept( '.pdf,.doc' )
40 * ->render();
41 *
42 * Example Usage (WP Media Image):
43 * FileUploader::make()
44 * ->variant( FileUploader::IMAGE_UPLOADER )
45 * ->use_wp_media( true )
46 * ->wp_media_library_type( 'image' )
47 * ->name( 'profile_photo' )
48 * ->render();
49 *
50 * Example Usage (WP Media Multiple Documents):
51 * FileUploader::make()
52 * ->use_wp_media( true )
53 * ->multiple( true )
54 * ->wp_media_library_type( 'application/pdf,application/msword' )
55 * ->name( 'shared_files' )
56 * ->render();
57 *
58 * Example Usage (Native Image):
59 * FileUploader::make()
60 * ->variant( FileUploader::IMAGE_UPLOADER )
61 * ->name( 'cover_photo' )
62 * ->render();
63 *
64 * Example Usage (Custom UI):
65 * FileUploader::make()
66 * ->name( 'custom_upload' )
67 * ->uploader_icon( Icon::RESOURCES )
68 * ->uploader_title( __( 'Resource Center', 'tutor' ) )
69 * ->uploader_subtitle( __( 'Add any relevant documents here', 'tutor' ) )
70 * ->uploader_button_text( __( 'Choose Resources', 'tutor' ) )
71 * ->render();
72 *
73 * @since 4.0.0
74 */
75 class FileUploader extends BaseComponent {
76
77 /**
78 * Variant constants.
79 *
80 * @since 4.0.0
81 */
82 public const FILE_UPLOADER = 'file-uploader';
83 public const IMAGE_UPLOADER = 'image-uploader';
84
85
86 /**
87 * File uploader accept attribute.
88 *
89 * @since 4.0.0
90 *
91 * @var string
92 */
93 protected $accept = '.pdf,.doc,.docx,.jpg,.jpeg,.png';
94
95 /**
96 * File uploader max size.
97 *
98 * @since 4.0.0
99 *
100 * @var int
101 */
102 protected $max_size = null;
103
104 /**
105 * File uploader max files.
106 *
107 * @since 4.0.0
108 *
109 * @var int|null
110 */
111 protected $max_files = null;
112
113 /**
114 * File uploader icon.
115 *
116 * @since 4.0.0
117 *
118 * @var string
119 */
120 protected $uploader_icon = Icon::UPLOAD_FILE;
121
122 /**
123 * File uploader title.
124 *
125 * @since 4.0.0
126 *
127 * @var string
128 */
129 protected $uploader_title = '';
130
131 /**
132 * File uploader subtitle.
133 *
134 * @since 4.0.0
135 *
136 * @var string
137 */
138 protected $uploader_subtitle = '';
139
140 /**
141 * File uploader button text.
142 *
143 * @since 4.0.0
144 *
145 * @var string
146 */
147 protected $uploader_button_text = '';
148
149 /**
150 * Component variant.
151 *
152 * @since 4.0.0
153 *
154 * @var string
155 */
156 protected $variant = self::FILE_UPLOADER;
157
158 /**
159 * Whether to use WordPress media library instead of native file input.
160 *
161 * @since 4.0.0
162 *
163 * @var bool
164 */
165 protected $use_wp_media = false;
166
167 /**
168 * Title for WordPress media modal.
169 *
170 * @since 4.0.0
171 *
172 * @var string
173 */
174 protected $wp_media_title = '';
175
176 /**
177 * Button text for WordPress media modal.
178 *
179 * @since 4.0.0
180 *
181 * @var string
182 */
183 protected $wp_media_button_text = '';
184
185 /**
186 * Library type filter for WordPress media (image, video, audio, application).
187 *
188 * @since 4.0.0
189 *
190 * @var string
191 */
192 protected $wp_media_library_type = '';
193
194 /**
195 * Whether multiple option can be selected in input.
196 *
197 * @since 4.0.0
198 *
199 * @var boolean
200 */
201 protected $multiple = false;
202
203 /**
204 * InputField name attribute.
205 *
206 * @since 4.0.0
207 *
208 * @var string
209 */
210 protected $name = '';
211
212 /**
213 * InputField ID attribute.
214 *
215 * @since 4.0.0
216 *
217 * @var string
218 */
219 protected $id = '';
220
221 /**
222 * Whether input is required.
223 *
224 * @since 4.0.0
225 *
226 * @var bool
227 */
228 protected $required = false;
229
230 /**
231 * InputField value.
232 *
233 * @since 4.0.0
234 *
235 * @var string
236 */
237 protected $value = '';
238
239 /**
240 * Upload icon size.
241 *
242 * @since 4.0.0
243 *
244 * @var integer
245 */
246 protected $upload_icon_size = 24;
247
248 /**
249 * Set uploader accept attribute.
250 *
251 * Common types: .pdf, .doc, .docx, .jpg, .jpeg, .png
252 * For WP Media: image, video, audio, application
253 *
254 * @since 4.0.0
255 *
256 * @param string $accept Accept attribute.
257 *
258 * @return $this
259 */
260 public function accept( $accept ) {
261 $this->accept = $accept;
262
263 return $this;
264 }
265
266 /**
267 * Set uploader max size.
268 *
269 * @since 4.0.0
270 *
271 * @param int $max_size Max size in bytes.
272 *
273 * @return $this
274 */
275 public function max_size( $max_size = null ) {
276 if ( null === $max_size ) {
277 $max_size = wp_max_upload_size();
278 }
279 $this->max_size = $max_size;
280
281 return $this;
282 }
283
284 /**
285 * Set uploader max files.
286 *
287 * @since 4.0.0
288 *
289 * @param int|null $max_files Maximum number of selectable files.
290 *
291 * @return $this
292 */
293 public function max_files( $max_files = null ) {
294 $this->max_files = null !== $max_files ? (int) $max_files : null;
295
296 return $this;
297 }
298
299 /**
300 * Set uploader icon.
301 *
302 * @since 4.0.0
303 *
304 * @param string $icon Icon name.
305 *
306 * @return $this
307 */
308 public function uploader_icon( $icon ) {
309 $this->uploader_icon = $icon;
310
311 return $this;
312 }
313
314 /**
315 * Set uploader icon size.
316 *
317 * @since 4.0.0
318 *
319 * @param int $size Icon size.
320 *
321 * @return $this
322 */
323 public function uploader_icon_size( $size ) {
324 $this->upload_icon_size = $size;
325
326 return $this;
327 }
328
329 /**
330 * Set uploader title.
331 *
332 * @since 4.0.0
333 *
334 * @param string $title Title text.
335 *
336 * @return $this
337 */
338 public function uploader_title( $title ) {
339 $this->uploader_title = $title;
340
341 return $this;
342 }
343
344 /**
345 * Set uploader subtitle.
346 *
347 * @since 4.0.0
348 *
349 * @param string $subtitle Subtitle text.
350 *
351 * @return $this
352 */
353 public function uploader_subtitle( $subtitle ) {
354 $this->uploader_subtitle = $subtitle;
355
356 return $this;
357 }
358
359 /**
360 * Set uploader button text.
361 *
362 * @since 4.0.0
363 *
364 * @param string $button_text Button text.
365 *
366 * @return $this
367 */
368 public function uploader_button_text( $button_text ) {
369 $this->uploader_button_text = $button_text;
370
371 return $this;
372 }
373
374 /**
375 * Set component variant.
376 *
377 * @since 4.0.0
378 *
379 * @param string $variant Component variant (file-uploader|image-uploader).
380 *
381 * @return $this
382 */
383 public function variant( $variant ) {
384 $this->variant = $variant;
385
386 return $this;
387 }
388
389 /**
390 * Set use WordPress media library.
391 *
392 * @since 4.0.0
393 *
394 * @param bool $use_wp_media Use WP media library.
395 *
396 * @return $this
397 */
398 public function use_wp_media( $use_wp_media = true ) {
399 $this->use_wp_media = (bool) $use_wp_media;
400
401 return $this;
402 }
403
404 /**
405 * Set WP media title.
406 *
407 * @since 4.0.0
408 *
409 * @param string $wp_media_title WP media title.
410 *
411 * @return $this
412 */
413 public function wp_media_title( $wp_media_title ) {
414 $this->wp_media_title = $wp_media_title;
415
416 return $this;
417 }
418
419 /**
420 * Set WP media button text.
421 *
422 * @since 4.0.0
423 *
424 * @param string $wp_media_button_text WP media button text.
425 *
426 * @return $this
427 */
428 public function wp_media_button_text( $wp_media_button_text ) {
429 $this->wp_media_button_text = $wp_media_button_text;
430
431 return $this;
432 }
433
434 /**
435 * Set WP media library type.
436 *
437 * Common types: image, video, audio, application, text
438 *
439 * @since 4.0.0
440 *
441 * @param string $wp_media_library_type WP media library type.
442 *
443 * @return $this
444 */
445 public function wp_media_library_type( $wp_media_library_type ) {
446 $this->wp_media_library_type = $wp_media_library_type;
447
448 return $this;
449 }
450
451 /**
452 * Set multiple.
453 *
454 * @since 4.0.0
455 *
456 * @param bool $multiple Multiple.
457 *
458 * @return $this
459 */
460 public function multiple( $multiple = true ) {
461 $this->multiple = (bool) $multiple;
462
463 return $this;
464 }
465
466 /**
467 * Set input name.
468 *
469 * @since 4.0.0
470 *
471 * @param string $name Name.
472 *
473 * @return $this
474 */
475 public function name( $name ) {
476 $this->name = sanitize_key( $name );
477
478 return $this;
479 }
480
481 /**
482 * Set input ID.
483 *
484 * @since 4.0.0
485 *
486 * @param string $id InputField ID.
487 *
488 * @return $this
489 */
490 public function id( $id ) {
491 $this->id = sanitize_key( $id );
492
493 return $this;
494 }
495
496 /**
497 * Set required.
498 *
499 * @since 4.0.0
500 *
501 * @param bool $required Required.
502 *
503 * @return $this
504 */
505 public function required( $required = true ) {
506 $this->required = $required;
507
508 return $this;
509 }
510
511 /**
512 * Set value.
513 *
514 * @since 4.0.0
515 *
516 * @param string $value Value.
517 *
518 * @return $this
519 */
520 public function value( $value ) {
521 $this->value = $value;
522
523 return $this;
524 }
525
526 /**
527 * Get component content
528 *
529 * @return string
530 */
531 public function get(): string {
532 $multiple = $this->multiple;
533 $accept = $this->accept;
534 $max_size = $this->max_size ?? wp_max_upload_size();
535 $max_files = $this->max_files;
536 $icon = $this->uploader_icon;
537 $title = ! empty( $this->uploader_title ) ? $this->uploader_title : __( 'Drop files here or click to upload', 'tutor' );
538 $subtitle = ! empty( $this->uploader_subtitle ) ? $this->uploader_subtitle : '';
539 $button_text = ! empty( $this->uploader_button_text ) ? $this->uploader_button_text : __( 'Select Files', 'tutor' );
540 $on_file_select = $this->attributes['onFileSelect'] ?? 'null';
541 $on_error = $this->attributes['onError'] ?? 'null';
542 $on_file_remove = $this->attributes['onFileRemove'] ?? 'null';
543 $variant = $this->variant;
544 $uploader_attributes = $this->attributes;
545
546 // Remove Alpine specific attributes from HTML attributes.
547 unset( $uploader_attributes['onFileSelect'] );
548 unset( $uploader_attributes['onError'] );
549
550 $this->attributes = $uploader_attributes;
551
552 ob_start();
553 ?>
554 <div
555 class="tutor-file-uploader-wrapper"
556 x-data="tutorFileUploader({
557 multiple: <?php echo $multiple ? 'true' : 'false'; ?>,
558 maxFiles: <?php echo null !== $max_files ? (int) $max_files : 'undefined'; ?>,
559 accept: '<?php echo esc_attr( $accept ); ?>',
560 maxSize: <?php echo (int) $max_size; ?>,
561 onFileSelect: <?php echo esc_js( $on_file_select ); ?>,
562 onFileRemove: <?php echo esc_js( $on_file_remove ); ?>,
563 onError: <?php echo esc_js( $on_error ); ?>,
564 variant: '<?php echo esc_attr( $variant ); ?>',
565 value: values.<?php echo esc_attr( $this->name ); ?>,
566 name: '<?php echo esc_attr( $this->name ); ?>',
567 required: <?php echo is_bool( $this->required ) ? ( $this->required ? 'true' : 'false' ) : "'" . esc_js( $this->required ) . "'"; ?>,
568 useWPMedia: <?php echo $this->use_wp_media ? 'true' : 'false'; ?>,
569 wpMediaTitle: '<?php echo esc_js( $this->wp_media_title ); ?>',
570 wpMediaButtonText: '<?php echo esc_js( $this->wp_media_button_text ); ?>',
571 wpMediaLibraryType: '<?php echo esc_js( $this->wp_media_library_type ); ?>',
572 })"
573 >
574 <template x-if="imagePreview">
575 <div class="tutor-file-preview">
576 <img :src="imagePreview" alt="Preview">
577 <div class="tutor-file-preview-overlay">
578 <div class="tutor-file-preview-actions">
579 <?php
580 Button::make()
581 ->label( __( 'Delete', 'tutor' ) )
582 ->variant( Variant::DESTRUCTIVE )
583 ->size( Size::SMALL )
584 ->attr( 'type', 'button' )
585 ->attr( '@click.stop', 'removeFile()' )
586 ->render();
587
588 Button::make()
589 ->label( __( 'Upload New', 'tutor' ) )
590 ->variant( Variant::PRIMARY )
591 ->size( Size::SMALL )
592 ->attr( 'type', 'button' )
593 ->attr( '@click.stop', 'openFileDialog()' )
594 ->render();
595 ?>
596 </div>
597 </div>
598 </div>
599 </template>
600
601 <template x-if="variant === 'file-uploader' && selectedFiles.length > 0">
602 <div class="tutor-flex tutor-flex-column tutor-gap-5">
603 <div class="tutor-grid tutor-grid-cols-2 tutor-sm-grid-cols-1 tutor-gap-5">
604 <template x-for="(file, index) in selectedFiles" :key="index">
605 <div class="tutor-attachment-card-wrapper">
606 <?php
607 AttachmentCard::make()
608 ->title_attr( 'x-text', 'file.name' )
609 ->meta_attr( 'x-text', 'formatBytes(file.size)' )
610 ->action_attr( '@click.stop', 'removeFile(index)' )
611 ->render();
612 ?>
613 </div>
614 </template>
615 </div>
616 <div x-show="maxFiles > selectedFiles.length" class="tutor-mt-1">
617 <button type="button" class="tutor-btn tutor-btn-primary-soft tutor-sm-w-full" @click="openFileDialog()">
618 <?php $this->multiple ? esc_html_e( 'Upload More Files', 'tutor' ) : esc_html_e( 'Upload Again', 'tutor' ); ?>
619 </button>
620 </div>
621 </div>
622 </template>
623
624 <!-- Upload Area -->
625 <div
626 x-show="!imagePreview && (variant !== 'file-uploader' || selectedFiles.length === 0)"
627 class="tutor-file-uploader"
628 :class="{
629 'tutor-file-uploader-drag-over': isDragOver,
630 'tutor-file-uploader-disabled': isDisabled
631 }"
632 @click="openFileDialog()"
633 @dragover.prevent="handleDragOver($event)"
634 @dragleave.prevent="handleDragLeave($event)"
635 @drop.prevent="handleDrop($event)"
636 <?php echo self::IMAGE_UPLOADER === $variant ? 'data-image-uploader' : ''; ?>
637 >
638 <input
639 type="file"
640 class="tutor-file-uploader-input"
641 :multiple="multiple"
642 :accept="accept"
643 :disabled="isDisabled"
644 x-ref="fileInput"
645 @change="handleFileSelect($event)"
646 name="<?php echo esc_attr( $this->name ); ?>"
647 id="<?php echo esc_attr( ! empty( $this->id ) ? $this->id : $this->name ); ?>"
648 <?php echo $this->get_attributes_string(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
649 >
650 <div class="tutor-file-uploader-icon">
651 <?php SvgIcon::make()->name( $icon )->size( $this->upload_icon_size )->render(); ?>
652 </div>
653 <div class="tutor-file-uploader-content">
654 <p class="tutor-file-uploader-title"><?php echo esc_html( $title ); ?></p>
655 <?php if ( ! empty( $subtitle ) ) : ?>
656 <p class="tutor-file-uploader-subtitle"><?php echo esc_html( $subtitle ); ?></p>
657 <?php endif; ?>
658 </div>
659 <button type="button" class="tutor-btn tutor-btn-primary-soft" :disabled="isDisabled">
660 <?php echo esc_html( $button_text ); ?>
661 </button>
662 </div>
663 </div>
664 <?php
665 $this->component_string = ob_get_clean();
666 return $this->component_string;
667 }
668 }
669