PluginProbe
Elementor Website Builder – more than just a page builder / 4.0.9
Elementor Website Builder – more than just a page builder v4.0.9
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 4.0.9, at includes/widgets/video.php

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