Constants
18 hours ago
Accordion.php
18 hours ago
Alert.php
18 hours ago
AttachmentCard.php
18 hours ago
Avatar.php
18 hours ago
Badge.php
18 hours ago
BaseComponent.php
18 hours ago
Button.php
18 hours ago
ConfirmationModal.php
18 hours ago
CourseFilter.php
18 hours ago
DateFilter.php
18 hours ago
DropdownFilter.php
18 hours ago
EmptyState.php
18 hours ago
FileUploader.php
18 hours ago
InputField.php
18 hours ago
Modal.php
18 hours ago
Nav.php
18 hours ago
Pagination.php
18 hours ago
Popover.php
18 hours ago
PreviewTrigger.php
18 hours ago
Progress.php
18 hours ago
SearchFilter.php
18 hours ago
Sorting.php
18 hours ago
StarRating.php
18 hours ago
StarRatingInput.php
18 hours ago
StatusSelect.php
18 hours ago
SvgIcon.php
18 hours ago
Table.php
18 hours ago
Tabs.php
18 hours ago
Tooltip.php
18 hours ago
WPEditor.php
18 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 |