PluginProbe
Elementor Website Builder – more than just a page builder / 3.0.7
Elementor Website Builder – more than just a page builder v3.0.7
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 / managers / controls.php

controls.php in Elementor Website Builder – more than just a page builder 3.0.7, at includes/managers/controls.php

977 lines 21.0 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 controls manager.
10 *
11 * Elementor controls manager handler class is responsible for registering and
12 * initializing all the supported controls, both regular controls and the group
13 * controls.
14 *
15 * @since 1.0.0
16 */
17 class Controls_Manager {
18
19 /**
20 * Content tab.
21 */
22 const TAB_CONTENT = 'content';
23
24 /**
25 * Style tab.
26 */
27 const TAB_STYLE = 'style';
28
29 /**
30 * Advanced tab.
31 */
32 const TAB_ADVANCED = 'advanced';
33
34 /**
35 * Responsive tab.
36 */
37 const TAB_RESPONSIVE = 'responsive';
38
39 /**
40 * Layout tab.
41 */
42 const TAB_LAYOUT = 'layout';
43
44 /**
45 * Settings tab.
46 */
47 const TAB_SETTINGS = 'settings';
48
49 /**
50 * Text control.
51 */
52 const TEXT = 'text';
53
54 /**
55 * Number control.
56 */
57 const NUMBER = 'number';
58
59 /**
60 * Textarea control.
61 */
62 const TEXTAREA = 'textarea';
63
64 /**
65 * Select control.
66 */
67 const SELECT = 'select';
68
69 /**
70 * Switcher control.
71 */
72 const SWITCHER = 'switcher';
73
74 /**
75 * Button control.
76 */
77 const BUTTON = 'button';
78
79 /**
80 * Hidden control.
81 */
82 const HIDDEN = 'hidden';
83
84 /**
85 * Heading control.
86 */
87 const HEADING = 'heading';
88
89 /**
90 * Raw HTML control.
91 */
92 const RAW_HTML = 'raw_html';
93
94 /**
95 * Deprecated Notice control.
96 */
97 const DEPRECATED_NOTICE = 'deprecated_notice';
98
99 /**
100 * Popover Toggle control.
101 */
102 const POPOVER_TOGGLE = 'popover_toggle';
103
104 /**
105 * Section control.
106 */
107 const SECTION = 'section';
108
109 /**
110 * Tab control.
111 */
112 const TAB = 'tab';
113
114 /**
115 * Tabs control.
116 */
117 const TABS = 'tabs';
118
119 /**
120 * Divider control.
121 */
122 const DIVIDER = 'divider';
123
124 /**
125 * Color control.
126 */
127 const COLOR = 'color';
128
129 /**
130 * Media control.
131 */
132 const MEDIA = 'media';
133
134 /**
135 * Slider control.
136 */
137 const SLIDER = 'slider';
138
139 /**
140 * Dimensions control.
141 */
142 const DIMENSIONS = 'dimensions';
143
144 /**
145 * Choose control.
146 */
147 const CHOOSE = 'choose';
148
149 /**
150 * WYSIWYG control.
151 */
152 const WYSIWYG = 'wysiwyg';
153
154 /**
155 * Code control.
156 */
157 const CODE = 'code';
158
159 /**
160 * Font control.
161 */
162 const FONT = 'font';
163
164 /**
165 * Image dimensions control.
166 */
167 const IMAGE_DIMENSIONS = 'image_dimensions';
168
169 /**
170 * WordPress widget control.
171 */
172 const WP_WIDGET = 'wp_widget';
173
174 /**
175 * URL control.
176 */
177 const URL = 'url';
178
179 /**
180 * Repeater control.
181 */
182 const REPEATER = 'repeater';
183
184 /**
185 * Icon control.
186 */
187 const ICON = 'icon';
188
189 /**
190 * Icons control.
191 */
192 const ICONS = 'icons';
193
194 /**
195 * Gallery control.
196 */
197 const GALLERY = 'gallery';
198
199 /**
200 * Structure control.
201 */
202 const STRUCTURE = 'structure';
203
204 /**
205 * Select2 control.
206 */
207 const SELECT2 = 'select2';
208
209 /**
210 * Date/Time control.
211 */
212 const DATE_TIME = 'date_time';
213
214 /**
215 * Box shadow control.
216 */
217 const BOX_SHADOW = 'box_shadow';
218
219 /**
220 * Text shadow control.
221 */
222 const TEXT_SHADOW = 'text_shadow';
223
224 /**
225 * Entrance animation control.
226 */
227 const ANIMATION = 'animation';
228
229 /**
230 * Hover animation control.
231 */
232 const HOVER_ANIMATION = 'hover_animation';
233
234 /**
235 * Exit animation control.
236 */
237 const EXIT_ANIMATION = 'exit_animation';
238
239 /**
240 * Controls.
241 *
242 * Holds the list of all the controls. Default is `null`.
243 *
244 * @since 1.0.0
245 * @access private
246 *
247 * @var Base_Control[]
248 */
249 private $controls = null;
250
251 /**
252 * Control groups.
253 *
254 * Holds the list of all the control groups. Default is an empty array.
255 *
256 * @since 1.0.0
257 * @access private
258 *
259 * @var Group_Control_Base[]
260 */
261 private $control_groups = [];
262
263 /**
264 * Control stacks.
265 *
266 * Holds the list of all the control stacks. Default is an empty array.
267 *
268 * @since 1.0.0
269 * @access private
270 *
271 * @var array
272 */
273 private $stacks = [];
274
275 /**
276 * Tabs.
277 *
278 * Holds the list of all the tabs.
279 *
280 * @since 1.0.0
281 * @access private
282 * @static
283 *
284 * @var array
285 */
286 private static $tabs;
287
288 /**
289 * Init tabs.
290 *
291 * Initialize control tabs.
292 *
293 * @since 1.6.0
294 * @access private
295 * @static
296 */
297 private static function init_tabs() {
298 self::$tabs = [
299 self::TAB_CONTENT => __( 'Content', 'elementor' ),
300 self::TAB_STYLE => __( 'Style', 'elementor' ),
301 self::TAB_ADVANCED => __( 'Advanced', 'elementor' ),
302 self::TAB_RESPONSIVE => __( 'Responsive', 'elementor' ),
303 self::TAB_LAYOUT => __( 'Layout', 'elementor' ),
304 self::TAB_SETTINGS => __( 'Settings', 'elementor' ),
305 ];
306 }
307
308 /**
309 * Get tabs.
310 *
311 * Retrieve the tabs of the current control.
312 *
313 * @since 1.6.0
314 * @access public
315 * @static
316 *
317 * @return array Control tabs.
318 */
319 public static function get_tabs() {
320 if ( ! self::$tabs ) {
321 self::init_tabs();
322 }
323
324 return self::$tabs;
325 }
326
327 /**
328 * Add tab.
329 *
330 * This method adds a new tab to the current control.
331 *
332 * @since 1.6.0
333 * @access public
334 * @static
335 *
336 * @param string $tab_name Tab name.
337 * @param string $tab_label Tab label.
338 */
339 public static function add_tab( $tab_name, $tab_label = '' ) {
340 if ( ! self::$tabs ) {
341 self::init_tabs();
342 }
343
344 if ( isset( self::$tabs[ $tab_name ] ) ) {
345 return;
346 }
347
348 self::$tabs[ $tab_name ] = $tab_label;
349 }
350
351 public static function get_groups_names() {
352 // Group name must use "-" instead of "_"
353 return [
354 'background',
355 'border',
356 'typography',
357 'image-size',
358 'box-shadow',
359 'css-filter',
360 'text-shadow',
361 ];
362 }
363
364 public static function get_controls_names() {
365 return [
366 self::TEXT,
367 self::NUMBER,
368 self::TEXTAREA,
369 self::SELECT,
370 self::SWITCHER,
371
372 self::BUTTON,
373 self::HIDDEN,
374 self::HEADING,
375 self::RAW_HTML,
376 self::POPOVER_TOGGLE,
377 self::SECTION,
378 self::TAB,
379 self::TABS,
380 self::DIVIDER,
381 self::DEPRECATED_NOTICE,
382
383 self::COLOR,
384 self::MEDIA,
385 self::SLIDER,
386 self::DIMENSIONS,
387 self::CHOOSE,
388 self::WYSIWYG,
389 self::CODE,
390 self::FONT,
391 self::IMAGE_DIMENSIONS,
392
393 self::WP_WIDGET,
394
395 self::URL,
396 self::REPEATER,
397 self::ICON,
398 self::ICONS,
399 self::GALLERY,
400 self::STRUCTURE,
401 self::SELECT2,
402 self::DATE_TIME,
403 self::BOX_SHADOW,
404 self::TEXT_SHADOW,
405 self::ANIMATION,
406 self::HOVER_ANIMATION,
407 self::EXIT_ANIMATION,
408 ];
409 }
410
411 /**
412 * Register controls.
413 *
414 * This method creates a list of all the supported controls by requiring the
415 * control files and initializing each one of them.
416 *
417 * The list of supported controls includes the regular controls and the group
418 * controls.
419 *
420 * External developers can register new controls by hooking to the
421 * `elementor/controls/controls_registered` action.
422 *
423 * @since 1.0.0
424 * @access private
425 */
426 private function register_controls() {
427 $this->controls = [];
428
429 foreach ( self::get_controls_names() as $control_id ) {
430 $control_class_id = str_replace( ' ', '_', ucwords( str_replace( '_', ' ', $control_id ) ) );
431 $class_name = __NAMESPACE__ . '\Control_' . $control_class_id;
432
433 $this->register_control( $control_id, new $class_name() );
434 }
435
436 // Group Controls
437 foreach ( self::get_groups_names() as $group_name ) {
438 $group_class_id = str_replace( ' ', '_', ucwords( str_replace( '-', ' ', $group_name ) ) );
439 $class_name = __NAMESPACE__ . '\Group_Control_' . $group_class_id;
440
441 $this->control_groups[ $group_name ] = new $class_name();
442 }
443
444 /**
445 * After controls registered.
446 *
447 * Fires after Elementor controls are registered.
448 *
449 * @since 1.0.0
450 *
451 * @param Controls_Manager $this The controls manager.
452 */
453 do_action( 'elementor/controls/controls_registered', $this );
454 }
455
456 /**
457 * Register control.
458 *
459 * This method adds a new control to the controls list. It adds any given
460 * control to any given control instance.
461 *
462 * @since 1.0.0
463 * @access public
464 *
465 * @param string $control_id Control ID.
466 * @param Base_Control $control_instance Control instance, usually the
467 * current instance.
468 */
469 public function register_control( $control_id, Base_Control $control_instance ) {
470 $this->controls[ $control_id ] = $control_instance;
471 }
472
473 /**
474 * Unregister control.
475 *
476 * This method removes control from the controls list.
477 *
478 * @since 1.0.0
479 * @access public
480 *
481 * @param string $control_id Control ID.
482 *
483 * @return bool True if the control was removed, False otherwise.
484 */
485 public function unregister_control( $control_id ) {
486 if ( ! isset( $this->controls[ $control_id ] ) ) {
487 return false;
488 }
489
490 unset( $this->controls[ $control_id ] );
491
492 return true;
493 }
494
495 /**
496 * Get controls.
497 *
498 * Retrieve the controls list from the current instance.
499 *
500 * @since 1.0.0
501 * @access public
502 *
503 * @return Base_Control[] Controls list.
504 */
505 public function get_controls() {
506 if ( null === $this->controls ) {
507 $this->register_controls();
508 }
509
510 return $this->controls;
511 }
512
513 /**
514 * Get control.
515 *
516 * Retrieve a specific control from the current controls instance.
517 *
518 * @since 1.0.0
519 * @access public
520 *
521 * @param string $control_id Control ID.
522 *
523 * @return bool|Base_Control Control instance, or False otherwise.
524 */
525 public function get_control( $control_id ) {
526 $controls = $this->get_controls();
527
528 return isset( $controls[ $control_id ] ) ? $controls[ $control_id ] : false;
529 }
530
531 /**
532 * Get controls data.
533 *
534 * Retrieve all the registered controls and all the data for each control.
535 *
536 * @since 1.0.0
537 * @access public
538 *
539 * @return array {
540 * Control data.
541 *
542 * @type array $name Control data.
543 * }
544 */
545 public function get_controls_data() {
546 $controls_data = [];
547
548 foreach ( $this->get_controls() as $name => $control ) {
549 $controls_data[ $name ] = $control->get_settings();
550 }
551
552 return $controls_data;
553 }
554
555 /**
556 * Render controls.
557 *
558 * Generate the final HTML for all the registered controls using the element
559 * template.
560 *
561 * @since 1.0.0
562 * @access public
563 */
564 public function render_controls() {
565 foreach ( $this->get_controls() as $control ) {
566 $control->print_template();
567 }
568 }
569
570 /**
571 * Get control groups.
572 *
573 * Retrieve a specific group for a given ID, or a list of all the control
574 * groups.
575 *
576 * If the given group ID is wrong, it will return `null`. When the ID valid,
577 * it will return the group control instance. When no ID was given, it will
578 * return all the control groups.
579 *
580 * @since 1.0.10
581 * @access public
582 *
583 * @param string $id Optional. Group ID. Default is null.
584 *
585 * @return null|Group_Control_Base|Group_Control_Base[]
586 */
587 public function get_control_groups( $id = null ) {
588 if ( $id ) {
589 return isset( $this->control_groups[ $id ] ) ? $this->control_groups[ $id ] : null;
590 }
591
592 return $this->control_groups;
593 }
594
595 /**
596 * Add group control.
597 *
598 * This method adds a new group control to the control groups list. It adds
599 * any given group control to any given group control instance.
600 *
601 * @since 1.0.0
602 * @access public
603 *
604 * @param string $id Group control ID.
605 * @param Group_Control_Base $instance Group control instance, usually the
606 * current instance.
607 *
608 * @return Group_Control_Base Group control instance.
609 */
610 public function add_group_control( $id, $instance ) {
611 $this->control_groups[ $id ] = $instance;
612
613 return $instance;
614 }
615
616 /**
617 * Enqueue control scripts and styles.
618 *
619 * Used to register and enqueue custom scripts and styles used by the control.
620 *
621 * @since 1.0.0
622 * @access public
623 */
624 public function enqueue_control_scripts() {
625 foreach ( $this->get_controls() as $control ) {
626 $control->enqueue();
627 }
628 }
629
630 /**
631 * Open new stack.
632 *
633 * This method adds a new stack to the control stacks list. It adds any
634 * given stack to the current control instance.
635 *
636 * @since 1.0.0
637 * @access public
638 *
639 * @param Controls_Stack $controls_stack Controls stack.
640 */
641 public function open_stack( Controls_Stack $controls_stack ) {
642 $stack_id = $controls_stack->get_unique_name();
643
644 $this->stacks[ $stack_id ] = [
645 'tabs' => [],
646 'controls' => [],
647 ];
648 }
649
650 /**
651 * Add control to stack.
652 *
653 * This method adds a new control to the stack.
654 *
655 * @since 1.0.0
656 * @access public
657 *
658 * @param Controls_Stack $element Element stack.
659 * @param string $control_id Control ID.
660 * @param array $control_data Control data.
661 * @param array $options Optional. Control additional options.
662 * Default is an empty array.
663 *
664 * @return bool True if control added, False otherwise.
665 */
666 public function add_control_to_stack( Controls_Stack $element, $control_id, $control_data, $options = [] ) {
667 $default_options = [
668 'overwrite' => false,
669 'index' => null,
670 ];
671
672 $options = array_merge( $default_options, $options );
673
674 $default_args = [
675 'type' => self::TEXT,
676 'tab' => self::TAB_CONTENT,
677 ];
678
679 $control_data['name'] = $control_id;
680
681 $control_data = array_merge( $default_args, $control_data );
682
683 $control_type_instance = $this->get_control( $control_data['type'] );
684
685 if ( ! $control_type_instance ) {
686 _doing_it_wrong( sprintf( '%1$s::%2$s', __CLASS__, __FUNCTION__ ), sprintf( 'Control type "%s" not found.', $control_data['type'] ), '1.0.0' );
687 return false;
688 }
689
690 if ( $control_type_instance instanceof Base_Data_Control ) {
691 $control_default_value = $control_type_instance->get_default_value();
692
693 if ( is_array( $control_default_value ) ) {
694 $control_data['default'] = isset( $control_data['default'] ) ? array_merge( $control_default_value, $control_data['default'] ) : $control_default_value;
695 } else {
696 $control_data['default'] = isset( $control_data['default'] ) ? $control_data['default'] : $control_default_value;
697 }
698 }
699
700 $stack_id = $element->get_unique_name();
701
702 if ( ! $options['overwrite'] && isset( $this->stacks[ $stack_id ]['controls'][ $control_id ] ) ) {
703 _doing_it_wrong( sprintf( '%1$s::%2$s', __CLASS__, __FUNCTION__ ), sprintf( 'Cannot redeclare control with same name "%s".', $control_id ), '1.0.0' );
704
705 return false;
706 }
707
708 $tabs = self::get_tabs();
709
710 if ( ! isset( $tabs[ $control_data['tab'] ] ) ) {
711 $control_data['tab'] = $default_args['tab'];
712 }
713
714 $this->stacks[ $stack_id ]['tabs'][ $control_data['tab'] ] = $tabs[ $control_data['tab'] ];
715
716 $this->stacks[ $stack_id ]['controls'][ $control_id ] = $control_data;
717
718 if ( null !== $options['index'] ) {
719 $controls = $this->stacks[ $stack_id ]['controls'];
720
721 $controls_keys = array_keys( $controls );
722
723 array_splice( $controls_keys, $options['index'], 0, $control_id );
724
725 $this->stacks[ $stack_id ]['controls'] = array_merge( array_flip( $controls_keys ), $controls );
726 }
727
728 return true;
729 }
730
731 /**
732 * Remove control from stack.
733 *
734 * This method removes a control a the stack.
735 *
736 * @since 1.0.0
737 * @access public
738 *
739 * @param string $stack_id Stack ID.
740 * @param array|string $control_id The ID of the control to remove.
741 *
742 * @return bool|\WP_Error True if the stack was removed, False otherwise.
743 */
744 public function remove_control_from_stack( $stack_id, $control_id ) {
745 if ( is_array( $control_id ) ) {
746 foreach ( $control_id as $id ) {
747 $this->remove_control_from_stack( $stack_id, $id );
748 }
749
750 return true;
751 }
752
753 if ( empty( $this->stacks[ $stack_id ]['controls'][ $control_id ] ) ) {
754 return new \WP_Error( 'Cannot remove not-exists control.' );
755 }
756
757 unset( $this->stacks[ $stack_id ]['controls'][ $control_id ] );
758
759 return true;
760 }
761
762 /**
763 * Get control from stack.
764 *
765 * Retrieve a specific control for a given a specific stack.
766 *
767 * If the given control does not exist in the stack, or the stack does not
768 * exist, it will return `WP_Error`. Otherwise, it will retrieve the control
769 * from the stack.
770 *
771 * @since 1.1.0
772 * @access public
773 *
774 * @param string $stack_id Stack ID.
775 * @param string $control_id Control ID.
776 *
777 * @return array|\WP_Error The control, or an error.
778 */
779 public function get_control_from_stack( $stack_id, $control_id ) {
780 if ( empty( $this->stacks[ $stack_id ]['controls'][ $control_id ] ) ) {
781 return new \WP_Error( 'Cannot get a not-exists control.' );
782 }
783
784 return $this->stacks[ $stack_id ]['controls'][ $control_id ];
785 }
786
787 /**
788 * Update control in stack.
789 *
790 * This method updates the control data for a given stack.
791 *
792 * @since 1.1.0
793 * @access public
794 *
795 * @param Controls_Stack $element Element stack.
796 * @param string $control_id Control ID.
797 * @param array $control_data Control data.
798 * @param array $options Optional. Control additional options.
799 * Default is an empty array.
800 *
801 * @return bool True if control updated, False otherwise.
802 */
803 public function update_control_in_stack( Controls_Stack $element, $control_id, $control_data, array $options = [] ) {
804 $old_control_data = $this->get_control_from_stack( $element->get_unique_name(), $control_id );
805
806 if ( is_wp_error( $old_control_data ) ) {
807 return false;
808 }
809
810 if ( ! empty( $options['recursive'] ) ) {
811 $control_data = array_replace_recursive( $old_control_data, $control_data );
812 } else {
813 $control_data = array_merge( $old_control_data, $control_data );
814 }
815
816 return $this->add_control_to_stack( $element, $control_id, $control_data, [
817 'overwrite' => true,
818 ] );
819 }
820
821 /**
822 * Get stacks.
823 *
824 * Retrieve a specific stack for the list of stacks.
825 *
826 * If the given stack is wrong, it will return `null`. When the stack valid,
827 * it will return the the specific stack. When no stack was given, it will
828 * return all the stacks.
829 *
830 * @since 1.7.1
831 * @access public
832 *
833 * @param string $stack_id Optional. stack ID. Default is null.
834 *
835 * @return null|array A list of stacks.
836 */
837 public function get_stacks( $stack_id = null ) {
838 if ( $stack_id ) {
839 if ( isset( $this->stacks[ $stack_id ] ) ) {
840 return $this->stacks[ $stack_id ];
841 }
842
843 return null;
844 }
845
846 return $this->stacks;
847 }
848
849 /**
850 * Get element stack.
851 *
852 * Retrieve a specific stack for the list of stacks from the current instance.
853 *
854 * @since 1.0.0
855 * @access public
856 *
857 * @param Controls_Stack $controls_stack Controls stack.
858 *
859 * @return null|array Stack data if it exist, `null` otherwise.
860 */
861 public function get_element_stack( Controls_Stack $controls_stack ) {
862 $stack_id = $controls_stack->get_unique_name();
863
864 if ( ! isset( $this->stacks[ $stack_id ] ) ) {
865 return null;
866 }
867
868 return $this->stacks[ $stack_id ];
869 }
870
871 /**
872 * Add custom CSS controls.
873 *
874 * This method adds a new control for the "Custom CSS" feature. The free
875 * version of elementor uses this method to display an upgrade message to
876 * Elementor Pro.
877 *
878 * @since 1.0.0
879 * @access public
880 *
881 * @param Controls_Stack $controls_stack .
882 * @param string $tab
883 * @param array $additional_messages
884 *
885 */
886 public function add_custom_css_controls( Controls_Stack $controls_stack, $tab = self::TAB_ADVANCED, $additional_messages = [] ) {
887 $controls_stack->start_controls_section(
888 'section_custom_css_pro',
889 [
890 'label' => __( 'Custom CSS', 'elementor' ),
891 'tab' => $tab,
892 ]
893 );
894
895 $messages = [
896 __( 'Custom CSS lets you add CSS code to any widget, and see it render live right in the editor.', 'elementor' ),
897 ];
898
899 if ( $additional_messages ) {
900 $messages = array_merge( $messages, $additional_messages );
901 }
902
903 $controls_stack->add_control(
904 'custom_css_pro',
905 [
906 'type' => self::RAW_HTML,
907 'raw' => $this->get_teaser_template( [
908 'title' => __( 'Meet Our Custom CSS', 'elementor' ),
909 'messages' => $messages,
910 'link' => 'https://elementor.com/pro/?utm_source=panel-custom-css&utm_campaign=gopro&utm_medium=wp-dash',
911 ] ),
912 ]
913 );
914
915 $controls_stack->end_controls_section();
916 }
917
918 public function get_teaser_template( $texts ) {
919 ob_start();
920 ?>
921 <div class="elementor-nerd-box">
922 <img class="elementor-nerd-box-icon" src="<?php echo ELEMENTOR_ASSETS_URL . 'images/go-pro.svg'; ?>" />
923 <div class="elementor-nerd-box-title"><?php echo $texts['title']; ?></div>
924 <?php foreach ( $texts['messages'] as $message ) { ?>
925 <div class="elementor-nerd-box-message"><?php echo $message; ?></div>
926 <?php }
927
928 if ( $texts['link'] ) { ?>
929 <a class="elementor-nerd-box-link elementor-button elementor-button-default elementor-button-go-pro" href="<?php echo Utils::get_pro_link( $texts['link'] ); ?>" target="_blank">
930 <?php echo __( 'Go Pro', 'elementor' ); ?>
931 </a>
932 <?php } ?>
933 </div>
934 <?php
935
936 return ob_get_clean();
937 }
938
939 /**
940 * Add custom attributes controls.
941 *
942 * This method adds a new control for the "Custom Attributes" feature. The free
943 * version of elementor uses this method to display an upgrade message to
944 * Elementor Pro.
945 *
946 * @since 2.8.3
947 * @access public
948 *
949 * @param Controls_Stack $controls_stack.
950 */
951 public function add_custom_attributes_controls( Controls_Stack $controls_stack ) {
952 $controls_stack->start_controls_section(
953 'section_custom_attributes_pro',
954 [
955 'label' => __( 'Attributes', 'elementor' ),
956 'tab' => self::TAB_ADVANCED,
957 ]
958 );
959
960 $controls_stack->add_control(
961 'custom_attributes_pro',
962 [
963 'type' => self::RAW_HTML,
964 'raw' => $this->get_teaser_template( [
965 'title' => __( 'Meet Our Attributes', 'elementor' ),
966 'messages' => [
967 __( 'Attributes lets you add custom HTML attributes to any element.', 'elementor' ),
968 ],
969 'link' => 'https://elementor.com/pro/?utm_source=panel-custom-attributes&utm_campaign=gopro&utm_medium=wp-dash',
970 ] ),
971 ]
972 );
973
974 $controls_stack->end_controls_section();
975 }
976 }
977