PluginProbe
Elementor Website Builder – more than just a page builder / 3.21.3
Elementor Website Builder – more than just a page builder v3.21.3
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 / common.php

common.php in Elementor Website Builder – more than just a page builder 3.21.3, at includes/widgets/common.php

1,167 lines 28.3 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\Core\Breakpoints\Manager as Breakpoints_Manager;
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit; // Exit if accessed directly.
8 }
9
10 /**
11 * Elementor common widget.
12 *
13 * Elementor base widget that gives you all the advanced options of the basic
14 * widget.
15 *
16 * @since 1.0.0
17 */
18 class Widget_Common extends Widget_Base {
19
20 /**
21 * Get widget name.
22 *
23 * Retrieve common 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 'common';
32 }
33
34 /**
35 * Show in panel.
36 *
37 * Whether to show the common widget in the panel or not.
38 *
39 * @since 1.0.0
40 * @access public
41 *
42 * @return bool Whether to show the widget in the panel.
43 */
44 public function show_in_panel() {
45 return false;
46 }
47
48 /**
49 * Get Responsive Device Args
50 *
51 * Receives an array of device args, and duplicates it for each active breakpoint.
52 * Returns an array of device args.
53 *
54 * @since 3.4.7
55 * @deprecated 3.7.0 Not needed anymore because responsive conditioning in the Editor was fixed in v3.7.0.
56 * @access protected
57 *
58 * @param array $args arguments to duplicate per breakpoint
59 * @param array $devices_to_exclude
60 *
61 * @return array responsive device args
62 */
63 protected function get_responsive_device_args( array $args, array $devices_to_exclude = [] ) {
64 Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.7.0' );
65
66 $device_args = [];
67 $breakpoints = Plugin::$instance->breakpoints->get_active_breakpoints();
68
69 foreach ( $breakpoints as $breakpoint_key => $breakpoint ) {
70 // If the device is not excluded, add it to the device args array.
71 if ( ! in_array( $breakpoint_key, $devices_to_exclude, true ) ) {
72 $parsed_device_args = $this->parse_device_args_placeholders( $args, $breakpoint_key );
73
74 $device_args[ $breakpoint_key ] = $parsed_device_args;
75 }
76 }
77
78 return $device_args;
79 }
80
81 /**
82 * Parse Device Args Placeholders
83 *
84 * Receives an array of args. Iterates over the args, and replaces the {{DEVICE}} placeholder, if exists, with the
85 * passed breakpoint key.
86 *
87 * @since 3.4.7
88 * @access private
89 *
90 * @param array $args
91 * @param string $breakpoint_key
92 * @return array parsed device args
93 */
94 private function parse_device_args_placeholders( array $args, $breakpoint_key ) {
95 $parsed_args = [];
96
97 foreach ( $args as $arg_key => $arg_value ) {
98 $arg_key = str_replace( '{{DEVICE}}', $breakpoint_key, $arg_key );
99
100 if ( is_array( $arg_value ) ) {
101 $arg_value = $this->parse_device_args_placeholders( $arg_value, $breakpoint_key );
102 }
103
104 $parsed_args[ $arg_key ] = $arg_value;
105 }
106
107 return $parsed_args;
108 }
109
110 /**
111 * @param $shape String Shape name.
112 *
113 * @return string The shape path in the assets folder.
114 */
115 private function get_shape_url( $shape ) {
116 return ELEMENTOR_ASSETS_URL . 'mask-shapes/' . $shape . '.svg';
117 }
118
119 /**
120 * Return a translated user-friendly list of the available masking shapes.
121 *
122 * @param bool $add_custom Determine if the output should contain `Custom` options.
123 *
124 * @return array Array of shapes with their URL as key.
125 */
126 private function get_shapes( $add_custom = true ) {
127 $shapes = [
128 'circle' => esc_html__( 'Circle', 'elementor' ),
129 'flower' => esc_html__( 'Flower', 'elementor' ),
130 'sketch' => esc_html__( 'Sketch', 'elementor' ),
131 'triangle' => esc_html__( 'Triangle', 'elementor' ),
132 'blob' => esc_html__( 'Blob', 'elementor' ),
133 'hexagon' => esc_html__( 'Hexagon', 'elementor' ),
134 ];
135
136 if ( $add_custom ) {
137 $shapes['custom'] = esc_html__( 'Custom', 'elementor' );
138 }
139
140 return $shapes;
141 }
142
143 /**
144 * Gets a string of CSS rules to apply, and returns an array of selectors with those rules.
145 * This function has been created in order to deal with masking for image widget.
146 * For most of the widgets the mask is being applied to the wrapper itself, but in the case of an image widget,
147 * the `img` tag should be masked directly. So instead of writing a lot of selectors every time,
148 * this function builds both of those selectors easily.
149 *
150 * @param $rules string The CSS rules to apply.
151 *
152 * @return array Selectors with the rules applied.
153 */
154 private function get_mask_selectors( $rules ) {
155 $mask_selectors = [
156 'default' => '{{WRAPPER}}:not( .elementor-widget-image ) .elementor-widget-container',
157 'image' => '{{WRAPPER}}.elementor-widget-image .elementor-widget-container img',
158 ];
159
160 return [
161 $mask_selectors['default'] => $rules,
162 $mask_selectors['image'] => $rules,
163 ];
164 }
165
166 /**
167 * Register the Layout section.
168 *
169 * @return void
170 */
171 private function register_layout_section() {
172 $this->start_controls_section(
173 '_section_style',
174 [
175 'label' => esc_html__( 'Layout', 'elementor' ),
176 'tab' => Controls_Manager::TAB_ADVANCED,
177 ]
178 );
179
180 // Element Name for the Navigator
181 $this->add_control(
182 '_title',
183 [
184 'label' => esc_html__( 'Title', 'elementor' ),
185 'type' => Controls_Manager::HIDDEN,
186 'render_type' => 'none',
187 ]
188 );
189
190 $this->add_responsive_control(
191 '_margin',
192 [
193 'label' => esc_html__( 'Margin', 'elementor' ),
194 'type' => Controls_Manager::DIMENSIONS,
195 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
196 'selectors' => [
197 '{{WRAPPER}} > .elementor-widget-container' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
198 ],
199 ]
200 );
201
202 $this->add_responsive_control(
203 '_padding',
204 [
205 'label' => esc_html__( 'Padding', 'elementor' ),
206 'type' => Controls_Manager::DIMENSIONS,
207 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
208 'selectors' => [
209 '{{WRAPPER}} > .elementor-widget-container' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
210 ],
211 ]
212 );
213
214 $experiments_manager = Plugin::$instance->experiments;
215 $is_container_active = $experiments_manager->is_feature_active( 'container' );
216
217 $this->add_responsive_control(
218 '_element_width',
219 [
220 'label' => esc_html__( 'Width', 'elementor' ),
221 'type' => Controls_Manager::SELECT,
222 'default' => '',
223 'options' => [
224 '' => esc_html__( 'Default', 'elementor' ),
225 'inherit' => esc_html__( 'Full Width', 'elementor' ) . ' (100%)',
226 'auto' => esc_html__( 'Inline', 'elementor' ) . ' (auto)',
227 'initial' => esc_html__( 'Custom', 'elementor' ),
228 ],
229 'selectors_dictionary' => [
230 'inherit' => '100%',
231 ],
232 'prefix_class' => 'elementor-widget%s__width-',
233 'selectors' => [
234 '{{WRAPPER}}' => 'width: {{VALUE}}; max-width: {{VALUE}}',
235 ],
236 ]
237 );
238
239 $this->add_responsive_control(
240 '_element_custom_width',
241 [
242 'label' => esc_html__( 'Custom Width', 'elementor' ),
243 'type' => Controls_Manager::SLIDER,
244 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
245 'default' => [
246 'unit' => '%',
247 ],
248 'range' => [
249 'px' => [
250 'max' => 1000,
251 ],
252 ],
253 'selectors' => [
254 '{{WRAPPER}}' => '--container-widget-width: {{SIZE}}{{UNIT}}; --container-widget-flex-grow: 0; width: var( --container-widget-width, {{SIZE}}{{UNIT}} ); max-width: {{SIZE}}{{UNIT}}',
255 ],
256 'condition' => [ '_element_width' => 'initial' ],
257 ]
258 );
259
260 // Register Flex controls only if the Container experiment is active.
261 if ( $is_container_active ) {
262 $this->add_group_control(
263 Group_Control_Flex_Item::get_type(),
264 [
265 'name' => '_flex',
266 // Hack to increase specificity and make sure that the current widget overrides the
267 // parent flex settings.
268 'selector' => '{{WRAPPER}}.elementor-element',
269 'include' => [
270 'align_self',
271 'order',
272 'order_custom',
273 'size',
274 'grow',
275 'shrink',
276 ],
277 'fields_options' => [
278 'align_self' => [
279 'separator' => 'before',
280 ],
281 ],
282 ]
283 );
284 }
285
286 $vertical_align_conditions = [
287 '_element_width!' => '',
288 '_position' => '',
289 ];
290
291 if ( $is_container_active ) {
292 $vertical_align_conditions['_element_vertical_align!'] = ''; // TODO: For BC.
293 }
294
295 // TODO: For BC - Remove in the future.
296 $this->add_responsive_control(
297 '_element_vertical_align',
298 [
299 'label' => esc_html__( 'Vertical Align', 'elementor' ),
300 'type' => Controls_Manager::CHOOSE,
301 'options' => [
302 'flex-start' => [
303 'title' => esc_html__( 'Start', 'elementor' ),
304 'icon' => 'eicon-v-align-top',
305 ],
306 'center' => [
307 'title' => esc_html__( 'Center', 'elementor' ),
308 'icon' => 'eicon-v-align-middle',
309 ],
310 'flex-end' => [
311 'title' => esc_html__( 'End', 'elementor' ),
312 'icon' => 'eicon-v-align-bottom',
313 ],
314 ],
315 'condition' => $vertical_align_conditions,
316 'selectors' => [
317 '{{WRAPPER}}' => 'align-self: {{VALUE}}',
318 ],
319 ]
320 );
321
322 $this->add_control(
323 '_position_description',
324 [
325 'type' => Controls_Manager::ALERT,
326 'alert_type' => 'warning',
327 'heading' => esc_html__( 'Please note!', 'elementor' ),
328 'content' => esc_html__( 'Custom positioning is not considered best practice for responsive web design and should not be used too frequently.', 'elementor' ),
329 'render_type' => 'ui',
330 'condition' => [
331 '_position!' => '',
332 ],
333 ]
334 );
335
336 $this->add_control(
337 '_position',
338 [
339 'label' => esc_html__( 'Position', 'elementor' ),
340 'type' => Controls_Manager::SELECT,
341 'default' => '',
342 'options' => [
343 '' => esc_html__( 'Default', 'elementor' ),
344 'absolute' => esc_html__( 'Absolute', 'elementor' ),
345 'fixed' => esc_html__( 'Fixed', 'elementor' ),
346 ],
347 'prefix_class' => 'elementor-',
348 'frontend_available' => true,
349 'separator' => 'before',
350 ]
351 );
352
353 $start = is_rtl() ? esc_html__( 'Right', 'elementor' ) : esc_html__( 'Left', 'elementor' );
354 $end = ! is_rtl() ? esc_html__( 'Right', 'elementor' ) : esc_html__( 'Left', 'elementor' );
355
356 $this->add_control(
357 '_offset_orientation_h',
358 [
359 'label' => esc_html__( 'Horizontal Orientation', 'elementor' ),
360 'type' => Controls_Manager::CHOOSE,
361 'toggle' => false,
362 'default' => 'start',
363 'options' => [
364 'start' => [
365 'title' => $start,
366 'icon' => 'eicon-h-align-left',
367 ],
368 'end' => [
369 'title' => $end,
370 'icon' => 'eicon-h-align-right',
371 ],
372 ],
373 'classes' => 'elementor-control-start-end',
374 'render_type' => 'ui',
375 'condition' => [
376 '_position!' => '',
377 ],
378 ]
379 );
380
381 $this->add_responsive_control(
382 '_offset_x',
383 [
384 'label' => esc_html__( 'Offset', 'elementor' ),
385 'type' => Controls_Manager::SLIDER,
386 'range' => [
387 'px' => [
388 'min' => -1000,
389 'max' => 1000,
390 ],
391 '%' => [
392 'min' => -200,
393 'max' => 200,
394 ],
395 'vw' => [
396 'min' => -200,
397 'max' => 200,
398 ],
399 'vh' => [
400 'min' => -200,
401 'max' => 200,
402 ],
403 ],
404 'default' => [
405 'size' => 0,
406 ],
407 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'vh', 'custom' ],
408 'selectors' => [
409 'body:not(.rtl) {{WRAPPER}}' => 'left: {{SIZE}}{{UNIT}}',
410 'body.rtl {{WRAPPER}}' => 'right: {{SIZE}}{{UNIT}}',
411 ],
412 'condition' => [
413 '_offset_orientation_h!' => 'end',
414 '_position!' => '',
415 ],
416 ]
417 );
418
419 $this->add_responsive_control(
420 '_offset_x_end',
421 [
422 'label' => esc_html__( 'Offset', 'elementor' ),
423 'type' => Controls_Manager::SLIDER,
424 'range' => [
425 'px' => [
426 'min' => -1000,
427 'max' => 1000,
428 ],
429 '%' => [
430 'min' => -200,
431 'max' => 200,
432 ],
433 'vw' => [
434 'min' => -200,
435 'max' => 200,
436 ],
437 'vh' => [
438 'min' => -200,
439 'max' => 200,
440 ],
441 ],
442 'default' => [
443 'size' => 0,
444 ],
445 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'vh', 'custom' ],
446 'selectors' => [
447 'body:not(.rtl) {{WRAPPER}}' => 'right: {{SIZE}}{{UNIT}}',
448 'body.rtl {{WRAPPER}}' => 'left: {{SIZE}}{{UNIT}}',
449 ],
450 'condition' => [
451 '_offset_orientation_h' => 'end',
452 '_position!' => '',
453 ],
454 ]
455 );
456
457 $this->add_control(
458 '_offset_orientation_v',
459 [
460 'label' => esc_html__( 'Vertical Orientation', 'elementor' ),
461 'type' => Controls_Manager::CHOOSE,
462 'toggle' => false,
463 'default' => 'start',
464 'options' => [
465 'start' => [
466 'title' => esc_html__( 'Top', 'elementor' ),
467 'icon' => 'eicon-v-align-top',
468 ],
469 'end' => [
470 'title' => esc_html__( 'Bottom', 'elementor' ),
471 'icon' => 'eicon-v-align-bottom',
472 ],
473 ],
474 'render_type' => 'ui',
475 'condition' => [
476 '_position!' => '',
477 ],
478 ]
479 );
480
481 $this->add_responsive_control(
482 '_offset_y',
483 [
484 'label' => esc_html__( 'Offset', 'elementor' ),
485 'type' => Controls_Manager::SLIDER,
486 'range' => [
487 'px' => [
488 'min' => -1000,
489 'max' => 1000,
490 ],
491 '%' => [
492 'min' => -200,
493 'max' => 200,
494 ],
495 'vh' => [
496 'min' => -200,
497 'max' => 200,
498 ],
499 'vw' => [
500 'min' => -200,
501 'max' => 200,
502 ],
503 ],
504 'size_units' => [ 'px', '%', 'em', 'rem', 'vh', 'vw', 'custom' ],
505 'default' => [
506 'size' => 0,
507 ],
508 'selectors' => [
509 '{{WRAPPER}}' => 'top: {{SIZE}}{{UNIT}}',
510 ],
511 'condition' => [
512 '_offset_orientation_v!' => 'end',
513 '_position!' => '',
514 ],
515 ]
516 );
517
518 $this->add_responsive_control(
519 '_offset_y_end',
520 [
521 'label' => esc_html__( 'Offset', 'elementor' ),
522 'type' => Controls_Manager::SLIDER,
523 'range' => [
524 'px' => [
525 'min' => -1000,
526 'max' => 1000,
527 ],
528 '%' => [
529 'min' => -200,
530 'max' => 200,
531 ],
532 'vh' => [
533 'min' => -200,
534 'max' => 200,
535 ],
536 'vw' => [
537 'min' => -200,
538 'max' => 200,
539 ],
540 ],
541 'size_units' => [ 'px', '%', 'em', 'rem', 'vh', 'vw', 'custom' ],
542 'default' => [
543 'size' => 0,
544 ],
545 'selectors' => [
546 '{{WRAPPER}}' => 'bottom: {{SIZE}}{{UNIT}}',
547 ],
548 'condition' => [
549 '_offset_orientation_v' => 'end',
550 '_position!' => '',
551 ],
552 ]
553 );
554
555 $this->add_responsive_control(
556 '_z_index',
557 [
558 'label' => esc_html__( 'Z-Index', 'elementor' ),
559 'type' => Controls_Manager::NUMBER,
560 'selectors' => [
561 '{{WRAPPER}}' => 'z-index: {{VALUE}};',
562 ],
563 ]
564 );
565
566 $this->add_control(
567 '_element_id',
568 [
569 'label' => esc_html__( 'CSS ID', 'elementor' ),
570 'type' => Controls_Manager::TEXT,
571 'dynamic' => [
572 'active' => true,
573 ],
574 'ai' => [
575 'active' => false,
576 ],
577 'default' => '',
578 'title' => esc_html__( 'Add your custom id WITHOUT the Pound key. e.g: my-id', 'elementor' ),
579 'style_transfer' => false,
580 'classes' => 'elementor-control-direction-ltr',
581 ]
582 );
583
584 $this->add_control(
585 '_css_classes',
586 [
587 'label' => esc_html__( 'CSS Classes', 'elementor' ),
588 'type' => Controls_Manager::TEXT,
589 'ai' => [
590 'active' => false,
591 ],
592 'dynamic' => [
593 'active' => true,
594 ],
595 'prefix_class' => '',
596 'title' => esc_html__( 'Add your custom class WITHOUT the dot. e.g: my-class', 'elementor' ),
597 'classes' => 'elementor-control-direction-ltr',
598 ]
599 );
600
601 Plugin::$instance->controls_manager->add_display_conditions_controls( $this );
602
603 $this->end_controls_section();
604 }
605
606 /**
607 * Register the Motion Effects section.
608 *
609 * @return void
610 */
611 private function register_effects_section() {
612 $this->start_controls_section(
613 'section_effects',
614 [
615 'label' => esc_html__( 'Motion Effects', 'elementor' ),
616 'tab' => Controls_Manager::TAB_ADVANCED,
617 ]
618 );
619
620 Plugin::$instance->controls_manager->add_motion_effects_promotion_control( $this );
621
622 $this->add_responsive_control(
623 '_animation',
624 [
625 'label' => esc_html__( 'Entrance Animation', 'elementor' ),
626 'type' => Controls_Manager::ANIMATION,
627 'frontend_available' => true,
628 ]
629 );
630
631 $this->add_control(
632 'animation_duration',
633 [
634 'label' => esc_html__( 'Animation Duration', 'elementor' ),
635 'type' => Controls_Manager::SELECT,
636 'default' => '',
637 'options' => [
638 'slow' => esc_html__( 'Slow', 'elementor' ),
639 '' => esc_html__( 'Normal', 'elementor' ),
640 'fast' => esc_html__( 'Fast', 'elementor' ),
641 ],
642 'prefix_class' => 'animated-',
643 'condition' => [
644 '_animation!' => '',
645 ],
646 ]
647 );
648
649 $this->add_control(
650 '_animation_delay',
651 [
652 'label' => esc_html__( 'Animation Delay', 'elementor' ) . ' (ms)',
653 'type' => Controls_Manager::NUMBER,
654 'default' => '',
655 'min' => 0,
656 'step' => 100,
657 'condition' => [
658 '_animation!' => '',
659 ],
660 'render_type' => 'none',
661 'frontend_available' => true,
662 ]
663 );
664
665 $this->end_controls_section();
666 }
667
668 /** Register the Background section.
669 *
670 * @return void
671 */
672 private function register_background_section() {
673 $this->start_controls_section(
674 '_section_background',
675 [
676 'label' => esc_html__( 'Background', 'elementor' ),
677 'tab' => Controls_Manager::TAB_ADVANCED,
678 ]
679 );
680
681 $this->start_controls_tabs( '_tabs_background' );
682
683 $this->start_controls_tab(
684 '_tab_background_normal',
685 [
686 'label' => esc_html__( 'Normal', 'elementor' ),
687 ]
688 );
689
690 $this->add_group_control(
691 Group_Control_Background::get_type(),
692 [
693 'name' => '_background',
694 'selector' => '{{WRAPPER}} > .elementor-widget-container',
695 ]
696 );
697
698 $this->end_controls_tab();
699
700 $this->start_controls_tab(
701 '_tab_background_hover',
702 [
703 'label' => esc_html__( 'Hover', 'elementor' ),
704 ]
705 );
706
707 $this->add_group_control(
708 Group_Control_Background::get_type(),
709 [
710 'name' => '_background_hover',
711 'selector' => '{{WRAPPER}}:hover .elementor-widget-container',
712 ]
713 );
714
715 $this->add_control(
716 '_background_hover_transition',
717 [
718 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
719 'type' => Controls_Manager::SLIDER,
720 'range' => [
721 'px' => [
722 'min' => 0,
723 'max' => 3,
724 'step' => 0.1,
725 ],
726 ],
727 'render_type' => 'ui',
728 'separator' => 'before',
729 'selectors' => [
730 '{{WRAPPER}} > .elementor-widget-container' => 'transition: background {{SIZE}}s',
731 ],
732 ]
733 );
734
735 $this->end_controls_tab();
736
737 $this->end_controls_tabs();
738
739 $this->end_controls_section();
740 }
741
742 /**
743 * Register the Border section.
744 *
745 * @return void
746 */
747 private function register_border_section() {
748 $this->start_controls_section(
749 '_section_border',
750 [
751 'label' => esc_html__( 'Border', 'elementor' ),
752 'tab' => Controls_Manager::TAB_ADVANCED,
753 ]
754 );
755
756 $this->start_controls_tabs( '_tabs_border' );
757
758 $this->start_controls_tab(
759 '_tab_border_normal',
760 [
761 'label' => esc_html__( 'Normal', 'elementor' ),
762 ]
763 );
764
765 $this->add_group_control(
766 Group_Control_Border::get_type(),
767 [
768 'name' => '_border',
769 'selector' => '{{WRAPPER}} > .elementor-widget-container',
770 ]
771 );
772
773 $this->add_responsive_control(
774 '_border_radius',
775 [
776 'label' => esc_html__( 'Border Radius', 'elementor' ),
777 'type' => Controls_Manager::DIMENSIONS,
778 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
779 'selectors' => [
780 '{{WRAPPER}} > .elementor-widget-container' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
781 ],
782 ]
783 );
784
785 $this->add_group_control(
786 Group_Control_Box_Shadow::get_type(),
787 [
788 'name' => '_box_shadow',
789 'selector' => '{{WRAPPER}} > .elementor-widget-container',
790 ]
791 );
792
793 $this->end_controls_tab();
794
795 $this->start_controls_tab(
796 '_tab_border_hover',
797 [
798 'label' => esc_html__( 'Hover', 'elementor' ),
799 ]
800 );
801
802 $this->add_group_control(
803 Group_Control_Border::get_type(),
804 [
805 'name' => '_border_hover',
806 'selector' => '{{WRAPPER}}:hover .elementor-widget-container',
807 ]
808 );
809
810 $this->add_responsive_control(
811 '_border_radius_hover',
812 [
813 'label' => esc_html__( 'Border Radius', 'elementor' ),
814 'type' => Controls_Manager::DIMENSIONS,
815 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
816 'selectors' => [
817 '{{WRAPPER}}:hover > .elementor-widget-container' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
818 ],
819 ]
820 );
821
822 $this->add_group_control(
823 Group_Control_Box_Shadow::get_type(),
824 [
825 'name' => '_box_shadow_hover',
826 'selector' => '{{WRAPPER}}:hover .elementor-widget-container',
827 ]
828 );
829
830 $this->add_control(
831 '_border_hover_transition',
832 [
833 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
834 'type' => Controls_Manager::SLIDER,
835 'separator' => 'before',
836 'range' => [
837 'px' => [
838 'min' => 0,
839 'max' => 3,
840 'step' => 0.1,
841 ],
842 ],
843 'selectors' => [
844 '{{WRAPPER}} .elementor-widget-container' => 'transition: background {{_background_hover_transition.SIZE}}s, border {{SIZE}}s, border-radius {{SIZE}}s, box-shadow {{SIZE}}s',
845 ],
846 ]
847 );
848
849 $this->end_controls_tab();
850
851 $this->end_controls_tabs();
852
853 $this->end_controls_section();
854 }
855
856
857 /**
858 * Register the Mask section.
859 *
860 * @return void
861 */
862 private function register_masking_section() {
863 $this->start_controls_section(
864 '_section_masking',
865 [
866 'label' => esc_html__( 'Mask', 'elementor' ),
867 'tab' => Controls_Manager::TAB_ADVANCED,
868 ]
869 );
870
871 $this->add_control(
872 '_mask_switch',
873 [
874 'label' => esc_html__( 'Mask', 'elementor' ),
875 'type' => Controls_Manager::SWITCHER,
876 'label_on' => esc_html__( 'On', 'elementor' ),
877 'label_off' => esc_html__( 'Off', 'elementor' ),
878 'default' => '',
879 ]
880 );
881
882 $this->add_control(
883 '_mask_shape',
884 [
885 'label' => esc_html__( 'Shape', 'elementor' ),
886 'type' => Controls_Manager::SELECT,
887 'options' => $this->get_shapes(),
888 'default' => 'circle',
889 'selectors' => $this->get_mask_selectors( '-webkit-mask-image: url( ' . ELEMENTOR_ASSETS_URL . '/mask-shapes/{{VALUE}}.svg );' ),
890 'condition' => [
891 '_mask_switch!' => '',
892 ],
893 ]
894 );
895
896 $this->add_control(
897 '_mask_image',
898 [
899 'label' => esc_html__( 'Image', 'elementor' ),
900 'type' => Controls_Manager::MEDIA,
901 'media_types' => [ 'image' ],
902 'should_include_svg_inline_option' => true,
903 'library_type' => 'image/svg+xml',
904 'dynamic' => [
905 'active' => true,
906 ],
907 'selectors' => $this->get_mask_selectors( '-webkit-mask-image: url( {{URL}} );' ),
908 'condition' => [
909 '_mask_switch!' => '',
910 '_mask_shape' => 'custom',
911 ],
912 ]
913 );
914
915 $this->add_control(
916 '_mask_notice',
917 [
918 'type' => Controls_Manager::HIDDEN,
919 'raw' => esc_html__( 'Need More Shapes?', 'elementor' ) .
920 '<br>' .
921 sprintf(
922 '%1$s <a target="_blank" href="https://go.elementor.com/mask-control">%2$s</a>',
923 esc_html__( 'Explore additional Premium Shape packs and use them in your site.', 'elementor' ),
924 esc_html__( 'Learn more', 'elementor' ),
925 ),
926 'content_classes' => 'elementor-panel-alert elementor-panel-alert-info',
927 'condition' => [
928 '_mask_switch!' => '',
929 ],
930 ]
931 );
932
933 $this->add_responsive_control(
934 '_mask_size',
935 [
936 'label' => esc_html__( 'Size', 'elementor' ),
937 'type' => Controls_Manager::SELECT,
938 'options' => [
939 'contain' => esc_html__( 'Fit', 'elementor' ),
940 'cover' => esc_html__( 'Fill', 'elementor' ),
941 'custom' => esc_html__( 'Custom', 'elementor' ),
942 ],
943 'default' => 'contain',
944 'selectors' => $this->get_mask_selectors( '-webkit-mask-size: {{VALUE}};' ),
945 'condition' => [
946 '_mask_switch!' => '',
947 ],
948 ]
949 );
950
951 $this->add_responsive_control(
952 '_mask_size_scale',
953 [
954 'label' => esc_html__( 'Scale', 'elementor' ),
955 'type' => Controls_Manager::SLIDER,
956 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
957 'range' => [
958 'px' => [
959 'min' => 0,
960 'max' => 500,
961 ],
962 'em' => [
963 'min' => 0,
964 'max' => 100,
965 ],
966 '%' => [
967 'min' => 0,
968 'max' => 200,
969 ],
970 ],
971 'default' => [
972 'unit' => '%',
973 'size' => 100,
974 ],
975 'selectors' => $this->get_mask_selectors( '-webkit-mask-size: {{SIZE}}{{UNIT}};' ),
976 'condition' => [
977 '_mask_switch!' => '',
978 '_mask_size' => 'custom',
979 ],
980 ]
981 );
982
983 $this->add_responsive_control(
984 '_mask_position',
985 [
986 'label' => esc_html__( 'Position', 'elementor' ),
987 'type' => Controls_Manager::SELECT,
988 'options' => [
989 'center center' => esc_html__( 'Center Center', 'elementor' ),
990 'center left' => esc_html__( 'Center Left', 'elementor' ),
991 'center right' => esc_html__( 'Center Right', 'elementor' ),
992 'top center' => esc_html__( 'Top Center', 'elementor' ),
993 'top left' => esc_html__( 'Top Left', 'elementor' ),
994 'top right' => esc_html__( 'Top Right', 'elementor' ),
995 'bottom center' => esc_html__( 'Bottom Center', 'elementor' ),
996 'bottom left' => esc_html__( 'Bottom Left', 'elementor' ),
997 'bottom right' => esc_html__( 'Bottom Right', 'elementor' ),
998 'custom' => esc_html__( 'Custom', 'elementor' ),
999 ],
1000 'default' => 'center center',
1001 'selectors' => $this->get_mask_selectors( '-webkit-mask-position: {{VALUE}};' ),
1002 'condition' => [
1003 '_mask_switch!' => '',
1004 ],
1005 ]
1006 );
1007
1008 $this->add_responsive_control(
1009 '_mask_position_x',
1010 [
1011 'label' => esc_html__( 'X Position', 'elementor' ),
1012 'type' => Controls_Manager::SLIDER,
1013 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1014 'range' => [
1015 'px' => [
1016 'min' => -500,
1017 'max' => 500,
1018 ],
1019 'em' => [
1020 'min' => -100,
1021 'max' => 100,
1022 ],
1023 '%' => [
1024 'min' => -100,
1025 'max' => 100,
1026 ],
1027 'vw' => [
1028 'min' => -100,
1029 'max' => 100,
1030 ],
1031 ],
1032 'default' => [
1033 'unit' => '%',
1034 'size' => 0,
1035 ],
1036 'selectors' => $this->get_mask_selectors( '-webkit-mask-position-x: {{SIZE}}{{UNIT}};' ),
1037 'condition' => [
1038 '_mask_switch!' => '',
1039 '_mask_position' => 'custom',
1040 ],
1041 ]
1042 );
1043
1044 $this->add_responsive_control(
1045 '_mask_position_y',
1046 [
1047 'label' => esc_html__( 'Y Position', 'elementor' ),
1048 'type' => Controls_Manager::SLIDER,
1049 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1050 'range' => [
1051 'px' => [
1052 'min' => -500,
1053 'max' => 500,
1054 ],
1055 'em' => [
1056 'min' => -100,
1057 'max' => 100,
1058 ],
1059 '%' => [
1060 'min' => -100,
1061 'max' => 100,
1062 ],
1063 'vw' => [
1064 'min' => -100,
1065 'max' => 100,
1066 ],
1067 ],
1068 'default' => [
1069 'unit' => '%',
1070 'size' => 0,
1071 ],
1072 'selectors' => $this->get_mask_selectors( '-webkit-mask-position-y: {{SIZE}}{{UNIT}};' ),
1073 'condition' => [
1074 '_mask_switch!' => '',
1075 '_mask_position' => 'custom',
1076 ],
1077 ]
1078 );
1079
1080 $this->add_responsive_control(
1081 '_mask_repeat',
1082 [
1083 'label' => esc_html__( 'Repeat', 'elementor' ),
1084 'type' => Controls_Manager::SELECT,
1085 'options' => [
1086 'no-repeat' => esc_html__( 'No-repeat', 'elementor' ),
1087 'repeat' => esc_html__( 'Repeat', 'elementor' ),
1088 'repeat-x' => esc_html__( 'Repeat-x', 'elementor' ),
1089 'repeat-Y' => esc_html__( 'Repeat-y', 'elementor' ),
1090 'round' => esc_html__( 'Round', 'elementor' ),
1091 'space' => esc_html__( 'Space', 'elementor' ),
1092 ],
1093 'default' => 'no-repeat',
1094 'selectors' => $this->get_mask_selectors( '-webkit-mask-repeat: {{VALUE}};' ),
1095 'condition' => [
1096 '_mask_switch!' => '',
1097 '_mask_size!' => 'cover',
1098 ],
1099 ]
1100 );
1101
1102 $this->end_controls_section();
1103 }
1104
1105
1106 /**
1107 * Register the Responsive section.
1108 *
1109 * @return void
1110 */
1111 private function register_responsive_section() {
1112 $this->start_controls_section(
1113 '_section_responsive',
1114 [
1115 'label' => esc_html__( 'Responsive', 'elementor' ),
1116 'tab' => Controls_Manager::TAB_ADVANCED,
1117 ]
1118 );
1119
1120 $this->add_control(
1121 'responsive_description',
1122 [
1123 'raw' => sprintf(
1124 /* translators: 1: Link open tag, 2: Link close tag. */
1125 esc_html__( 'Responsive visibility will take effect only on %1$s preview mode %2$s or live page, and not while editing in Elementor.', 'elementor' ),
1126 '<a href="javascript: $e.run( \'panel/close\' )">',
1127 '</a>'
1128 ),
1129 'type' => Controls_Manager::RAW_HTML,
1130 'content_classes' => 'elementor-descriptor',
1131 ]
1132 );
1133
1134 $this->add_hidden_device_controls();
1135
1136 $this->end_controls_section();
1137 }
1138
1139 /**
1140 * Register common widget controls.
1141 *
1142 * Adds different input fields to allow the user to change and customize the widget settings.
1143 *
1144 * @since 3.1.0
1145 * @access protected
1146 */
1147 protected function register_controls() {
1148 $this->register_layout_section();
1149
1150 $this->register_effects_section();
1151
1152 $this->register_transform_section();
1153
1154 $this->register_background_section();
1155
1156 $this->register_border_section();
1157
1158 $this->register_masking_section();
1159
1160 $this->register_responsive_section();
1161
1162 Plugin::$instance->controls_manager->add_custom_attributes_controls( $this );
1163
1164 Plugin::$instance->controls_manager->add_custom_css_controls( $this );
1165 }
1166 }
1167