PluginProbe
Elementor Website Builder – more than just a page builder / 3.30.0-beta1
Elementor Website Builder – more than just a page builder v3.30.0-beta1
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / includes / widgets / video.php

video.php in Elementor Website Builder – more than just a page builder 3.30.0-beta1, at includes/widgets/video.php

1,405 lines 33.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor;
3
4 use Elementor\Modules\DynamicTags\Module as TagsModule;
5 use Elementor\Modules\Promotions\Controls\Promotion_Control;
6
7 if ( ! defined( 'ABSPATH' ) ) {
8 exit; // Exit if accessed directly.
9 }
10
11 /**
12 * Elementor video widget.
13 *
14 * Elementor widget that displays a video player.
15 *
16 * @since 1.0.0
17 */
18 class Widget_Video extends Widget_Base {
19
20 /**
21 * Get widget name.
22 *
23 * Retrieve video 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 'video';
32 }
33
34 /**
35 * Get widget title.
36 *
37 * Retrieve video 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__( 'Video', 'elementor' );
46 }
47
48 /**
49 * Get widget icon.
50 *
51 * Retrieve video 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-youtube';
60 }
61
62 /**
63 * Get widget categories.
64 *
65 * Retrieve the list of categories the video 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 [ 'video', 'player', 'embed', 'youtube', 'vimeo', 'dailymotion', 'videopress' ];
90 }
91
92 protected function is_dynamic_content(): bool {
93 return false;
94 }
95
96 /**
97 * Get style dependencies.
98 *
99 * Retrieve the list of style dependencies the widget requires.
100 *
101 * @since 3.24.0
102 * @access public
103 *
104 * @return array Widget style dependencies.
105 */
106 public function get_style_depends(): array {
107 return [ 'widget-video' ];
108 }
109
110 public function has_widget_inner_wrapper(): bool {
111 return ! Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
112 }
113
114 /**
115 * Register video widget controls.
116 *
117 * Adds different input fields to allow the user to change and customize the widget settings.
118 *
119 * @since 3.1.0
120 * @access protected
121 */
122 protected function register_controls() {
123 $this->start_controls_section(
124 'section_video',
125 [
126 'label' => esc_html__( 'Video', 'elementor' ),
127 ]
128 );
129
130 $this->add_control(
131 'video_type',
132 [
133 'label' => esc_html__( 'Source', 'elementor' ),
134 'type' => Controls_Manager::SELECT,
135 'default' => 'youtube',
136 'options' => [
137 'youtube' => esc_html__( 'YouTube', 'elementor' ),
138 'vimeo' => esc_html__( 'Vimeo', 'elementor' ),
139 'dailymotion' => esc_html__( 'Dailymotion', 'elementor' ),
140 'videopress' => esc_html__( 'VideoPress', 'elementor' ),
141 'hosted' => esc_html__( 'Self Hosted', 'elementor' ),
142 ],
143 'frontend_available' => true,
144 ]
145 );
146
147 $this->add_control(
148 'youtube_url',
149 [
150 'label' => esc_html__( 'Link', 'elementor' ),
151 'type' => Controls_Manager::TEXT,
152 'dynamic' => [
153 'active' => true,
154 'categories' => [
155 TagsModule::POST_META_CATEGORY,
156 TagsModule::URL_CATEGORY,
157 ],
158 ],
159 'placeholder' => esc_html__( 'Enter your URL', 'elementor' ) . ' (YouTube)',
160 'default' => 'https://www.youtube.com/watch?v=XHOmBV4js_E',
161 'label_block' => true,
162 'condition' => [
163 'video_type' => 'youtube',
164 ],
165 'ai' => [
166 'active' => false,
167 ],
168 'frontend_available' => true,
169 ]
170 );
171
172 $this->add_control(
173 'vimeo_url',
174 [
175 'label' => esc_html__( 'Link', 'elementor' ),
176 'type' => Controls_Manager::TEXT,
177 'dynamic' => [
178 'active' => true,
179 'categories' => [
180 TagsModule::POST_META_CATEGORY,
181 TagsModule::URL_CATEGORY,
182 ],
183 ],
184 'placeholder' => esc_html__( 'Enter your URL', 'elementor' ) . ' (Vimeo)',
185 'default' => 'https://vimeo.com/235215203',
186 'label_block' => true,
187 'condition' => [
188 'video_type' => 'vimeo',
189 ],
190 'ai' => [
191 'active' => false,
192 ],
193 ]
194 );
195
196 $this->add_control(
197 'dailymotion_url',
198 [
199 'label' => esc_html__( 'Link', 'elementor' ),
200 'type' => Controls_Manager::TEXT,
201 'dynamic' => [
202 'active' => true,
203 'categories' => [
204 TagsModule::POST_META_CATEGORY,
205 TagsModule::URL_CATEGORY,
206 ],
207 ],
208 'placeholder' => esc_html__( 'Enter your URL', 'elementor' ) . ' (Dailymotion)',
209 'default' => 'https://www.dailymotion.com/video/x6tqhqb',
210 'label_block' => true,
211 'condition' => [
212 'video_type' => 'dailymotion',
213 ],
214 'ai' => [
215 'active' => false,
216 ],
217 ]
218 );
219
220 $this->add_control(
221 'insert_url',
222 [
223 'label' => esc_html__( 'External URL', 'elementor' ),
224 'type' => Controls_Manager::SWITCHER,
225 'condition' => [
226 'video_type' => [ 'hosted', 'videopress' ],
227 ],
228 ]
229 );
230
231 $this->add_control(
232 'hosted_url',
233 [
234 'label' => esc_html__( 'Choose Video File', 'elementor' ),
235 'type' => Controls_Manager::MEDIA,
236 'dynamic' => [
237 'active' => true,
238 'categories' => [
239 TagsModule::MEDIA_CATEGORY,
240 ],
241 ],
242 'media_types' => [
243 'video',
244 ],
245 'condition' => [
246 'video_type' => [ 'hosted', 'videopress' ],
247 'insert_url' => '',
248 ],
249 ]
250 );
251
252 $this->add_control(
253 'external_url',
254 [
255 'label' => esc_html__( 'URL', 'elementor' ),
256 'type' => Controls_Manager::URL,
257 'autocomplete' => false,
258 'options' => false,
259 'label_block' => true,
260 'show_label' => false,
261 'dynamic' => [
262 'active' => true,
263 'categories' => [
264 TagsModule::POST_META_CATEGORY,
265 TagsModule::URL_CATEGORY,
266 ],
267 ],
268 'placeholder' => esc_html__( 'Enter your URL', 'elementor' ),
269 'condition' => [
270 'video_type' => 'hosted',
271 'insert_url' => 'yes',
272 ],
273 ]
274 );
275
276 $this->add_control(
277 'videopress_url',
278 [
279 'label' => esc_html__( 'URL', 'elementor' ),
280 'type' => Controls_Manager::TEXT,
281 'label_block' => true,
282 'show_label' => false,
283 'default' => 'https://videopress.com/v/ZCAOzTNk',
284 'dynamic' => [
285 'active' => true,
286 'categories' => [
287 TagsModule::POST_META_CATEGORY,
288 TagsModule::URL_CATEGORY,
289 ],
290 ],
291 'placeholder' => esc_html__( 'VideoPress URL', 'elementor' ),
292 'ai' => [
293 'active' => false,
294 ],
295 'condition' => [
296 'video_type' => 'videopress',
297 'insert_url' => 'yes',
298 ],
299
300 ]
301 );
302
303 $this->add_control(
304 'start',
305 [
306 'label' => esc_html__( 'Start Time', 'elementor' ),
307 'type' => Controls_Manager::NUMBER,
308 'description' => esc_html__( 'Specify a start time (in seconds)', 'elementor' ),
309 'frontend_available' => true,
310 'separator' => 'before',
311 ]
312 );
313
314 $this->add_control(
315 'end',
316 [
317 'label' => esc_html__( 'End Time', 'elementor' ),
318 'type' => Controls_Manager::NUMBER,
319 'description' => esc_html__( 'Specify an end time (in seconds)', 'elementor' ),
320 'condition' => [
321 'video_type' => [ 'youtube', 'hosted' ],
322 ],
323 'frontend_available' => true,
324 ]
325 );
326
327 $this->add_control(
328 'video_options',
329 [
330 'label' => esc_html__( 'Video Options', 'elementor' ),
331 'type' => Controls_Manager::HEADING,
332 'separator' => 'before',
333 ]
334 );
335
336 $this->add_control(
337 'autoplay',
338 [
339 'label' => esc_html__( 'Autoplay', 'elementor' ),
340 'description' => sprintf(
341 /* translators: 1: `<a>` opening tag, 2: `</a>` closing tag. */
342 esc_html__( 'Note: Autoplay is affected by %1$s Google’s Autoplay policy %2$s on Chrome browsers.', 'elementor' ),
343 '<a href="https://developers.google.com/web/updates/2017/09/autoplay-policy-changes" target="_blank">',
344 '</a>'
345 ),
346 'type' => Controls_Manager::SWITCHER,
347 'frontend_available' => true,
348 ]
349 );
350
351 $this->add_control(
352 'play_on_mobile',
353 [
354 'label' => esc_html__( 'Play On Mobile', 'elementor' ),
355 'type' => Controls_Manager::SWITCHER,
356 'condition' => [
357 'autoplay' => 'yes',
358 ],
359 'frontend_available' => true,
360 ]
361 );
362
363 $this->add_control(
364 'mute',
365 [
366 'label' => esc_html__( 'Mute', 'elementor' ),
367 'type' => Controls_Manager::SWITCHER,
368 'frontend_available' => true,
369 ]
370 );
371
372 $this->add_control(
373 'loop',
374 [
375 'label' => esc_html__( 'Loop', 'elementor' ),
376 'type' => Controls_Manager::SWITCHER,
377 'condition' => [
378 'video_type!' => 'dailymotion',
379 ],
380 'frontend_available' => true,
381 ]
382 );
383
384 $this->add_control(
385 'controls',
386 [
387 'label' => esc_html__( 'Player Controls', 'elementor' ),
388 'type' => Controls_Manager::SWITCHER,
389 'label_off' => esc_html__( 'Hide', 'elementor' ),
390 'label_on' => esc_html__( 'Show', 'elementor' ),
391 'default' => 'yes',
392 'condition' => [
393 'video_type!' => 'vimeo',
394 ],
395 'frontend_available' => true,
396 ]
397 );
398
399 $this->add_control(
400 'showinfo',
401 [
402 'label' => esc_html__( 'Video Info', 'elementor' ),
403 'type' => Controls_Manager::SWITCHER,
404 'label_off' => esc_html__( 'Hide', 'elementor' ),
405 'label_on' => esc_html__( 'Show', 'elementor' ),
406 'default' => 'yes',
407 'condition' => [
408 'video_type' => [ 'dailymotion' ],
409 ],
410 ]
411 );
412
413 $this->add_control(
414 'cc_load_policy',
415 [
416 'label' => esc_html__( 'Captions', 'elementor' ),
417 'type' => Controls_Manager::SWITCHER,
418 'condition' => [
419 'video_type' => [ 'youtube' ],
420 'controls' => 'yes',
421 ],
422 'frontend_available' => true,
423 ]
424 );
425
426 $this->add_control(
427 'logo',
428 [
429 'label' => esc_html__( 'Logo', 'elementor' ),
430 'type' => Controls_Manager::SWITCHER,
431 'label_off' => esc_html__( 'Hide', 'elementor' ),
432 'label_on' => esc_html__( 'Show', 'elementor' ),
433 'default' => 'yes',
434 'condition' => [
435 'video_type' => [ 'dailymotion' ],
436 ],
437 ]
438 );
439
440 // YouTube.
441 $this->add_control(
442 'yt_privacy',
443 [
444 'label' => esc_html__( 'Privacy Mode', 'elementor' ),
445 'type' => Controls_Manager::SWITCHER,
446 'description' => esc_html__( 'When you turn on privacy mode, YouTube/Vimeo won\'t store information about visitors on your website unless they play the video.', 'elementor' ),
447 'condition' => [
448 'video_type' => [ 'youtube', 'vimeo' ],
449 ],
450 'frontend_available' => true,
451 ]
452 );
453
454 $this->add_control(
455 'lazy_load',
456 [
457 'label' => esc_html__( 'Lazy Load', 'elementor' ),
458 'type' => Controls_Manager::SWITCHER,
459 'conditions' => [
460 'relation' => 'or',
461 'terms' => [
462 [
463 'name' => 'video_type',
464 'operator' => '===',
465 'value' => 'youtube',
466 ],
467 [
468 'relation' => 'and',
469 'terms' => [
470 [
471 'name' => 'show_image_overlay',
472 'operator' => '===',
473 'value' => 'yes',
474 ],
475 [
476 'name' => 'video_type',
477 'operator' => '!==',
478 'value' => 'hosted',
479 ],
480 ],
481 ],
482 ],
483 ],
484 'frontend_available' => true,
485 ]
486 );
487
488 $this->add_control(
489 'rel',
490 [
491 'label' => esc_html__( 'Suggested Videos', 'elementor' ),
492 'type' => Controls_Manager::SELECT,
493 'options' => [
494 '' => esc_html__( 'Current Video Channel', 'elementor' ),
495 'yes' => esc_html__( 'Any Video', 'elementor' ),
496 ],
497 'condition' => [
498 'video_type' => 'youtube',
499 ],
500 ]
501 );
502
503 // Vimeo.
504 $this->add_control(
505 'vimeo_title',
506 [
507 'label' => esc_html__( 'Intro Title', 'elementor' ),
508 'type' => Controls_Manager::SWITCHER,
509 'label_off' => esc_html__( 'Hide', 'elementor' ),
510 'label_on' => esc_html__( 'Show', 'elementor' ),
511 'default' => 'yes',
512 'condition' => [
513 'video_type' => 'vimeo',
514 ],
515 ]
516 );
517
518 $this->add_control(
519 'vimeo_portrait',
520 [
521 'label' => esc_html__( 'Intro Portrait', 'elementor' ),
522 'type' => Controls_Manager::SWITCHER,
523 'label_off' => esc_html__( 'Hide', 'elementor' ),
524 'label_on' => esc_html__( 'Show', 'elementor' ),
525 'default' => 'yes',
526 'condition' => [
527 'video_type' => 'vimeo',
528 ],
529 ]
530 );
531
532 $this->add_control(
533 'vimeo_byline',
534 [
535 'label' => esc_html__( 'Intro Byline', 'elementor' ),
536 'type' => Controls_Manager::SWITCHER,
537 'label_off' => esc_html__( 'Hide', 'elementor' ),
538 'label_on' => esc_html__( 'Show', 'elementor' ),
539 'default' => 'yes',
540 'condition' => [
541 'video_type' => 'vimeo',
542 ],
543 ]
544 );
545
546 $this->add_control(
547 'color',
548 [
549 'label' => esc_html__( 'Controls Color', 'elementor' ),
550 'type' => Controls_Manager::COLOR,
551 'default' => '',
552 'condition' => [
553 'video_type' => [ 'vimeo', 'dailymotion' ],
554 ],
555 ]
556 );
557
558 $this->add_control(
559 'download_button',
560 [
561 'label' => esc_html__( 'Download Button', 'elementor' ),
562 'type' => Controls_Manager::SWITCHER,
563 'label_off' => esc_html__( 'Hide', 'elementor' ),
564 'label_on' => esc_html__( 'Show', 'elementor' ),
565 'condition' => [
566 'video_type' => 'hosted',
567 ],
568 ]
569 );
570
571 $this->add_control(
572 'preload',
573 [
574 'label' => esc_html__( 'Preload', 'elementor' ),
575 'type' => Controls_Manager::SELECT,
576 'options' => [
577 'metadata' => esc_html__( 'Metadata', 'elementor' ),
578 'auto' => esc_html__( 'Auto', 'elementor' ),
579 'none' => esc_html__( 'None', 'elementor' ),
580 ],
581 'description' => sprintf(
582 '%1$s <a target="_blank" href="https://go.elementor.com/preload-video/">%2$s</a>',
583 esc_html__( 'Preload attribute lets you specify how the video should be loaded when the page loads.', 'elementor' ),
584 esc_html__( 'Learn more', 'elementor' ),
585 ),
586 'default' => 'metadata',
587 'condition' => [
588 'video_type' => 'hosted',
589 'autoplay' => '',
590 ],
591 ]
592 );
593
594 $this->add_control(
595 'poster',
596 [
597 'label' => esc_html__( 'Poster', 'elementor' ),
598 'type' => Controls_Manager::MEDIA,
599 'dynamic' => [
600 'active' => true,
601 ],
602 'condition' => [
603 'video_type' => 'hosted',
604 ],
605 ]
606 );
607
608 if ( ! Utils::has_pro() ) {
609 $this->add_control(
610 Utils::VIDEO_PLAYLIST . '_promotion',
611 [
612 'label' => esc_html__( 'Video Playlist widget', 'elementor' ),
613 'type' => Promotion_Control::TYPE,
614 ]
615 );
616 }
617
618 $this->end_controls_section();
619
620 $this->start_controls_section(
621 'section_image_overlay',
622 [
623 'label' => esc_html__( 'Image Overlay', 'elementor' ),
624 ]
625 );
626
627 $this->add_control(
628 'show_image_overlay',
629 [
630 'label' => esc_html__( 'Image Overlay', 'elementor' ),
631 'type' => Controls_Manager::SWITCHER,
632 'label_off' => esc_html__( 'Hide', 'elementor' ),
633 'label_on' => esc_html__( 'Show', 'elementor' ),
634 'frontend_available' => true,
635 ]
636 );
637
638 $this->add_control(
639 'image_overlay',
640 [
641 'label' => esc_html__( 'Choose Image', 'elementor' ),
642 'type' => Controls_Manager::MEDIA,
643 'default' => [
644 'url' => Utils::get_placeholder_image_src(),
645 ],
646 'dynamic' => [
647 'active' => true,
648 ],
649 'condition' => [
650 'show_image_overlay' => 'yes',
651 ],
652 'frontend_available' => true,
653 ]
654 );
655
656 $this->add_group_control(
657 Group_Control_Image_Size::get_type(),
658 [
659 'name' => 'image_overlay', // Usage: `{name}_size` and `{name}_custom_dimension`, in this case `image_overlay_size` and `image_overlay_custom_dimension`.
660 'default' => 'full',
661 'condition' => [
662 'show_image_overlay' => 'yes',
663 ],
664 ]
665 );
666
667 $this->add_control(
668 'show_play_icon',
669 [
670 'label' => esc_html__( 'Play Icon', 'elementor' ),
671 'type' => Controls_Manager::SWITCHER,
672 'default' => 'yes',
673 'label_off' => esc_html__( 'Hide', 'elementor' ),
674 'label_on' => esc_html__( 'Show', 'elementor' ),
675 'separator' => 'before',
676 'condition' => [
677 'show_image_overlay' => 'yes',
678 'image_overlay[url]!' => '',
679 ],
680 ]
681 );
682
683 $this->add_control(
684 'play_icon',
685 [
686 'label' => esc_html__( 'Icon', 'elementor' ),
687 'type' => Controls_Manager::ICONS,
688 'fa4compatibility' => 'icon',
689 'skin' => 'inline',
690 'label_block' => false,
691 'skin_settings' => [
692 'inline' => [
693 'none' => [
694 'label' => 'Default',
695 'icon' => 'eicon-play',
696 ],
697 'icon' => [
698 'icon' => 'eicon-star',
699 ],
700 ],
701 ],
702 'recommended' => [
703 'fa-regular' => [
704 'play-circle',
705 ],
706 'fa-solid' => [
707 'play',
708 'play-circle',
709 ],
710 ],
711 'condition' => [
712 'show_image_overlay' => 'yes',
713 'show_play_icon!' => '',
714 ],
715 ]
716 );
717
718 $this->add_control(
719 'lightbox',
720 [
721 'label' => esc_html__( 'Lightbox', 'elementor' ),
722 'type' => Controls_Manager::SWITCHER,
723 'frontend_available' => true,
724 'label_off' => esc_html__( 'Off', 'elementor' ),
725 'label_on' => esc_html__( 'On', 'elementor' ),
726 'condition' => [
727 'show_image_overlay' => 'yes',
728 'image_overlay[url]!' => '',
729 ],
730 'separator' => 'before',
731 ]
732 );
733
734 $this->end_controls_section();
735
736 $this->start_controls_section(
737 'section_video_style',
738 [
739 'label' => esc_html__( 'Video', 'elementor' ),
740 'tab' => Controls_Manager::TAB_STYLE,
741 ]
742 );
743
744 $this->add_control(
745 'aspect_ratio',
746 [
747 'label' => esc_html__( 'Aspect Ratio', 'elementor' ),
748 'type' => Controls_Manager::SELECT,
749 'options' => [
750 '169' => '16:9',
751 '219' => '21:9',
752 '43' => '4:3',
753 '32' => '3:2',
754 '11' => '1:1',
755 '916' => '9:16',
756 ],
757 'selectors_dictionary' => [
758 '169' => '1.77777', // 16 / 9
759 '219' => '2.33333', // 21 / 9
760 '43' => '1.33333', // 4 / 3
761 '32' => '1.5', // 3 / 2
762 '11' => '1', // 1 / 1
763 '916' => '0.5625', // 9 / 16
764 ],
765 'default' => '169',
766 'selectors' => [
767 '{{WRAPPER}} .elementor-wrapper' => '--video-aspect-ratio: {{VALUE}}',
768 ],
769 ]
770 );
771
772 $this->add_group_control(
773 Group_Control_Css_Filter::get_type(),
774 [
775 'name' => 'css_filters',
776 'selector' => '{{WRAPPER}} .elementor-wrapper',
777 ]
778 );
779
780 $this->end_controls_section();
781
782 $this->start_controls_section(
783 'section_image_overlay_style',
784 [
785 'label' => esc_html__( 'Image Overlay', 'elementor' ),
786 'tab' => Controls_Manager::TAB_STYLE,
787 'condition' => [
788 'show_image_overlay' => 'yes',
789 'show_play_icon' => 'yes',
790 ],
791 ]
792 );
793
794 $this->add_control(
795 'play_icon_title',
796 [
797 'label' => esc_html__( 'Play Icon', 'elementor' ),
798 'type' => Controls_Manager::HEADING,
799 'condition' => [
800 'show_image_overlay' => 'yes',
801 'show_play_icon' => 'yes',
802 ],
803 ]
804 );
805
806 $this->add_control(
807 'play_icon_color',
808 [
809 'label' => esc_html__( 'Color', 'elementor' ),
810 'type' => Controls_Manager::COLOR,
811 'selectors' => [
812 '{{WRAPPER}} .elementor-custom-embed-play i' => 'color: {{VALUE}}',
813 '{{WRAPPER}} .elementor-custom-embed-play svg' => 'fill: {{VALUE}}',
814 ],
815 'condition' => [
816 'show_image_overlay' => 'yes',
817 'show_play_icon' => 'yes',
818 ],
819 ]
820 );
821
822 $this->add_responsive_control(
823 'play_icon_size',
824 [
825 'label' => esc_html__( 'Size', 'elementor' ),
826 'type' => Controls_Manager::SLIDER,
827 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
828 'range' => [
829 'px' => [
830 'min' => 10,
831 'max' => 300,
832 ],
833 ],
834 'selectors' => [
835 // Not using a CSS vars because the default size value is coming from a global scss file.
836 '{{WRAPPER}} .elementor-custom-embed-play i' => 'font-size: {{SIZE}}{{UNIT}}',
837 '{{WRAPPER}} .elementor-custom-embed-play svg' => 'width: {{SIZE}}{{UNIT}}; height: {{SIZE}}{{UNIT}};',
838 ],
839 'condition' => [
840 'show_image_overlay' => 'yes',
841 'show_play_icon' => 'yes',
842 ],
843 ]
844 );
845
846 $this->add_group_control(
847 Group_Control_Text_Shadow::get_type(),
848 [
849 'name' => 'play_icon_text_shadow',
850 'selector' => '{{WRAPPER}} .elementor-custom-embed-play i',
851 'fields_options' => [
852 'text_shadow_type' => [
853 'label' => esc_html__( 'Shadow', 'elementor' ),
854 ],
855 ],
856 'condition' => [
857 'show_image_overlay' => 'yes',
858 'show_play_icon' => 'yes',
859 'play_icon[library]!' => 'svg',
860 ],
861 ]
862 );
863
864 $this->end_controls_section();
865
866 $this->start_controls_section(
867 'section_lightbox_style',
868 [
869 'label' => esc_html__( 'Lightbox', 'elementor' ),
870 'tab' => Controls_Manager::TAB_STYLE,
871 'condition' => [
872 'show_image_overlay' => 'yes',
873 'image_overlay[url]!' => '',
874 'lightbox' => 'yes',
875 ],
876 ]
877 );
878
879 $this->add_control(
880 'lightbox_color',
881 [
882 'label' => esc_html__( 'Background Color', 'elementor' ),
883 'type' => Controls_Manager::COLOR,
884 'selectors' => [
885 '#elementor-lightbox-{{ID}}' => 'background-color: {{VALUE}};',
886 ],
887 ]
888 );
889
890 $this->add_control(
891 'lightbox_ui_color',
892 [
893 'label' => esc_html__( 'UI Color', 'elementor' ),
894 'type' => Controls_Manager::COLOR,
895 'selectors' => [
896 '#elementor-lightbox-{{ID}} .dialog-lightbox-close-button' => 'color: {{VALUE}}',
897 '#elementor-lightbox-{{ID}} .dialog-lightbox-close-button svg' => 'fill: {{VALUE}}',
898 ],
899 ]
900 );
901
902 $this->add_control(
903 'lightbox_ui_color_hover',
904 [
905 'label' => esc_html__( 'UI Hover Color', 'elementor' ),
906 'type' => Controls_Manager::COLOR,
907 'selectors' => [
908 '#elementor-lightbox-{{ID}} .dialog-lightbox-close-button:hover' => 'color: {{VALUE}}',
909 '#elementor-lightbox-{{ID}} .dialog-lightbox-close-button:hover svg' => 'fill: {{VALUE}}',
910 ],
911 ]
912 );
913
914 $this->add_responsive_control(
915 'lightbox_content_animation',
916 [
917 'label' => esc_html__( 'Entrance Animation', 'elementor' ),
918 'type' => Controls_Manager::ANIMATION,
919 'frontend_available' => true,
920 'separator' => 'before',
921 ]
922 );
923
924 $this->add_control(
925 'deprecation_warning',
926 [
927 'type' => Controls_Manager::ALERT,
928 'alert_type' => 'danger',
929 'content' => esc_html__( 'Note: These controls have been deprecated and are only visible if they were previously in use. The video’s width and position are now set based on its aspect ratio.', 'elementor' ),
930 'separator' => 'before',
931 'condition' => [
932 'lightbox_video_width!' => '',
933 'lightbox_content_position!' => '',
934 ],
935 ]
936 );
937
938 // Deprecated control. Visible only if it was previously in use.
939 $this->add_control(
940 'lightbox_video_width',
941 [
942 'label' => esc_html__( 'Content Width', 'elementor' ),
943 'type' => Controls_Manager::SLIDER,
944 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
945 'default' => [
946 'unit' => '%',
947 ],
948 // 'selectors' => [
949 // '(desktop+)#elementor-lightbox-{{ID}} .elementor-video-container' => 'width: {{SIZE}}{{UNIT}};',
950 // ],
951 'condition' => [
952 'lightbox_video_width!' => '',
953 'lightbox_content_position!' => '',
954 ],
955 ]
956 );
957
958 // Deprecated control. Visible only if it was previously in use.
959 $this->add_control(
960 'lightbox_content_position',
961 [
962 'label' => esc_html__( 'Content Position', 'elementor' ),
963 'type' => Controls_Manager::SELECT,
964 'frontend_available' => true,
965 'options' => [
966 '' => esc_html__( 'Center', 'elementor' ),
967 'top' => esc_html__( 'Top', 'elementor' ),
968 ],
969 // 'selectors' => [
970 // '#elementor-lightbox-{{ID}} .elementor-video-container' => '{{VALUE}}; transform: translateX(-50%);',
971 // ],
972 'selectors_dictionary' => [
973 'top' => 'top: 60px',
974 ],
975 'condition' => [
976 'lightbox_video_width!' => '',
977 'lightbox_content_position!' => '',
978 ],
979 ]
980 );
981
982 $this->end_controls_section();
983 }
984
985 public function print_a11y_text( $image_overlay ) {
986 if ( empty( $image_overlay['alt'] ) ) {
987 echo esc_html__( 'Play Video', 'elementor' );
988 } else {
989 echo esc_html__( 'Play Video about', 'elementor' ) . ' ' . esc_attr( $image_overlay['alt'] );
990 }
991 }
992
993 /**
994 * Render video widget output on the frontend.
995 *
996 * Written in PHP and used to generate the final HTML.
997 *
998 * @since 1.0.0
999 * @access protected
1000 */
1001 protected function render() {
1002 $settings = $this->get_settings_for_display();
1003
1004 $video_url = $settings[ $settings['video_type'] . '_url' ];
1005
1006 if ( 'hosted' === $settings['video_type'] ) {
1007 $video_url = $this->get_hosted_video_url();
1008 } else {
1009 if ( 'videopress' === $settings['video_type'] ) {
1010 $video_url = $this->get_videopress_video_url();
1011 }
1012
1013 $embed_params = $this->get_embed_params();
1014 $embed_options = $this->get_embed_options();
1015 }
1016
1017 if ( empty( $video_url ) ) {
1018 return;
1019 }
1020
1021 if ( 'youtube' === $settings['video_type'] ) {
1022 $video_html = '<div class="elementor-video"></div>';
1023 }
1024
1025 if ( 'hosted' === $settings['video_type'] ) {
1026 $this->add_render_attribute( 'video-wrapper', 'class', 'e-hosted-video' );
1027
1028 ob_start();
1029
1030 $this->render_hosted_video();
1031
1032 $video_html = ob_get_clean();
1033 } else {
1034 $is_static_render_mode = Plugin::$instance->frontend->is_static_render_mode();
1035 $post_id = get_queried_object_id();
1036
1037 if ( $is_static_render_mode ) {
1038 $video_html = Embed::get_embed_thumbnail_html( $video_url, $post_id );
1039 // YouTube API requires a different markup which was set above.
1040 } else if ( 'youtube' !== $settings['video_type'] ) {
1041 $video_html = Embed::get_embed_html( $video_url, $embed_params, $embed_options );
1042 }
1043 }
1044
1045 if ( empty( $video_html ) ) {
1046 echo esc_url( $video_url );
1047
1048 return;
1049 }
1050
1051 $this->add_render_attribute( 'video-wrapper', 'class', 'elementor-wrapper' );
1052
1053 $this->add_render_attribute( 'video-wrapper', 'class', 'elementor-open-' . ( $settings['lightbox'] ? 'lightbox' : 'inline' ) );
1054 ?>
1055 <div <?php $this->print_render_attribute_string( 'video-wrapper' ); ?>>
1056 <?php
1057 if ( ! $settings['lightbox'] ) {
1058 Utils::print_unescaped_internal_string( $video_html ); // XSS ok.
1059 }
1060
1061 if ( $this->has_image_overlay() ) {
1062 $this->add_render_attribute( 'image-overlay', 'class', 'elementor-custom-embed-image-overlay' );
1063
1064 if ( $settings['lightbox'] ) {
1065 if ( 'hosted' === $settings['video_type'] ) {
1066 $lightbox_url = $video_url;
1067 } else {
1068 $lightbox_url = Embed::get_embed_url( $video_url, $embed_params, $embed_options );
1069 }
1070
1071 $lightbox_options = [
1072 'type' => 'video',
1073 'videoType' => $settings['video_type'],
1074 'url' => $lightbox_url,
1075 'autoplay' => $settings['autoplay'],
1076 'modalOptions' => [
1077 'id' => 'elementor-lightbox-' . $this->get_id(),
1078 'entranceAnimation' => $settings['lightbox_content_animation'],
1079 'entranceAnimation_tablet' => $settings['lightbox_content_animation_tablet'],
1080 'entranceAnimation_mobile' => $settings['lightbox_content_animation_mobile'],
1081 'videoAspectRatio' => $settings['aspect_ratio'] ?? '169',
1082 ],
1083 ];
1084
1085 if ( 'hosted' === $settings['video_type'] ) {
1086 $lightbox_options['videoParams'] = $this->get_hosted_params();
1087 }
1088
1089 $this->add_render_attribute( 'image-overlay', [
1090 'data-elementor-open-lightbox' => 'yes',
1091 'data-elementor-lightbox' => wp_json_encode( $lightbox_options ),
1092 'data-e-action-hash' => Plugin::instance()->frontend->create_action_hash( 'lightbox', $lightbox_options ),
1093 ] );
1094
1095 if ( Plugin::$instance->editor->is_edit_mode() ) {
1096 $this->add_render_attribute( 'image-overlay', [
1097 'class' => 'elementor-clickable',
1098 ] );
1099 }
1100 } else {
1101 // When there is an image URL but no ID, it means the overlay image is the placeholder. In this case, get the placeholder URL.
1102 if ( empty( $settings['image_overlay']['id'] && ! empty( $settings['image_overlay']['url'] ) ) ) {
1103 $image_url = $settings['image_overlay']['url'];
1104 } else {
1105 $image_url = Group_Control_Image_Size::get_attachment_image_src( $settings['image_overlay']['id'], 'image_overlay', $settings );
1106 }
1107
1108 $this->add_render_attribute( 'image-overlay', 'style', 'background-image: url(' . $image_url . ');' );
1109 }
1110 ?>
1111 <div <?php $this->print_render_attribute_string( 'image-overlay' ); ?>>
1112 <?php if ( $settings['lightbox'] ) : ?>
1113 <?php Group_Control_Image_Size::print_attachment_image_html( $settings, 'image_overlay' ); ?>
1114 <?php endif; ?>
1115 <?php if ( 'yes' === $settings['show_play_icon'] ) : ?>
1116 <div class="elementor-custom-embed-play" role="button" aria-label="<?php $this->print_a11y_text( $settings['image_overlay'] ); ?>" tabindex="0">
1117 <?php
1118 if ( empty( $settings['play_icon']['value'] ) ) {
1119 $settings['play_icon'] = [
1120 'library' => 'eicons',
1121 'value' => 'eicon-play',
1122 ];
1123 }
1124 Icons_Manager::render_icon( $settings['play_icon'], [ 'aria-hidden' => 'true' ] );
1125 ?>
1126 </div>
1127 <?php endif; ?>
1128 </div>
1129 <?php } ?>
1130 </div>
1131 <?php
1132 }
1133
1134 /**
1135 * Render video widget as plain content.
1136 *
1137 * Override the default behavior, by printing the video URL instead of rendering it.
1138 *
1139 * @since 1.4.5
1140 * @access public
1141 */
1142 public function render_plain_content() {
1143 $settings = $this->get_settings_for_display();
1144
1145 if ( 'hosted' !== $settings['video_type'] ) {
1146 $url = $settings[ $settings['video_type'] . '_url' ];
1147 } else {
1148 $url = $this->get_hosted_video_url();
1149 }
1150
1151 echo esc_url( $url );
1152 }
1153
1154 /**
1155 * Get embed params.
1156 *
1157 * Retrieve video widget embed parameters.
1158 *
1159 * @since 1.5.0
1160 * @access public
1161 *
1162 * @return array Video embed parameters.
1163 */
1164 public function get_embed_params() {
1165 $settings = $this->get_settings_for_display();
1166
1167 $params = [];
1168
1169 if ( $settings['autoplay'] && ! $this->has_image_overlay() ) {
1170 $params['autoplay'] = '1';
1171
1172 if ( $settings['play_on_mobile'] ) {
1173 $params['playsinline'] = '1';
1174 }
1175 }
1176
1177 $params_dictionary = [];
1178
1179 if ( 'youtube' === $settings['video_type'] ) {
1180 $params_dictionary = [
1181 'loop',
1182 'controls',
1183 'mute',
1184 'rel',
1185 'cc_load_policy',
1186 ];
1187
1188 if ( $settings['loop'] ) {
1189 $video_properties = Embed::get_video_properties( $settings['youtube_url'] );
1190
1191 $params['playlist'] = $video_properties['video_id'];
1192 }
1193
1194 $params['start'] = $settings['start'];
1195
1196 $params['end'] = $settings['end'];
1197
1198 $params['wmode'] = 'opaque';
1199 } elseif ( 'vimeo' === $settings['video_type'] ) {
1200 $params_dictionary = [
1201 'loop',
1202 'mute' => 'muted',
1203 'vimeo_title' => 'title',
1204 'vimeo_portrait' => 'portrait',
1205 'vimeo_byline' => 'byline',
1206 ];
1207
1208 $params['color'] = str_replace( '#', '', $settings['color'] );
1209
1210 $params['autopause'] = '0';
1211
1212 if ( ! empty( $settings['yt_privacy'] ) ) {
1213 $params['dnt'] = 'true';
1214 }
1215 } elseif ( 'dailymotion' === $settings['video_type'] ) {
1216 $params_dictionary = [
1217 'controls',
1218 'mute',
1219 'showinfo' => 'ui-start-screen-info',
1220 'logo' => 'ui-logo',
1221 ];
1222
1223 $params['ui-highlight'] = str_replace( '#', '', $settings['color'] );
1224
1225 $params['start'] = $settings['start'];
1226
1227 $params['endscreen-enable'] = '0';
1228 } elseif ( 'videopress' === $settings['video_type'] ) {
1229 $params_dictionary = $this->get_params_dictionary_for_videopress();
1230
1231 $params['at'] = $settings['start'];
1232 }
1233
1234 foreach ( $params_dictionary as $key => $param_name ) {
1235 $setting_name = $param_name;
1236
1237 if ( is_string( $key ) ) {
1238 $setting_name = $key;
1239 }
1240
1241 $setting_value = $settings[ $setting_name ] ? '1' : '0';
1242
1243 $params[ $param_name ] = $setting_value;
1244 }
1245
1246 return $params;
1247 }
1248
1249 /**
1250 * Whether the video widget has an overlay image or not.
1251 *
1252 * Used to determine whether an overlay image was set for the video.
1253 *
1254 * @since 1.0.0
1255 * @access protected
1256 *
1257 * @return bool Whether an image overlay was set for the video.
1258 */
1259 protected function has_image_overlay() {
1260 $settings = $this->get_settings_for_display();
1261
1262 return ! empty( $settings['image_overlay']['url'] ) && 'yes' === $settings['show_image_overlay'];
1263 }
1264
1265 /**
1266 * @since 2.1.0
1267 * @access private
1268 */
1269 private function get_embed_options() {
1270 $settings = $this->get_settings_for_display();
1271
1272 $embed_options = [];
1273
1274 if ( 'youtube' === $settings['video_type'] ) {
1275 $embed_options['privacy'] = $settings['yt_privacy'];
1276 } elseif ( 'vimeo' === $settings['video_type'] ) {
1277 $embed_options['start'] = $settings['start'];
1278 }
1279
1280 $embed_options['lazy_load'] = ! empty( $settings['lazy_load'] );
1281
1282 return $embed_options;
1283 }
1284
1285 /**
1286 * @since 2.1.0
1287 * @access private
1288 */
1289 private function get_hosted_params() {
1290 $settings = $this->get_settings_for_display();
1291
1292 $video_params = [];
1293
1294 foreach ( [ 'autoplay', 'loop', 'controls' ] as $option_name ) {
1295 if ( $settings[ $option_name ] ) {
1296 $video_params[ $option_name ] = '';
1297 }
1298 }
1299
1300 if ( $settings['preload'] ) {
1301 $video_params['preload'] = $settings['preload'];
1302 }
1303
1304 if ( $settings['mute'] ) {
1305 $video_params['muted'] = 'muted';
1306 }
1307
1308 if ( $settings['play_on_mobile'] ) {
1309 $video_params['playsinline'] = '';
1310 }
1311
1312 if ( ! $settings['download_button'] ) {
1313 $video_params['controlsList'] = 'nodownload';
1314 }
1315
1316 if ( $settings['poster']['url'] ) {
1317 $video_params['poster'] = $settings['poster']['url'];
1318 }
1319
1320 return $video_params;
1321 }
1322
1323 /**
1324 *
1325 * @return string
1326 * @since 2.1.0
1327 * @access private
1328 */
1329 private function get_hosted_video_url() {
1330 $settings = $this->get_settings_for_display();
1331
1332 if ( ! empty( $settings['insert_url'] ) ) {
1333 $video_url = $settings['external_url']['url'];
1334 } else {
1335 $video_url = $settings['hosted_url']['url'];
1336 }
1337
1338 if ( empty( $video_url ) ) {
1339 return '';
1340 }
1341
1342 if ( $settings['start'] || $settings['end'] ) {
1343 $video_url .= '#t=';
1344 }
1345
1346 if ( $settings['start'] ) {
1347 $video_url .= $settings['start'];
1348 }
1349
1350 if ( $settings['end'] ) {
1351 $video_url .= ',' . $settings['end'];
1352 }
1353
1354 return $video_url;
1355 }
1356
1357 /**
1358 * Get the VideoPress video URL from the current selected settings.
1359 *
1360 * @return string
1361 */
1362 private function get_videopress_video_url() {
1363 $settings = $this->get_settings_for_display();
1364
1365 if ( ! empty( $settings['insert_url'] ) ) {
1366 return $settings['videopress_url'];
1367 }
1368
1369 return $settings['hosted_url']['url'];
1370 }
1371
1372 /**
1373 * Get the params dictionary for VideoPress videos.
1374 *
1375 * @return array
1376 */
1377 private function get_params_dictionary_for_videopress() {
1378 return [
1379 'controls',
1380 'autoplay' => 'autoPlay',
1381 'mute' => 'muted',
1382 'loop',
1383 'play_on_mobile' => 'playsinline',
1384 ];
1385 }
1386
1387 /**
1388 *
1389 * @since 2.1.0
1390 * @access private
1391 */
1392 private function render_hosted_video() {
1393 $video_url = $this->get_hosted_video_url();
1394 if ( empty( $video_url ) ) {
1395 return;
1396 }
1397
1398 $video_params = $this->get_hosted_params();
1399 /* Sometimes the video url is base64, therefore we use `esc_attr` in `src`. */
1400 ?>
1401 <video class="elementor-video" src="<?php echo esc_attr( $video_url ); ?>" <?php Utils::print_html_attributes( $video_params ); ?>></video>
1402 <?php
1403 }
1404 }
1405