PluginProbe
Elementor Website Builder – more than just a page builder / 3.26.2
Elementor Website Builder – more than just a page builder v3.26.2
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-base.php

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

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