PluginProbe
Elementor Website Builder – more than just a page builder / 3.30.0-dev3
Elementor Website Builder – more than just a page builder v3.30.0-dev3
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.30.0-dev3, at includes/widgets/common-base.php

1,393 lines 34.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 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 String $shape 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 * Get a list of the available mask shapes.
128 *
129 * @param bool $custom_button Determine if the output should contain `Custom Mask` button.
130 *
131 * @return array A list of mask shapes.
132 */
133 private function get_shapes( $custom_button = true ): array {
134 $shapes = [
135 'circle' => [
136 'title' => esc_html__( 'Circle', 'elementor' ),
137 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/circle.svg',
138 ],
139 'oval-vertical' => [
140 'title' => esc_html__( 'Oval vertical', 'elementor' ),
141 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/oval-vertical.svg',
142 ],
143 'oval-horizontal' => [
144 'title' => esc_html__( 'Oval horizontal', 'elementor' ),
145 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/oval-horizontal.svg',
146 ],
147 'pill-vertical' => [
148 'title' => esc_html__( 'Pill vertical', 'elementor' ),
149 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/pill-vertical.svg',
150 ],
151 'pill-horizontal' => [
152 'title' => esc_html__( 'Pill horizontal', 'elementor' ),
153 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/pill-horizontal.svg',
154 ],
155 'triangle' => [
156 'title' => esc_html__( 'Triangle', 'elementor' ),
157 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/triangle.svg',
158 ],
159 'diamond' => [
160 'title' => esc_html__( 'Diamond', 'elementor' ),
161 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/diamond.svg',
162 ],
163 'pentagon' => [
164 'title' => esc_html__( 'Pentagon', 'elementor' ),
165 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/pentagon.svg',
166 ],
167 'hexagon-vertical' => [
168 'title' => esc_html__( 'Hexagon vertical', 'elementor' ),
169 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/hexagon-vertical.svg',
170 ],
171 'hexagon-horizontal' => [
172 'title' => esc_html__( 'Hexagon horizontal', 'elementor' ),
173 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/hexagon-horizontal.svg',
174 ],
175 'heptagon' => [
176 'title' => esc_html__( 'Heptagon', 'elementor' ),
177 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/heptagon.svg',
178 ],
179 'octagon' => [
180 'title' => esc_html__( 'Octagon', 'elementor' ),
181 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/octagon.svg',
182 ],
183 'parallelogram-right' => [
184 'title' => esc_html__( 'Parallelogram right', 'elementor' ),
185 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/parallelogram-right.svg',
186 ],
187 'parallelogram-left' => [
188 'title' => esc_html__( 'Parallelogram left', 'elementor' ),
189 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/parallelogram-left.svg',
190 ],
191 'trapezoid-up' => [
192 'title' => esc_html__( 'Trapezoid Up', 'elementor' ),
193 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/trapezoid-up.svg',
194 ],
195 'trapezoid-down' => [
196 'title' => esc_html__( 'Trapezoid Down', 'elementor' ),
197 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/trapezoid-down.svg',
198 ],
199 'flower' => [
200 'title' => esc_html__( 'Flower', 'elementor' ),
201 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/flower.svg',
202 ],
203 'sketch' => [
204 'title' => esc_html__( 'Sketch', 'elementor' ),
205 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/sketch.svg',
206 ],
207 'hexagon' => [
208 'title' => esc_html__( 'Hexagon Donut', 'elementor' ),
209 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/hexagon.svg',
210 ],
211 'blob' => [
212 'title' => esc_html__( 'Blob', 'elementor' ),
213 'image' => ELEMENTOR_ASSETS_URL . 'mask-shapes/blob.svg',
214 ],
215 ];
216
217 $shapes = array_merge( $shapes, self::get_additional_mask_shapes() );
218
219 if ( $custom_button ) {
220 $shapes['custom'] = [
221 'type' => 'button',
222 'title' => esc_html__( 'Custom Mask', 'elementor' ),
223 ];
224 }
225
226 return $shapes;
227 }
228
229 /**
230 * Get additional mask shapes.
231 *
232 * Used to add custom mask shapes to elementor.
233 *
234 * @since 3.30.0
235 *
236 * @return array A list of additional mask shapes.
237 */
238 private static function get_additional_mask_shapes(): array {
239 static $additional_mask_shapes = null;
240
241 if ( null !== $additional_mask_shapes ) {
242 return $additional_mask_shapes;
243 }
244
245 $additional_mask_shapes = [];
246
247 /**
248 * Additional mask shapes.
249 *
250 * Filters the mask shapes used by Elementor to add additional mask shapes.
251 *
252 * @since 3.30.0
253 *
254 * @param array $additional_mask_shapes Additional mask shapes.
255 */
256 $additional_mask_shapes = apply_filters( 'elementor/mask_shapes/additional_shapes', $additional_mask_shapes );
257
258 return $additional_mask_shapes;
259 }
260
261 /**
262 * Gets a string of CSS rules to apply, and returns an array of selectors with those rules.
263 * This function has been created in order to deal with masking for image widget.
264 * For most of the widgets the mask is being applied to the wrapper itself, but in the case of an image widget,
265 * the `img` tag should be masked directly. So instead of writing a lot of selectors every time,
266 * this function builds both of those selectors easily.
267 *
268 * @param string $rules The CSS rules to apply.
269 *
270 * @return array Selectors with the rules applied.
271 */
272 private function get_mask_selectors( $rules ) {
273 $mask_selectors = [
274 'default' => static::MASK_SELECTOR_DEFAULT,
275 'image' => static::MASK_SELECTOR_IMG,
276 ];
277
278 return [
279 $mask_selectors['default'] => $rules,
280 $mask_selectors['image'] => $rules,
281 ];
282 }
283
284 /**
285 * Register the Layout section.
286 *
287 * @return void
288 */
289 private function register_layout_section() {
290 $this->start_controls_section(
291 '_section_style',
292 [
293 'label' => esc_html__( 'Layout', 'elementor' ),
294 'tab' => Controls_Manager::TAB_ADVANCED,
295 ]
296 );
297
298 // Element Name for the Navigator
299 $this->add_control(
300 '_title',
301 [
302 'label' => esc_html__( 'Title', 'elementor' ),
303 'type' => Controls_Manager::HIDDEN,
304 'render_type' => 'none',
305 ]
306 );
307
308 $this->add_responsive_control(
309 '_margin',
310 [
311 'label' => esc_html__( 'Margin', 'elementor' ),
312 'type' => Controls_Manager::DIMENSIONS,
313 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
314 'selectors' => [
315 static::WRAPPER_SELECTOR_CHILD => static::MARGIN,
316 ],
317 ]
318 );
319
320 $this->add_responsive_control(
321 '_padding',
322 [
323 'label' => esc_html__( 'Padding', 'elementor' ),
324 'type' => Controls_Manager::DIMENSIONS,
325 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
326 'selectors' => [
327 static::WRAPPER_SELECTOR_CHILD => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
328 ],
329 ]
330 );
331
332 $experiments_manager = Plugin::$instance->experiments;
333 $is_container_active = $experiments_manager->is_feature_active( 'container' );
334
335 $this->add_responsive_control(
336 '_element_width',
337 [
338 'label' => esc_html__( 'Width', 'elementor' ),
339 'type' => Controls_Manager::SELECT,
340 'default' => '',
341 'options' => [
342 '' => esc_html__( 'Default', 'elementor' ),
343 'inherit' => esc_html__( 'Full Width', 'elementor' ) . ' (100%)',
344 'auto' => esc_html__( 'Inline', 'elementor' ) . ' (auto)',
345 'initial' => esc_html__( 'Custom', 'elementor' ),
346 ],
347 'selectors_dictionary' => [
348 'inherit' => '100%',
349 ],
350 'prefix_class' => 'elementor-widget%s__width-',
351 'selectors' => [
352 '{{WRAPPER}}' => 'width: {{VALUE}}; max-width: {{VALUE}}',
353 ],
354 ]
355 );
356
357 $this->add_responsive_control(
358 '_element_custom_width',
359 [
360 'label' => esc_html__( 'Custom Width', 'elementor' ),
361 'type' => Controls_Manager::SLIDER,
362 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
363 'default' => [
364 'unit' => '%',
365 ],
366 'range' => [
367 'px' => [
368 'max' => 1000,
369 ],
370 ],
371 'selectors' => [
372 '{{WRAPPER}}' => '--container-widget-width: {{SIZE}}{{UNIT}}; --container-widget-flex-grow: 0; width: var( --container-widget-width, {{SIZE}}{{UNIT}} ); max-width: {{SIZE}}{{UNIT}}',
373 ],
374 'condition' => [ '_element_width' => 'initial' ],
375 ]
376 );
377
378 $this->add_control(
379 '_heading_grid_item',
380 [
381 'type' => Controls_Manager::HEADING,
382 'label' => esc_html__( 'Grid Item', 'elementor' ),
383 'separator' => 'before',
384 ]
385 );
386
387 $this->add_responsive_control(
388 '_grid_column',
389 [
390 'label' => esc_html__( 'Column Span', 'elementor' ),
391 'type' => Controls_Manager::SELECT,
392 'options' => [
393 '' => ' Default',
394 '1' => '1',
395 '2' => '2',
396 '3' => '3',
397 '4' => '4',
398 '5' => '5',
399 '6' => '6',
400 '7' => '7',
401 '8' => '8',
402 '9' => '9',
403 '10' => '10',
404 '11' => '11',
405 '12' => '12',
406 'custom' => 'Custom',
407 ],
408 'selectors' => [
409 '{{WRAPPER}}' => 'grid-column: span {{VALUE}};',
410 ],
411 ]
412 );
413
414 $this->add_responsive_control(
415 '_grid_column_custom',
416 [
417 'label' => esc_html__( 'Custom', 'elementor' ),
418 'type' => Controls_Manager::TEXT,
419 'ai' => [
420 'active' => false,
421 ],
422 'selectors' => [
423 '{{WRAPPER}}' => 'grid-column: {{VALUE}}',
424 ],
425 'condition' => [
426 '_grid_column' => 'custom',
427 ],
428 ]
429 );
430
431 $this->add_responsive_control(
432 '_grid_row',
433 [
434 'label' => esc_html__( 'Row Span', 'elementor' ),
435 'type' => Controls_Manager::SELECT,
436 'options' => [
437 '' => ' Default',
438 '1' => '1',
439 '2' => '2',
440 '3' => '3',
441 '4' => '4',
442 '5' => '5',
443 '6' => '6',
444 '7' => '7',
445 '8' => '8',
446 '9' => '9',
447 '10' => '10',
448 '11' => '11',
449 '12' => '12',
450 'custom' => 'Custom',
451 ],
452 'selectors' => [
453 '{{WRAPPER}}' => 'grid-row: span {{VALUE}};',
454 ],
455 ]
456 );
457
458 $this->add_responsive_control(
459 '_grid_row_custom',
460 [
461 'label' => esc_html__( 'Custom', 'elementor' ),
462 'type' => Controls_Manager::TEXT,
463 'separator' => 'after',
464 'ai' => [
465 'active' => false,
466 ],
467 'selectors' => [
468 '{{WRAPPER}}' => 'grid-row: {{VALUE}}',
469 ],
470 'condition' => [
471 '_grid_row' => 'custom',
472 ],
473 ]
474 );
475
476 // Register Flex controls only if the Container experiment is active.
477 if ( $is_container_active ) {
478 $this->add_group_control(
479 Group_Control_Flex_Item::get_type(),
480 [
481 'name' => '_flex',
482 // Hack to increase specificity and make sure that the current widget overrides the
483 // parent flex settings.
484 'selector' => '{{WRAPPER}}.elementor-element',
485 'include' => [
486 'align_self',
487 'order',
488 'order_custom',
489 'size',
490 'grow',
491 'shrink',
492 ],
493 'fields_options' => [
494 'align_self' => [
495 'separator' => 'before',
496 ],
497 ],
498 ]
499 );
500 }
501
502 $vertical_align_conditions = [
503 '_element_width!' => '',
504 '_position' => '',
505 ];
506
507 if ( $is_container_active ) {
508 $vertical_align_conditions['_element_vertical_align!'] = ''; // TODO: For BC.
509 }
510
511 // TODO: For BC - Remove in the future.
512 $this->add_responsive_control(
513 '_element_vertical_align',
514 [
515 'label' => esc_html__( 'Vertical Align', 'elementor' ),
516 'type' => Controls_Manager::CHOOSE,
517 'options' => [
518 'flex-start' => [
519 'title' => esc_html__( 'Start', 'elementor' ),
520 'icon' => 'eicon-v-align-top',
521 ],
522 'center' => [
523 'title' => esc_html__( 'Center', 'elementor' ),
524 'icon' => 'eicon-v-align-middle',
525 ],
526 'flex-end' => [
527 'title' => esc_html__( 'End', 'elementor' ),
528 'icon' => 'eicon-v-align-bottom',
529 ],
530 ],
531 'condition' => $vertical_align_conditions,
532 'selectors' => [
533 '{{WRAPPER}}' => 'align-self: {{VALUE}}',
534 ],
535 ]
536 );
537
538 $this->add_control(
539 '_position_description',
540 [
541 'type' => Controls_Manager::ALERT,
542 'alert_type' => 'warning',
543 'heading' => esc_html__( 'Please note!', 'elementor' ),
544 'content' => esc_html__( 'Custom positioning is not considered best practice for responsive web design and should not be used too frequently.', 'elementor' ),
545 'render_type' => 'ui',
546 'condition' => [
547 '_position!' => '',
548 ],
549 ]
550 );
551
552 $this->add_control(
553 '_position',
554 [
555 'label' => esc_html__( 'Position', 'elementor' ),
556 'type' => Controls_Manager::SELECT,
557 'default' => '',
558 'options' => [
559 '' => esc_html__( 'Default', 'elementor' ),
560 'absolute' => esc_html__( 'Absolute', 'elementor' ),
561 'fixed' => esc_html__( 'Fixed', 'elementor' ),
562 ],
563 'prefix_class' => 'elementor-',
564 'frontend_available' => true,
565 'separator' => 'before',
566 ]
567 );
568
569 $start = is_rtl() ? esc_html__( 'Right', 'elementor' ) : esc_html__( 'Left', 'elementor' );
570 $end = ! is_rtl() ? esc_html__( 'Right', 'elementor' ) : esc_html__( 'Left', 'elementor' );
571
572 $this->add_control(
573 '_offset_orientation_h',
574 [
575 'label' => esc_html__( 'Horizontal Orientation', 'elementor' ),
576 'type' => Controls_Manager::CHOOSE,
577 'toggle' => false,
578 'default' => 'start',
579 'options' => [
580 'start' => [
581 'title' => $start,
582 'icon' => 'eicon-h-align-left',
583 ],
584 'end' => [
585 'title' => $end,
586 'icon' => 'eicon-h-align-right',
587 ],
588 ],
589 'classes' => 'elementor-control-start-end',
590 'render_type' => 'ui',
591 'condition' => [
592 '_position!' => '',
593 ],
594 ]
595 );
596
597 $this->add_responsive_control(
598 '_offset_x',
599 [
600 'label' => esc_html__( 'Offset', 'elementor' ),
601 'type' => Controls_Manager::SLIDER,
602 'range' => [
603 'px' => [
604 'min' => -1000,
605 'max' => 1000,
606 ],
607 '%' => [
608 'min' => -200,
609 'max' => 200,
610 ],
611 'vw' => [
612 'min' => -200,
613 'max' => 200,
614 ],
615 'vh' => [
616 'min' => -200,
617 'max' => 200,
618 ],
619 ],
620 'default' => [
621 'size' => 0,
622 ],
623 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'vh', 'custom' ],
624 'selectors' => [
625 'body:not(.rtl) {{WRAPPER}}' => 'left: {{SIZE}}{{UNIT}}',
626 'body.rtl {{WRAPPER}}' => 'right: {{SIZE}}{{UNIT}}',
627 ],
628 'condition' => [
629 '_offset_orientation_h!' => 'end',
630 '_position!' => '',
631 ],
632 ]
633 );
634
635 $this->add_responsive_control(
636 '_offset_x_end',
637 [
638 'label' => esc_html__( 'Offset', 'elementor' ),
639 'type' => Controls_Manager::SLIDER,
640 'range' => [
641 'px' => [
642 'min' => -1000,
643 'max' => 1000,
644 ],
645 '%' => [
646 'min' => -200,
647 'max' => 200,
648 ],
649 'vw' => [
650 'min' => -200,
651 'max' => 200,
652 ],
653 'vh' => [
654 'min' => -200,
655 'max' => 200,
656 ],
657 ],
658 'default' => [
659 'size' => 0,
660 ],
661 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'vh', 'custom' ],
662 'selectors' => [
663 'body:not(.rtl) {{WRAPPER}}' => 'right: {{SIZE}}{{UNIT}}',
664 'body.rtl {{WRAPPER}}' => 'left: {{SIZE}}{{UNIT}}',
665 ],
666 'condition' => [
667 '_offset_orientation_h' => 'end',
668 '_position!' => '',
669 ],
670 ]
671 );
672
673 $this->add_control(
674 '_offset_orientation_v',
675 [
676 'label' => esc_html__( 'Vertical Orientation', 'elementor' ),
677 'type' => Controls_Manager::CHOOSE,
678 'toggle' => false,
679 'default' => 'start',
680 'options' => [
681 'start' => [
682 'title' => esc_html__( 'Top', 'elementor' ),
683 'icon' => 'eicon-v-align-top',
684 ],
685 'end' => [
686 'title' => esc_html__( 'Bottom', 'elementor' ),
687 'icon' => 'eicon-v-align-bottom',
688 ],
689 ],
690 'render_type' => 'ui',
691 'condition' => [
692 '_position!' => '',
693 ],
694 ]
695 );
696
697 $this->add_responsive_control(
698 '_offset_y',
699 [
700 'label' => esc_html__( 'Offset', 'elementor' ),
701 'type' => Controls_Manager::SLIDER,
702 'range' => [
703 'px' => [
704 'min' => -1000,
705 'max' => 1000,
706 ],
707 '%' => [
708 'min' => -200,
709 'max' => 200,
710 ],
711 'vh' => [
712 'min' => -200,
713 'max' => 200,
714 ],
715 'vw' => [
716 'min' => -200,
717 'max' => 200,
718 ],
719 ],
720 'size_units' => [ 'px', '%', 'em', 'rem', 'vh', 'vw', 'custom' ],
721 'default' => [
722 'size' => 0,
723 ],
724 'selectors' => [
725 '{{WRAPPER}}' => 'top: {{SIZE}}{{UNIT}}',
726 ],
727 'condition' => [
728 '_offset_orientation_v!' => 'end',
729 '_position!' => '',
730 ],
731 ]
732 );
733
734 $this->add_responsive_control(
735 '_offset_y_end',
736 [
737 'label' => esc_html__( 'Offset', 'elementor' ),
738 'type' => Controls_Manager::SLIDER,
739 'range' => [
740 'px' => [
741 'min' => -1000,
742 'max' => 1000,
743 ],
744 '%' => [
745 'min' => -200,
746 'max' => 200,
747 ],
748 'vh' => [
749 'min' => -200,
750 'max' => 200,
751 ],
752 'vw' => [
753 'min' => -200,
754 'max' => 200,
755 ],
756 ],
757 'size_units' => [ 'px', '%', 'em', 'rem', 'vh', 'vw', 'custom' ],
758 'default' => [
759 'size' => 0,
760 ],
761 'selectors' => [
762 '{{WRAPPER}}' => 'bottom: {{SIZE}}{{UNIT}}',
763 ],
764 'condition' => [
765 '_offset_orientation_v' => 'end',
766 '_position!' => '',
767 ],
768 ]
769 );
770
771 $this->add_responsive_control(
772 '_z_index',
773 [
774 'label' => esc_html__( 'Z-Index', 'elementor' ),
775 'type' => Controls_Manager::NUMBER,
776 'selectors' => [
777 '{{WRAPPER}}' => 'z-index: {{VALUE}};',
778 ],
779 ]
780 );
781
782 $this->add_control(
783 '_element_id',
784 [
785 'label' => esc_html__( 'CSS ID', 'elementor' ),
786 'type' => Controls_Manager::TEXT,
787 'dynamic' => [
788 'active' => true,
789 ],
790 'ai' => [
791 'active' => false,
792 ],
793 'default' => '',
794 'title' => esc_html__( 'Add your custom id WITHOUT the Pound key. e.g: my-id', 'elementor' ),
795 'style_transfer' => false,
796 'classes' => 'elementor-control-direction-ltr',
797 ]
798 );
799
800 $this->add_control(
801 '_css_classes',
802 [
803 'label' => esc_html__( 'CSS Classes', 'elementor' ),
804 'type' => Controls_Manager::TEXT,
805 'ai' => [
806 'active' => false,
807 ],
808 'dynamic' => [
809 'active' => true,
810 ],
811 'prefix_class' => '',
812 'title' => esc_html__( 'Add your custom class WITHOUT the dot. e.g: my-class', 'elementor' ),
813 'classes' => 'elementor-control-direction-ltr',
814 ]
815 );
816
817 Plugin::$instance->controls_manager->add_display_conditions_controls( $this );
818
819 $this->end_controls_section();
820 }
821
822 /**
823 * Register the Motion Effects section.
824 *
825 * @return void
826 */
827 private function register_effects_section() {
828 $this->start_controls_section(
829 'section_effects',
830 [
831 'label' => esc_html__( 'Motion Effects', 'elementor' ),
832 'tab' => Controls_Manager::TAB_ADVANCED,
833 ]
834 );
835
836 Plugin::$instance->controls_manager->add_motion_effects_promotion_control( $this );
837
838 $this->add_responsive_control(
839 '_animation',
840 [
841 'label' => esc_html__( 'Entrance Animation', 'elementor' ),
842 'type' => Controls_Manager::ANIMATION,
843 'frontend_available' => true,
844 ]
845 );
846
847 $this->add_control(
848 'animation_duration',
849 [
850 'label' => esc_html__( 'Animation Duration', 'elementor' ),
851 'type' => Controls_Manager::SELECT,
852 'default' => '',
853 'options' => [
854 'slow' => esc_html__( 'Slow', 'elementor' ),
855 '' => esc_html__( 'Normal', 'elementor' ),
856 'fast' => esc_html__( 'Fast', 'elementor' ),
857 ],
858 'prefix_class' => 'animated-',
859 'condition' => [
860 '_animation!' => '',
861 ],
862 ]
863 );
864
865 $this->add_control(
866 '_animation_delay',
867 [
868 'label' => esc_html__( 'Animation Delay', 'elementor' ) . ' (ms)',
869 'type' => Controls_Manager::NUMBER,
870 'default' => '',
871 'min' => 0,
872 'step' => 100,
873 'condition' => [
874 '_animation!' => '',
875 ],
876 'render_type' => 'none',
877 'frontend_available' => true,
878 ]
879 );
880
881 $this->end_controls_section();
882 }
883
884 /** Register the Background section.
885 *
886 * @return void
887 */
888 private function register_background_section() {
889 $this->start_controls_section(
890 '_section_background',
891 [
892 'label' => esc_html__( 'Background', 'elementor' ),
893 'tab' => Controls_Manager::TAB_ADVANCED,
894 ]
895 );
896
897 $this->start_controls_tabs( '_tabs_background' );
898
899 $this->start_controls_tab(
900 '_tab_background_normal',
901 [
902 'label' => esc_html__( 'Normal', 'elementor' ),
903 ]
904 );
905
906 $this->add_group_control(
907 Group_Control_Background::get_type(),
908 [
909 'name' => '_background',
910 'selector' => static::WRAPPER_SELECTOR_CHILD,
911 ]
912 );
913
914 $this->end_controls_tab();
915
916 $this->start_controls_tab(
917 '_tab_background_hover',
918 [
919 'label' => esc_html__( 'Hover', 'elementor' ),
920 ]
921 );
922
923 $this->add_group_control(
924 Group_Control_Background::get_type(),
925 [
926 'name' => '_background_hover',
927 'selector' => static::WRAPPER_SELECTOR_HOVER,
928 ]
929 );
930
931 $this->add_control(
932 '_background_hover_transition',
933 [
934 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
935 'type' => Controls_Manager::SLIDER,
936 'range' => [
937 'px' => [
938 'min' => 0,
939 'max' => 3,
940 'step' => 0.1,
941 ],
942 ],
943 'render_type' => 'ui',
944 'separator' => 'before',
945 'selectors' => [
946 static::WRAPPER_SELECTOR_CHILD => 'transition: background {{SIZE}}s',
947 ],
948 ]
949 );
950
951 $this->end_controls_tab();
952
953 $this->end_controls_tabs();
954
955 $this->end_controls_section();
956 }
957
958 /**
959 * Register the Border section.
960 *
961 * @return void
962 */
963 private function register_border_section() {
964 $this->start_controls_section(
965 '_section_border',
966 [
967 'label' => esc_html__( 'Border', 'elementor' ),
968 'tab' => Controls_Manager::TAB_ADVANCED,
969 ]
970 );
971
972 $this->start_controls_tabs( '_tabs_border' );
973
974 $this->start_controls_tab(
975 '_tab_border_normal',
976 [
977 'label' => esc_html__( 'Normal', 'elementor' ),
978 ]
979 );
980
981 $this->add_group_control(
982 Group_Control_Border::get_type(),
983 [
984 'name' => '_border',
985 'selector' => static::WRAPPER_SELECTOR_CHILD,
986 ]
987 );
988
989 $this->add_responsive_control(
990 '_border_radius',
991 [
992 'label' => esc_html__( 'Border Radius', 'elementor' ),
993 'type' => Controls_Manager::DIMENSIONS,
994 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
995 'selectors' => [
996 static::WRAPPER_SELECTOR_CHILD => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
997 ],
998 ]
999 );
1000
1001 $this->add_group_control(
1002 Group_Control_Box_Shadow::get_type(),
1003 [
1004 'name' => '_box_shadow',
1005 'selector' => static::WRAPPER_SELECTOR_CHILD,
1006 ]
1007 );
1008
1009 $this->end_controls_tab();
1010
1011 $this->start_controls_tab(
1012 '_tab_border_hover',
1013 [
1014 'label' => esc_html__( 'Hover', 'elementor' ),
1015 ]
1016 );
1017
1018 $this->add_group_control(
1019 Group_Control_Border::get_type(),
1020 [
1021 'name' => '_border_hover',
1022 'selector' => static::WRAPPER_SELECTOR_HOVER,
1023 ]
1024 );
1025
1026 $this->add_responsive_control(
1027 '_border_radius_hover',
1028 [
1029 'label' => esc_html__( 'Border Radius', 'elementor' ),
1030 'type' => Controls_Manager::DIMENSIONS,
1031 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
1032 'selectors' => [
1033 static::WRAPPER_SELECTOR_HOVER_CHILD => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1034 ],
1035 ]
1036 );
1037
1038 $this->add_group_control(
1039 Group_Control_Box_Shadow::get_type(),
1040 [
1041 'name' => '_box_shadow_hover',
1042 'selector' => static::WRAPPER_SELECTOR_HOVER,
1043 ]
1044 );
1045
1046 $this->add_control(
1047 '_border_hover_transition',
1048 [
1049 'label' => esc_html__( 'Transition Duration', 'elementor' ) . ' (s)',
1050 'type' => Controls_Manager::SLIDER,
1051 'separator' => 'before',
1052 'range' => [
1053 'px' => [
1054 'min' => 0,
1055 'max' => 3,
1056 'step' => 0.1,
1057 ],
1058 ],
1059 'selectors' => [
1060 static::WRAPPER_SELECTOR => 'transition: background {{_background_hover_transition.SIZE}}s, border {{SIZE}}s, border-radius {{SIZE}}s, box-shadow {{SIZE}}s',
1061 ],
1062 ]
1063 );
1064
1065 $this->end_controls_tab();
1066
1067 $this->end_controls_tabs();
1068
1069 $this->end_controls_section();
1070 }
1071
1072
1073 /**
1074 * Register the Mask section.
1075 *
1076 * @return void
1077 */
1078 private function register_masking_section() {
1079 $this->start_controls_section(
1080 '_section_masking',
1081 [
1082 'label' => esc_html__( 'Mask', 'elementor' ),
1083 'tab' => Controls_Manager::TAB_ADVANCED,
1084 ]
1085 );
1086
1087 $this->add_control(
1088 '_mask_switch',
1089 [
1090 'label' => esc_html__( 'Mask', 'elementor' ),
1091 'type' => Controls_Manager::SWITCHER,
1092 'label_on' => esc_html__( 'On', 'elementor' ),
1093 'label_off' => esc_html__( 'Off', 'elementor' ),
1094 'default' => '',
1095 ]
1096 );
1097
1098 $this->add_control(
1099 '_mask_shape',
1100 [
1101 'label' => esc_html__( 'Shape', 'elementor' ),
1102 'type' => Controls_Manager::VISUAL_CHOICE,
1103 'label_block' => true,
1104 'columns' => 4,
1105 'options' => $this->get_shapes(),
1106 'default' => 'circle',
1107 'selectors' => $this->get_mask_selectors( '-webkit-mask-image: url( ' . ELEMENTOR_ASSETS_URL . 'mask-shapes/{{VALUE}}.svg );' ),
1108 'condition' => [
1109 '_mask_switch!' => '',
1110 ],
1111 ]
1112 );
1113
1114 $this->add_control(
1115 '_mask_image',
1116 [
1117 'label' => esc_html__( 'Image', 'elementor' ),
1118 'type' => Controls_Manager::MEDIA,
1119 'media_types' => [ 'image' ],
1120 'should_include_svg_inline_option' => true,
1121 'library_type' => 'image/svg+xml',
1122 'dynamic' => [
1123 'active' => true,
1124 ],
1125 'selectors' => $this->get_mask_selectors( '-webkit-mask-image: url( {{URL}} );' ),
1126 'condition' => [
1127 '_mask_switch!' => '',
1128 '_mask_shape' => 'custom',
1129 ],
1130 ]
1131 );
1132
1133 $this->add_control(
1134 '_mask_notice',
1135 [
1136 'type' => Controls_Manager::HIDDEN,
1137 'raw' => esc_html__( 'Need More Shapes?', 'elementor' ) .
1138 '<br>' .
1139 sprintf(
1140 '%1$s <a target="_blank" href="https://go.elementor.com/mask-control">%2$s</a>',
1141 esc_html__( 'Explore additional Premium Shape packs and use them in your site.', 'elementor' ),
1142 esc_html__( 'Learn more', 'elementor' ),
1143 ),
1144 'content_classes' => 'elementor-panel-alert elementor-panel-alert-info',
1145 'condition' => [
1146 '_mask_switch!' => '',
1147 ],
1148 ]
1149 );
1150
1151 $this->add_responsive_control(
1152 '_mask_size',
1153 [
1154 'label' => esc_html__( 'Size', 'elementor' ),
1155 'type' => Controls_Manager::SELECT,
1156 'options' => [
1157 'contain' => esc_html__( 'Fit', 'elementor' ),
1158 'cover' => esc_html__( 'Fill', 'elementor' ),
1159 'custom' => esc_html__( 'Custom', 'elementor' ),
1160 ],
1161 'default' => 'contain',
1162 'selectors' => $this->get_mask_selectors( '-webkit-mask-size: {{VALUE}};' ),
1163 'condition' => [
1164 '_mask_switch!' => '',
1165 ],
1166 ]
1167 );
1168
1169 $this->add_responsive_control(
1170 '_mask_size_scale',
1171 [
1172 'label' => esc_html__( 'Scale', 'elementor' ),
1173 'type' => Controls_Manager::SLIDER,
1174 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1175 'range' => [
1176 'px' => [
1177 'min' => 0,
1178 'max' => 500,
1179 ],
1180 'em' => [
1181 'min' => 0,
1182 'max' => 100,
1183 ],
1184 '%' => [
1185 'min' => 0,
1186 'max' => 200,
1187 ],
1188 ],
1189 'default' => [
1190 'unit' => '%',
1191 'size' => 100,
1192 ],
1193 'selectors' => $this->get_mask_selectors( '-webkit-mask-size: {{SIZE}}{{UNIT}};' ),
1194 'condition' => [
1195 '_mask_switch!' => '',
1196 '_mask_size' => 'custom',
1197 ],
1198 ]
1199 );
1200
1201 $this->add_responsive_control(
1202 '_mask_position',
1203 [
1204 'label' => esc_html__( 'Position', 'elementor' ),
1205 'type' => Controls_Manager::SELECT,
1206 'options' => [
1207 'center center' => esc_html__( 'Center Center', 'elementor' ),
1208 'center left' => esc_html__( 'Center Left', 'elementor' ),
1209 'center right' => esc_html__( 'Center Right', 'elementor' ),
1210 'top center' => esc_html__( 'Top Center', 'elementor' ),
1211 'top left' => esc_html__( 'Top Left', 'elementor' ),
1212 'top right' => esc_html__( 'Top Right', 'elementor' ),
1213 'bottom center' => esc_html__( 'Bottom Center', 'elementor' ),
1214 'bottom left' => esc_html__( 'Bottom Left', 'elementor' ),
1215 'bottom right' => esc_html__( 'Bottom Right', 'elementor' ),
1216 'custom' => esc_html__( 'Custom', 'elementor' ),
1217 ],
1218 'default' => 'center center',
1219 'selectors' => $this->get_mask_selectors( '-webkit-mask-position: {{VALUE}};' ),
1220 'condition' => [
1221 '_mask_switch!' => '',
1222 ],
1223 ]
1224 );
1225
1226 $this->add_responsive_control(
1227 '_mask_position_x',
1228 [
1229 'label' => esc_html__( 'X Position', 'elementor' ),
1230 'type' => Controls_Manager::SLIDER,
1231 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1232 'range' => [
1233 'px' => [
1234 'min' => -500,
1235 'max' => 500,
1236 ],
1237 'em' => [
1238 'min' => -100,
1239 'max' => 100,
1240 ],
1241 '%' => [
1242 'min' => -100,
1243 'max' => 100,
1244 ],
1245 'vw' => [
1246 'min' => -100,
1247 'max' => 100,
1248 ],
1249 ],
1250 'default' => [
1251 'unit' => '%',
1252 'size' => 0,
1253 ],
1254 'selectors' => $this->get_mask_selectors( '-webkit-mask-position-x: {{SIZE}}{{UNIT}};' ),
1255 'condition' => [
1256 '_mask_switch!' => '',
1257 '_mask_position' => 'custom',
1258 ],
1259 ]
1260 );
1261
1262 $this->add_responsive_control(
1263 '_mask_position_y',
1264 [
1265 'label' => esc_html__( 'Y Position', 'elementor' ),
1266 'type' => Controls_Manager::SLIDER,
1267 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
1268 'range' => [
1269 'px' => [
1270 'min' => -500,
1271 'max' => 500,
1272 ],
1273 'em' => [
1274 'min' => -100,
1275 'max' => 100,
1276 ],
1277 '%' => [
1278 'min' => -100,
1279 'max' => 100,
1280 ],
1281 'vw' => [
1282 'min' => -100,
1283 'max' => 100,
1284 ],
1285 ],
1286 'default' => [
1287 'unit' => '%',
1288 'size' => 0,
1289 ],
1290 'selectors' => $this->get_mask_selectors( '-webkit-mask-position-y: {{SIZE}}{{UNIT}};' ),
1291 'condition' => [
1292 '_mask_switch!' => '',
1293 '_mask_position' => 'custom',
1294 ],
1295 ]
1296 );
1297
1298 $this->add_responsive_control(
1299 '_mask_repeat',
1300 [
1301 'label' => esc_html__( 'Repeat', 'elementor' ),
1302 'type' => Controls_Manager::SELECT,
1303 'options' => [
1304 'no-repeat' => esc_html__( 'No-repeat', 'elementor' ),
1305 'repeat' => esc_html__( 'Repeat', 'elementor' ),
1306 'repeat-x' => esc_html__( 'Repeat-x', 'elementor' ),
1307 'repeat-Y' => esc_html__( 'Repeat-y', 'elementor' ),
1308 'round' => esc_html__( 'Round', 'elementor' ),
1309 'space' => esc_html__( 'Space', 'elementor' ),
1310 ],
1311 'default' => 'no-repeat',
1312 'selectors' => $this->get_mask_selectors( '-webkit-mask-repeat: {{VALUE}};' ),
1313 'condition' => [
1314 '_mask_switch!' => '',
1315 '_mask_size!' => 'cover',
1316 ],
1317 ]
1318 );
1319
1320 $this->end_controls_section();
1321 }
1322
1323
1324 /**
1325 * Register the Responsive section.
1326 *
1327 * @return void
1328 */
1329 private function register_responsive_section() {
1330 $this->start_controls_section(
1331 '_section_responsive',
1332 [
1333 'label' => esc_html__( 'Responsive', 'elementor' ),
1334 'tab' => Controls_Manager::TAB_ADVANCED,
1335 ]
1336 );
1337
1338 $this->add_control(
1339 'responsive_description',
1340 [
1341 'raw' => sprintf(
1342 /* translators: 1: Link open tag, 2: Link close tag. */
1343 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' ),
1344 '<a href="javascript: $e.run( \'panel/close\' )">',
1345 '</a>'
1346 ),
1347 'type' => Controls_Manager::RAW_HTML,
1348 'content_classes' => 'elementor-descriptor',
1349 ]
1350 );
1351
1352 $this->add_hidden_device_controls();
1353
1354 $this->end_controls_section();
1355 }
1356
1357 /**
1358 * Register common widget controls.
1359 *
1360 * Adds different input fields to allow the user to change and customize the widget settings.
1361 *
1362 * @since 3.1.0
1363 * @access protected
1364 */
1365 protected function register_controls() {
1366 $this->register_layout_section();
1367
1368 $this->register_effects_section();
1369
1370 $this->register_transform_section( '', static::TRANSFORM_SELECTOR_CLASS );
1371
1372 $this->register_background_section();
1373
1374 $this->register_border_section();
1375
1376 $this->register_masking_section();
1377
1378 $this->register_responsive_section();
1379
1380 $register_common_controls = apply_filters(
1381 'elementor/widget/common/register_css_attributes_control',
1382 true,
1383 $this
1384 );
1385
1386 if ( $register_common_controls ) {
1387 Plugin::$instance->controls_manager->add_custom_attributes_controls( $this );
1388
1389 Plugin::$instance->controls_manager->add_custom_css_controls( $this );
1390 }
1391 }
1392 }
1393