image.php (18674B)
1 <?php 2 namespace Elementor; 3 4 if ( ! defined( 'ABSPATH' ) ) { 5 exit; // Exit if accessed directly. 6 } 7 8 use Elementor\Core\Kits\Documents\Tabs\Global_Colors; 9 use Elementor\Core\Kits\Documents\Tabs\Global_Typography; 10 11 /** 12 * Elementor image widget. 13 * 14 * Elementor widget that displays an image into the page. 15 * 16 * @since 1.0.0 17 */ 18 class Widget_Image extends Widget_Base { 19 20 /** 21 * Get widget name. 22 * 23 * Retrieve image widget name. 24 * 25 * @since 1.0.0 26 * @access public 27 * 28 * @return string Widget name. 29 */ 30 public function get_name() { 31 return 'image'; 32 } 33 34 /** 35 * Get widget title. 36 * 37 * Retrieve image widget title. 38 * 39 * @since 1.0.0 40 * @access public 41 * 42 * @return string Widget title. 43 */ 44 public function get_title() { 45 return esc_html__( 'Image', 'elementor' ); 46 } 47 48 /** 49 * Get widget icon. 50 * 51 * Retrieve image widget icon. 52 * 53 * @since 1.0.0 54 * @access public 55 * 56 * @return string Widget icon. 57 */ 58 public function get_icon() { 59 return 'eicon-image'; 60 } 61 62 /** 63 * Get widget categories. 64 * 65 * Retrieve the list of categories the image widget belongs to. 66 * 67 * Used to determine where to display the widget in the editor. 68 * 69 * @since 2.0.0 70 * @access public 71 * 72 * @return array Widget categories. 73 */ 74 public function get_categories() { 75 return [ 'basic' ]; 76 } 77 78 /** 79 * Get widget keywords. 80 * 81 * Retrieve the list of keywords the widget belongs to. 82 * 83 * @since 2.1.0 84 * @access public 85 * 86 * @return array Widget keywords. 87 */ 88 public function get_keywords() { 89 return [ 'image', 'photo', 'visual' ]; 90 } 91 92 /** 93 * Register image widget controls. 94 * 95 * Adds different input fields to allow the user to change and customize the widget settings. 96 * 97 * @since 3.1.0 98 * @access protected 99 */ 100 protected function register_controls() { 101 $this->start_controls_section( 102 'section_image', 103 [ 104 'label' => esc_html__( 'Image', 'elementor' ), 105 ] 106 ); 107 108 $this->add_control( 109 'image', 110 [ 111 'label' => esc_html__( 'Choose Image', 'elementor' ), 112 'type' => Controls_Manager::MEDIA, 113 'dynamic' => [ 114 'active' => true, 115 ], 116 'default' => [ 117 'url' => Utils::get_placeholder_image_src(), 118 ], 119 ] 120 ); 121 122 $this->add_group_control( 123 Group_Control_Image_Size::get_type(), 124 [ 125 'name' => 'image', // Usage: `{name}_size` and `{name}_custom_dimension`, in this case `image_size` and `image_custom_dimension`. 126 'default' => 'large', 127 'separator' => 'none', 128 ] 129 ); 130 131 $this->add_responsive_control( 132 'align', 133 [ 134 'label' => esc_html__( 'Alignment', 'elementor' ), 135 'type' => Controls_Manager::CHOOSE, 136 'options' => [ 137 'left' => [ 138 'title' => esc_html__( 'Left', 'elementor' ), 139 'icon' => 'eicon-text-align-left', 140 ], 141 'center' => [ 142 'title' => esc_html__( 'Center', 'elementor' ), 143 'icon' => 'eicon-text-align-center', 144 ], 145 'right' => [ 146 'title' => esc_html__( 'Right', 'elementor' ), 147 'icon' => 'eicon-text-align-right', 148 ], 149 ], 150 'selectors' => [ 151 '{{WRAPPER}}' => 'text-align: {{VALUE}};', 152 ], 153 ] 154 ); 155 156 $this->add_control( 157 'caption_source', 158 [ 159 'label' => esc_html__( 'Caption', 'elementor' ), 160 'type' => Controls_Manager::SELECT, 161 'options' => [ 162 'none' => esc_html__( 'None', 'elementor' ), 163 'attachment' => esc_html__( 'Attachment Caption', 'elementor' ), 164 'custom' => esc_html__( 'Custom Caption', 'elementor' ), 165 ], 166 'default' => 'none', 167 ] 168 ); 169 170 $this->add_control( 171 'caption', 172 [ 173 'label' => esc_html__( 'Custom Caption', 'elementor' ), 174 'type' => Controls_Manager::TEXT, 175 'default' => '', 176 'placeholder' => esc_html__( 'Enter your image caption', 'elementor' ), 177 'condition' => [ 178 'caption_source' => 'custom', 179 ], 180 'dynamic' => [ 181 'active' => true, 182 ], 183 ] 184 ); 185 186 $this->add_control( 187 'link_to', 188 [ 189 'label' => esc_html__( 'Link', 'elementor' ), 190 'type' => Controls_Manager::SELECT, 191 'default' => 'none', 192 'options' => [ 193 'none' => esc_html__( 'None', 'elementor' ), 194 'file' => esc_html__( 'Media File', 'elementor' ), 195 'custom' => esc_html__( 'Custom URL', 'elementor' ), 196 ], 197 ] 198 ); 199 200 $this->add_control( 201 'link', 202 [ 203 'label' => esc_html__( 'Link', 'elementor' ), 204 'type' => Controls_Manager::URL, 205 'dynamic' => [ 206 'active' => true, 207 ], 208 'placeholder' => esc_html__( 'https://your-link.com', 'elementor' ), 209 'condition' => [ 210 'link_to' => 'custom', 211 ], 212 'show_label' => false, 213 ] 214 ); 215 216 $this->add_control( 217 'open_lightbox', 218 [ 219 'label' => esc_html__( 'Lightbox', 'elementor' ), 220 'type' => Controls_Manager::SELECT, 221 'default' => 'default', 222 'options' => [ 223 'default' => esc_html__( 'Default', 'elementor' ), 224 'yes' => esc_html__( 'Yes', 'elementor' ), 225 'no' => esc_html__( 'No', 'elementor' ), 226 ], 227 'condition' => [ 228 'link_to' => 'file', 229 ], 230 ] 231 ); 232 233 $this->add_control( 234 'view', 235 [ 236 'label' => esc_html__( 'View', 'elementor' ), 237 'type' => Controls_Manager::HIDDEN, 238 'default' => 'traditional', 239 ] 240 ); 241 242 $this->end_controls_section(); 243 244 $this->start_controls_section( 245 'section_style_image', 246 [ 247 'label' => esc_html__( 'Image', 'elementor' ), 248 'tab' => Controls_Manager::TAB_STYLE, 249 ] 250 ); 251 252 $this->add_responsive_control( 253 'width', 254 [ 255 'label' => esc_html__( 'Width', 'elementor' ), 256 'type' => Controls_Manager::SLIDER, 257 'default' => [ 258 'unit' => '%', 259 ], 260 'tablet_default' => [ 261 'unit' => '%', 262 ], 263 'mobile_default' => [ 264 'unit' => '%', 265 ], 266 'size_units' => [ '%', 'px', 'vw' ], 267 'range' => [ 268 '%' => [ 269 'min' => 1, 270 'max' => 100, 271 ], 272 'px' => [ 273 'min' => 1, 274 'max' => 1000, 275 ], 276 'vw' => [ 277 'min' => 1, 278 'max' => 100, 279 ], 280 ], 281 'selectors' => [ 282 '{{WRAPPER}} img' => 'width: {{SIZE}}{{UNIT}};', 283 ], 284 ] 285 ); 286 287 $this->add_responsive_control( 288 'space', 289 [ 290 'label' => esc_html__( 'Max Width', 'elementor' ), 291 'type' => Controls_Manager::SLIDER, 292 'default' => [ 293 'unit' => '%', 294 ], 295 'tablet_default' => [ 296 'unit' => '%', 297 ], 298 'mobile_default' => [ 299 'unit' => '%', 300 ], 301 'size_units' => [ '%', 'px', 'vw' ], 302 'range' => [ 303 '%' => [ 304 'min' => 1, 305 'max' => 100, 306 ], 307 'px' => [ 308 'min' => 1, 309 'max' => 1000, 310 ], 311 'vw' => [ 312 'min' => 1, 313 'max' => 100, 314 ], 315 ], 316 'selectors' => [ 317 '{{WRAPPER}} img' => 'max-width: {{SIZE}}{{UNIT}};', 318 ], 319 ] 320 ); 321 322 $this->add_responsive_control( 323 'height', 324 [ 325 'label' => esc_html__( 'Height', 'elementor' ), 326 'type' => Controls_Manager::SLIDER, 327 'default' => [ 328 'unit' => 'px', 329 ], 330 'tablet_default' => [ 331 'unit' => 'px', 332 ], 333 'mobile_default' => [ 334 'unit' => 'px', 335 ], 336 'size_units' => [ 'px', 'vh' ], 337 'range' => [ 338 'px' => [ 339 'min' => 1, 340 'max' => 500, 341 ], 342 'vh' => [ 343 'min' => 1, 344 'max' => 100, 345 ], 346 ], 347 'selectors' => [ 348 '{{WRAPPER}} img' => 'height: {{SIZE}}{{UNIT}};', 349 ], 350 ] 351 ); 352 353 $this->add_responsive_control( 354 'object-fit', 355 [ 356 'label' => esc_html__( 'Object Fit', 'elementor' ), 357 'type' => Controls_Manager::SELECT, 358 'condition' => [ 359 'height[size]!' => '', 360 ], 361 'options' => [ 362 '' => esc_html__( 'Default', 'elementor' ), 363 'fill' => esc_html__( 'Fill', 'elementor' ), 364 'cover' => esc_html__( 'Cover', 'elementor' ), 365 'contain' => esc_html__( 'Contain', 'elementor' ), 366 ], 367 'default' => '', 368 'selectors' => [ 369 '{{WRAPPER}} img' => 'object-fit: {{VALUE}};', 370 ], 371 ] 372 ); 373 374 $this->add_control( 375 'separator_panel_style', 376 [ 377 'type' => Controls_Manager::DIVIDER, 378 'style' => 'thick', 379 ] 380 ); 381 382 $this->start_controls_tabs( 'image_effects' ); 383 384 $this->start_controls_tab( 'normal', 385 [ 386 'label' => esc_html__( 'Normal', 'elementor' ), 387 ] 388 ); 389 390 $this->add_control( 391 'opacity', 392 [ 393 'label' => esc_html__( 'Opacity', 'elementor' ), 394 'type' => Controls_Manager::SLIDER, 395 'range' => [ 396 'px' => [ 397 'max' => 1, 398 'min' => 0.10, 399 'step' => 0.01, 400 ], 401 ], 402 'selectors' => [ 403 '{{WRAPPER}} img' => 'opacity: {{SIZE}};', 404 ], 405 ] 406 ); 407 408 $this->add_group_control( 409 Group_Control_Css_Filter::get_type(), 410 [ 411 'name' => 'css_filters', 412 'selector' => '{{WRAPPER}} img', 413 ] 414 ); 415 416 $this->end_controls_tab(); 417 418 $this->start_controls_tab( 'hover', 419 [ 420 'label' => esc_html__( 'Hover', 'elementor' ), 421 ] 422 ); 423 424 $this->add_control( 425 'opacity_hover', 426 [ 427 'label' => esc_html__( 'Opacity', 'elementor' ), 428 'type' => Controls_Manager::SLIDER, 429 'range' => [ 430 'px' => [ 431 'max' => 1, 432 'min' => 0.10, 433 'step' => 0.01, 434 ], 435 ], 436 'selectors' => [ 437 '{{WRAPPER}}:hover img' => 'opacity: {{SIZE}};', 438 ], 439 ] 440 ); 441 442 $this->add_group_control( 443 Group_Control_Css_Filter::get_type(), 444 [ 445 'name' => 'css_filters_hover', 446 'selector' => '{{WRAPPER}}:hover img', 447 ] 448 ); 449 450 $this->add_control( 451 'background_hover_transition', 452 [ 453 'label' => esc_html__( 'Transition Duration', 'elementor' ), 454 'type' => Controls_Manager::SLIDER, 455 'range' => [ 456 'px' => [ 457 'max' => 3, 458 'step' => 0.1, 459 ], 460 ], 461 'selectors' => [ 462 '{{WRAPPER}} img' => 'transition-duration: {{SIZE}}s', 463 ], 464 ] 465 ); 466 467 $this->add_control( 468 'hover_animation', 469 [ 470 'label' => esc_html__( 'Hover Animation', 'elementor' ), 471 'type' => Controls_Manager::HOVER_ANIMATION, 472 ] 473 ); 474 475 $this->end_controls_tab(); 476 477 $this->end_controls_tabs(); 478 479 $this->add_group_control( 480 Group_Control_Border::get_type(), 481 [ 482 'name' => 'image_border', 483 'selector' => '{{WRAPPER}} img', 484 'separator' => 'before', 485 ] 486 ); 487 488 $this->add_responsive_control( 489 'image_border_radius', 490 [ 491 'label' => esc_html__( 'Border Radius', 'elementor' ), 492 'type' => Controls_Manager::DIMENSIONS, 493 'size_units' => [ 'px', '%' ], 494 'selectors' => [ 495 '{{WRAPPER}} img' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', 496 ], 497 ] 498 ); 499 500 $this->add_group_control( 501 Group_Control_Box_Shadow::get_type(), 502 [ 503 'name' => 'image_box_shadow', 504 'exclude' => [ 505 'box_shadow_position', 506 ], 507 'selector' => '{{WRAPPER}} img', 508 ] 509 ); 510 511 $this->end_controls_section(); 512 513 $this->start_controls_section( 514 'section_style_caption', 515 [ 516 'label' => esc_html__( 'Caption', 'elementor' ), 517 'tab' => Controls_Manager::TAB_STYLE, 518 'condition' => [ 519 'caption_source!' => 'none', 520 ], 521 ] 522 ); 523 524 $this->add_control( 525 'caption_align', 526 [ 527 'label' => esc_html__( 'Alignment', 'elementor' ), 528 'type' => Controls_Manager::CHOOSE, 529 'options' => [ 530 'left' => [ 531 'title' => esc_html__( 'Left', 'elementor' ), 532 'icon' => 'eicon-text-align-left', 533 ], 534 'center' => [ 535 'title' => esc_html__( 'Center', 'elementor' ), 536 'icon' => 'eicon-text-align-center', 537 ], 538 'right' => [ 539 'title' => esc_html__( 'Right', 'elementor' ), 540 'icon' => 'eicon-text-align-right', 541 ], 542 'justify' => [ 543 'title' => esc_html__( 'Justified', 'elementor' ), 544 'icon' => 'eicon-text-align-justify', 545 ], 546 ], 547 'default' => '', 548 'selectors' => [ 549 '{{WRAPPER}} .widget-image-caption' => 'text-align: {{VALUE}};', 550 ], 551 ] 552 ); 553 554 $this->add_control( 555 'text_color', 556 [ 557 'label' => esc_html__( 'Text Color', 'elementor' ), 558 'type' => Controls_Manager::COLOR, 559 'default' => '', 560 'selectors' => [ 561 '{{WRAPPER}} .widget-image-caption' => 'color: {{VALUE}};', 562 ], 563 'global' => [ 564 'default' => Global_Colors::COLOR_TEXT, 565 ], 566 ] 567 ); 568 569 $this->add_control( 570 'caption_background_color', 571 [ 572 'label' => esc_html__( 'Background Color', 'elementor' ), 573 'type' => Controls_Manager::COLOR, 574 'selectors' => [ 575 '{{WRAPPER}} .widget-image-caption' => 'background-color: {{VALUE}};', 576 ], 577 ] 578 ); 579 580 $this->add_group_control( 581 Group_Control_Typography::get_type(), 582 [ 583 'name' => 'caption_typography', 584 'selector' => '{{WRAPPER}} .widget-image-caption', 585 'global' => [ 586 'default' => Global_Typography::TYPOGRAPHY_TEXT, 587 ], 588 ] 589 ); 590 591 $this->add_group_control( 592 Group_Control_Text_Shadow::get_type(), 593 [ 594 'name' => 'caption_text_shadow', 595 'selector' => '{{WRAPPER}} .widget-image-caption', 596 ] 597 ); 598 599 $this->add_responsive_control( 600 'caption_space', 601 [ 602 'label' => esc_html__( 'Spacing', 'elementor' ), 603 'type' => Controls_Manager::SLIDER, 604 'range' => [ 605 'px' => [ 606 'min' => 0, 607 'max' => 100, 608 ], 609 ], 610 'selectors' => [ 611 '{{WRAPPER}} .widget-image-caption' => 'margin-top: {{SIZE}}{{UNIT}};', 612 ], 613 ] 614 ); 615 616 $this->end_controls_section(); 617 } 618 619 /** 620 * Check if the current widget has caption 621 * 622 * @access private 623 * @since 2.3.0 624 * 625 * @param array $settings 626 * 627 * @return boolean 628 */ 629 private function has_caption( $settings ) { 630 return ( ! empty( $settings['caption_source'] ) && 'none' !== $settings['caption_source'] ); 631 } 632 633 /** 634 * Get the caption for current widget. 635 * 636 * @access private 637 * @since 2.3.0 638 * @param $settings 639 * 640 * @return string 641 */ 642 private function get_caption( $settings ) { 643 $caption = ''; 644 if ( ! empty( $settings['caption_source'] ) ) { 645 switch ( $settings['caption_source'] ) { 646 case 'attachment': 647 $caption = wp_get_attachment_caption( $settings['image']['id'] ); 648 break; 649 case 'custom': 650 $caption = ! Utils::is_empty( $settings['caption'] ) ? $settings['caption'] : ''; 651 } 652 } 653 return $caption; 654 } 655 656 /** 657 * Render image widget output on the frontend. 658 * 659 * Written in PHP and used to generate the final HTML. 660 * 661 * @since 1.0.0 662 * @access protected 663 */ 664 protected function render() { 665 $settings = $this->get_settings_for_display(); 666 667 if ( empty( $settings['image']['url'] ) ) { 668 return; 669 } 670 671 if ( ! Plugin::$instance->experiments->is_feature_active( 'e_dom_optimization' ) ) { 672 $this->add_render_attribute( 'wrapper', 'class', 'elementor-image' ); 673 } 674 675 $has_caption = $this->has_caption( $settings ); 676 677 $link = $this->get_link_url( $settings ); 678 679 if ( $link ) { 680 $this->add_link_attributes( 'link', $link ); 681 682 if ( Plugin::$instance->editor->is_edit_mode() ) { 683 $this->add_render_attribute( 'link', [ 684 'class' => 'elementor-clickable', 685 ] ); 686 } 687 688 if ( 'custom' !== $settings['link_to'] ) { 689 $this->add_lightbox_data_attributes( 'link', $settings['image']['id'], $settings['open_lightbox'] ); 690 } 691 } ?> 692 <?php if ( ! Plugin::$instance->experiments->is_feature_active( 'e_dom_optimization' ) ) { ?> 693 <div <?php $this->print_render_attribute_string( 'wrapper' ); ?>> 694 <?php } ?> 695 <?php if ( $has_caption ) : ?> 696 <figure class="wp-caption"> 697 <?php endif; ?> 698 <?php if ( $link ) : ?> 699 <a <?php $this->print_render_attribute_string( 'link' ); ?>> 700 <?php endif; ?> 701 <?php Group_Control_Image_Size::print_attachment_image_html( $settings ); ?> 702 <?php if ( $link ) : ?> 703 </a> 704 <?php endif; ?> 705 <?php if ( $has_caption ) : ?> 706 <figcaption class="widget-image-caption wp-caption-text"><?php 707 echo wp_kses_post( $this->get_caption( $settings ) ); 708 ?></figcaption> 709 <?php endif; ?> 710 <?php if ( $has_caption ) : ?> 711 </figure> 712 <?php endif; ?> 713 <?php if ( ! Plugin::$instance->experiments->is_feature_active( 'e_dom_optimization' ) ) { ?> 714 </div> 715 <?php } ?> 716 <?php 717 } 718 719 /** 720 * Render image widget output in the editor. 721 * 722 * Written as a Backbone JavaScript template and used to generate the live preview. 723 * 724 * @since 2.9.0 725 * @access protected 726 */ 727 protected function content_template() { 728 ?> 729 <# if ( settings.image.url ) { 730 var image = { 731 id: settings.image.id, 732 url: settings.image.url, 733 size: settings.image_size, 734 dimension: settings.image_custom_dimension, 735 model: view.getEditModel() 736 }; 737 738 var image_url = elementor.imagesManager.getImageUrl( image ); 739 740 if ( ! image_url ) { 741 return; 742 } 743 744 var hasCaption = function() { 745 if( ! settings.caption_source || 'none' === settings.caption_source ) { 746 return false; 747 } 748 return true; 749 } 750 751 var ensureAttachmentData = function( id ) { 752 if ( 'undefined' === typeof wp.media.attachment( id ).get( 'caption' ) ) { 753 wp.media.attachment( id ).fetch().then( function( data ) { 754 view.render(); 755 } ); 756 } 757 } 758 759 var getAttachmentCaption = function( id ) { 760 if ( ! id ) { 761 return ''; 762 } 763 ensureAttachmentData( id ); 764 return wp.media.attachment( id ).get( 'caption' ); 765 } 766 767 var getCaption = function() { 768 if ( ! hasCaption() ) { 769 return ''; 770 } 771 return 'custom' === settings.caption_source ? settings.caption : getAttachmentCaption( settings.image.id ); 772 } 773 774 var link_url; 775 776 if ( 'custom' === settings.link_to ) { 777 link_url = settings.link.url; 778 } 779 780 if ( 'file' === settings.link_to ) { 781 link_url = settings.image.url; 782 } 783 784 <?php if ( ! Plugin::$instance->experiments->is_feature_active( 'e_dom_optimization' ) ) { ?> 785 #><div class="elementor-image{{ settings.shape ? ' elementor-image-shape-' + settings.shape : '' }}"><# 786 <?php } ?> 787 788 var imgClass = ''; 789 790 if ( '' !== settings.hover_animation ) { 791 imgClass = 'elementor-animation-' + settings.hover_animation; 792 } 793 794 if ( hasCaption() ) { 795 #><figure class="wp-caption"><# 796 } 797 798 if ( link_url ) { 799 #><a class="elementor-clickable" data-elementor-open-lightbox="{{ settings.open_lightbox }}" href="{{ link_url }}"><# 800 } 801 #><img src="{{ image_url }}" class="{{ imgClass }}" /><# 802 803 if ( link_url ) { 804 #></a><# 805 } 806 807 if ( hasCaption() ) { 808 #><figcaption class="widget-image-caption wp-caption-text">{{{ getCaption() }}}</figcaption><# 809 } 810 811 if ( hasCaption() ) { 812 #></figure><# 813 } 814 815 <?php if ( ! Plugin::$instance->experiments->is_feature_active( 'e_dom_optimization' ) ) { ?> 816 #></div><# 817 <?php } ?> 818 819 } #> 820 <?php 821 } 822 823 /** 824 * Retrieve image widget link URL. 825 * 826 * @since 1.0.0 827 * @access private 828 * 829 * @param array $settings 830 * 831 * @return array|string|false An array/string containing the link URL, or false if no link. 832 */ 833 private function get_link_url( $settings ) { 834 if ( 'none' === $settings['link_to'] ) { 835 return false; 836 } 837 838 if ( 'custom' === $settings['link_to'] ) { 839 if ( empty( $settings['link']['url'] ) ) { 840 return false; 841 } 842 843 return $settings['link']; 844 } 845 846 return [ 847 'url' => $settings['image']['url'], 848 ]; 849 } 850 }