PluginProbe
Elementor Website Builder – more than just a page builder / 4.2.0-dev2
Elementor Website Builder – more than just a page builder v4.2.0-dev2
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 4.2.0-dev2, at includes/widgets/common-base.php

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