PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / trunk
ShopBuilder – WooCommerce Builder For Elementor vtrunk
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
shopbuilder / app / Abstracts / ElementorWidgetBase.php

ElementorWidgetBase.php in ShopBuilder – WooCommerce Builder For Elementor trunk, at app/Abstracts/ElementorWidgetBase.php

924 lines 23.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Main ElementorWidgetBase class.
4 *
5 * @package RadiusTheme\SB
6 */
7
8 namespace RadiusTheme\SB\Abstracts;
9
10 use Elementor\Group_Control_Css_Filter;
11 use Elementor\Plugin;
12 use Elementor\Repeater;
13 use Elementor\Widget_Base;
14 use Elementor\Controls_Manager;
15 use Elementor\Group_Control_Border;
16 use RadiusTheme\SB\Controllers\Hooks\FilterHooks;
17 use RadiusTheme\SB\Helpers\BuilderFns;
18 use Elementor\Group_Control_Typography;
19 use Elementor\Group_Control_Background;
20 use Elementor\Group_Control_Box_Shadow;
21 use Elementor\Group_Control_Text_Shadow;
22 use Elementor\Group_Control_Text_Stroke;
23 use RadiusTheme\SB\Elementor\Helper\ControlSelectors;
24 use RadiusTheme\SB\Helpers\Fns;
25
26
27 // Do not allow directly accessing this file.
28 if ( ! defined( 'ABSPATH' ) ) {
29 exit( 'This script cannot be accessed directly.' );
30 }
31
32 /**
33 * Abstract ElementorWidgetBase Class
34 *
35 * Implemented by classes for elementor addons development.
36 *
37 * @version 1.0.0
38 * @package RadiusTheme\SB
39 */
40 abstract class ElementorWidgetBase extends Widget_Base {
41
42 /**
43 * Widget Title.
44 *
45 * @var String
46 */
47 public $rtsb_name;
48
49 /**
50 * Widget name.
51 *
52 * @var String
53 */
54 public $rtsb_base;
55
56 /**
57 * Widget categories.
58 *
59 * @var String
60 */
61 public $rtsb_category;
62
63 /**
64 * Widget icon class
65 *
66 * @var String
67 */
68 public $rtsb_icon;
69
70 /**
71 * PRO Label HTML.
72 *
73 * @var String
74 */
75 public $pro_label = '';
76
77 /**
78 * PRO content tab.
79 *
80 * @var String
81 */
82 public $pro_tab;
83
84 /**
85 * Widget prefix.
86 *
87 * @var String
88 */
89 public $el_prefix;
90
91 /**
92 * Widget controls.
93 *
94 * @var array
95 */
96 public $selectors = [];
97
98 /**
99 * Class Constructor
100 *
101 * @param array $data default data.
102 * @param array $args default arg.
103 */
104 public function __construct( $data = [], $args = null ) {
105 $this->apply_hooks_before_render();
106 parent::__construct( $data, $args );
107 $this->rtsb_category = 'rtsb-shopbuilder';
108 $this->rtsb_icon = 'rtsb-el-custom rtsb-element icon-' . $this->rtsb_base;
109 $this->el_prefix = 'rtsb_el_';
110 $this->pro_label = sprintf(
111 '<span class="rtsb-pro-label">%s</span>',
112 esc_html__( 'Pro', 'shopbuilder' )
113 );
114 $this->selectors = ControlSelectors::get_widget_selectors( $this );
115 }
116
117
118 /**
119 * Elementor controls marge all settings
120 *
121 * @return array
122 */
123 abstract public function widget_fields();
124
125 /**
126 * Get widget name.
127 *
128 * Retrieve widget name.
129 *
130 * @access public
131 *
132 * @return string Widget name.
133 */
134 public function get_name() {
135 return $this->rtsb_base;
136 }
137
138 /**
139 * Set Widget Keyword.
140 *
141 * @return array
142 */
143 public function get_keywords() {
144 return [ 'woocommerce', 'shopbuilder' ];
145 }
146
147 /**
148 * Get widget title.
149 *
150 * Retrieve widget title.
151 *
152 * @access public
153 *
154 * @return string Widget title.
155 */
156 public function get_title() {
157 return $this->rtsb_name;
158 }
159
160 /**
161 * Get widget icon.
162 *
163 * Retrieve widget icon.
164 *
165 * @return string Widget icon.
166 * @since 1.0.0
167 * @access public
168 */
169 public function get_icon() {
170 return $this->rtsb_icon;
171 }
172
173 /**
174 * Get widget categories.
175 *
176 * Retrieve the list of categories widget belongs to.
177 *
178 * @return array Widget categories.
179 * @since 1.0.0
180 * @access public
181 */
182 public function get_categories() {
183 return [ $this->rtsb_category ];
184 }
185
186 /**
187 * Elementor Promotional section controls.
188 *
189 * @return array
190 */
191 public function promo_content() {
192 if ( rtsb()->has_pro() || $this->widget_exceptions() ) {
193 return [];
194 }
195
196 $promo_fields = [];
197
198 $promo_fields['pro_alert'] = [
199 'mode' => 'section_start',
200 'label' => sprintf(
201 '<span style="color: #f54">%s</span>',
202 esc_html__( 'Go Premium for More Features', 'shopbuilder' )
203 ),
204 ];
205
206 if ( $this->pro_tab ) {
207 $promo_fields['pro_alert']['tab'] = $this->pro_tab;
208 }
209
210 $promo_fields['get_pro'] = [
211 'type' => 'html',
212 'raw' => '<div class="elementor-nerd-box rtsb-promo"><div class="elementor-nerd-box-title" style="margin-top: 0; margin-bottom: 20px;">Unlock more possibilities</div><div class="elementor-nerd-box-message"><span class="pro-feature" style="font-size: 13px;"> Get the <a href="' . esc_url( rtsb()->pro_version_link() ) . '" target="_blank" style="color: #f54">Pro version</a> for more stunning layouts and customization options.</span></div><a class="elementor-nerd-box-link elementor-button elementor-button-default elementor-button-go-pro" href="' . esc_url( rtsb()->pro_version_link() ) . '" target="_blank">Get Pro</a></div>',
213 'separator' => 'default',
214 ];
215
216 $promo_fields['pro_alert_end'] = [
217 'mode' => 'section_end',
218 ];
219
220 return $promo_fields;
221 }
222
223 /**
224 * Register widget controls.
225 *
226 * Adds different input fields to allow the user to change and customize the widget settings.
227 *
228 * @since 1.0.0
229 * @access protected
230 */
231 protected function register_controls() {
232 $this->theme_support( 'widget_controls' );
233 $the_widget = $this->widget_fields();
234 if ( ! is_array( $the_widget ) ) {
235 return;
236 }
237 $fields = array_merge( $the_widget, $this->promo_content() );
238
239 $fields = apply_filters( 'rtsb/elements/elementor/widgets/controls/' . $this->rtsb_base, $fields, $this );
240
241 foreach ( $fields as $id => $field ) {
242 $field['classes'] = ! empty( $field['classes'] ) ? $field['classes'] . ' elementor-control-rtsb_el' : ' elementor-control-rtsb_el';
243
244 if ( ! empty( $field['type'] ) ) {
245 $field['type'] = self::el_fields( $field['type'] );
246 }
247
248 if ( ! empty( $field['tab'] ) ) {
249 $field['tab'] = self::el_tabs( $field['tab'] );
250 }
251
252 if ( isset( $field['mode'] ) && 'section_start' === $field['mode'] ) {
253 unset( $field['mode'] );
254 unset( $field['separator'] );
255
256 $this->start_controls_section( $id, $field );
257 } elseif ( isset( $field['mode'] ) && 'section_end' === $field['mode'] ) {
258 $this->end_controls_section();
259 } elseif ( isset( $field['mode'] ) && 'tabs_start' === $field['mode'] ) {
260 unset( $field['mode'] );
261 unset( $field['separator'] );
262
263 $this->start_controls_tabs( $id );
264 } elseif ( isset( $field['mode'] ) && 'tabs_end' === $field['mode'] ) {
265 $this->end_controls_tabs();
266 } elseif ( isset( $field['mode'] ) && 'tab_start' === $field['mode'] ) {
267 unset( $field['mode'] );
268 unset( $field['separator'] );
269
270 $this->start_controls_tab( $id, $field );
271 } elseif ( isset( $field['mode'] ) && 'tab_end' === $field['mode'] ) {
272 $this->end_controls_tab();
273 } elseif ( isset( $field['mode'] ) && 'group' === $field['mode'] ) {
274 $type = $field['type'];
275 $field['name'] = $id;
276 unset( $field['mode'] );
277 unset( $field['type'] );
278 $this->add_group_control( $type, $field );
279 } elseif ( isset( $field['mode'] ) && 'responsive' === $field['mode'] ) {
280 unset( $field['mode'] );
281
282 $this->add_responsive_control( $id, $field );
283 } elseif ( isset( $field['mode'] ) && 'popover_start' === $field['mode'] ) {
284 unset( $field['mode'] );
285 unset( $field['separator'] );
286
287 $this->add_control( $id, $field );
288 $this->start_popover();
289 } elseif ( isset( $field['mode'] ) && 'popover_end' === $field['mode'] ) {
290 $this->end_popover();
291 } elseif ( isset( $field['mode'] ) && 'repeater' === $field['mode'] ) {
292 $repeater = new Repeater();
293 $repeater_fields = $field['fields'];
294
295 foreach ( $repeater_fields as $rf_id => $value ) {
296 if ( ! empty( $value['type'] ) ) {
297 $value['type'] = self::el_fields( $value['type'] );
298 }
299 if ( isset( $value['mode'] ) && 'responsive' === $value['mode'] ) {
300 unset( $value['mode'] );
301 $repeater->add_responsive_control( $rf_id, $value );
302 } elseif ( isset( $value['mode'] ) && 'group' === $value['mode'] ) {
303 $type = $value['type'];
304 $value['name'] = $rf_id;
305 unset( $value['mode'] );
306 unset( $value['type'] );
307 $repeater->add_group_control( $type, $value );
308 } else {
309 $repeater->add_control( $rf_id, $value );
310 }
311 }
312
313 $field['fields'] = $repeater->get_controls();
314
315 $this->add_control( $id, $field );
316 } else {
317 $this->add_control( $id, $field );
318 }
319 }
320
321 do_action( 'rtsb/after/register/controls' );
322 }
323
324 /**
325 * Elementor Edit mode.
326 *
327 * @return mixed
328 */
329 public function is_edit_mode() {
330 return Plugin::$instance->preview->is_preview_mode() || Plugin::$instance->editor->is_edit_mode();
331 }
332
333 /**
334 * Elementor Edit preview.
335 *
336 * @return mixed
337 */
338 public function is_builder_mode() {
339 return BuilderFns::is_builder_preview() || $this->is_edit_mode();
340 }
341
342 /**
343 * Render a shared editor-only notice.
344 *
345 * Any widget can surface an editor placeholder (out of stock, no active
346 * campaign, empty result, etc.) with one consistent design. Renders only in
347 * edit/preview mode and prints the notice CSS inline once per request.
348 *
349 * The notice lives in the Elementor preview iframe, which loads only frontend
350 * styles — so the rule is printed here instead of the editor panel stylesheet,
351 * and kept out of the compiled frontend bundle.
352 *
353 * @param string $message Notice text (already translated).
354 * @param string $extra_class Optional extra class for per-widget targeting.
355 * @param string $title Optional hover tooltip; defaults to the editor-only hint.
356 * @return void
357 */
358 public function editor_notice( $message, $extra_class = '', $title = '' ) {
359 if ( ! $this->is_edit_mode() || '' === $message ) {
360 return;
361 }
362 $this->editor_notice_style();
363 $classes = trim( 'rtsb-editor-notice ' . $extra_class );
364 $title = '' !== $title ? $title : esc_html__( 'This notice is only visible in the Elementor editor.', 'shopbuilder' );
365 ?>
366 <div class="<?php echo esc_attr( $classes ); ?>" title="<?php echo esc_attr( $title ); ?>">
367 <span class="rtsb-editor-notice__label"><?php echo esc_html__( 'Editor Notice:', 'shopbuilder' ); ?></span>
368 <?php echo esc_html( $message ); ?>
369 </div>
370 <?php
371 }
372
373 /**
374 * Print the shared editor-notice CSS inline, once per request.
375 *
376 * @return void
377 */
378 protected function editor_notice_style() {
379 static $printed = false;
380 if ( $printed ) {
381 return;
382 }
383 $printed = true;
384 ?>
385 <style>
386 .rtsb-editor-notice {
387 position: relative;
388 max-height: 500px;
389 padding: 12px 16px 12px 44px;
390 border: 1px solid #f0b849;
391 border-left: 4px solid #f0b849;
392 border-radius: 4px;
393 background: #fff8e5;
394 color: #8a6d3b;
395 font-size: 13px;
396 font-weight: 500;
397 line-height: 1.5;
398 box-shadow: 0 1px 4px rgba(138, 109, 59, 0.2);
399 cursor: help;
400 overflow: hidden;
401 opacity: 1;
402 transition: opacity 0.3s ease, max-height 0.3s ease, margin 0.3s ease, padding 0.3s ease, border-width 0.3s ease;
403 }
404 .rtsb-editor-notice::before {
405 content: "\26A0";
406 position: absolute;
407 top: 50%;
408 left: 16px;
409 transform: translateY(-50%);
410 font-size: 18px;
411 line-height: 1;
412 }
413 .rtsb-editor-notice__label {
414 font-weight: 700;
415 margin-right: 4px;
416 }
417 /* Fade + collapse the notice when the editor panel is hidden (preview toggle). */
418 .elementor-editor-preview .rtsb-editor-notice {
419 max-height: 0;
420 margin-top: 0;
421 padding-top: 0;
422 padding-bottom: 0;
423 border-top-width: 0;
424 border-bottom-width: 0;
425 opacity: 0;
426 }
427 </style>
428 <?php
429 }
430
431 /**
432 * Elementor Edit mode need some extra js for isotop reinitialize
433 *
434 * @return void
435 */
436 public function editor_slider_script() {
437 if ( ! empty( \Elementor\Plugin::$instance->editor ) && \Elementor\Plugin::$instance->editor->is_edit_mode() ) {
438 $selector = $this->get_unique_selector() . ' .rtsb-carousel-slider';
439 ?>
440 <script>
441 jQuery('<?php echo esc_attr( $selector ); ?>').rtsb_slider();
442 </script>
443 <?php
444 }
445 }
446
447 /**
448 * Elementor Edit mode need some extra js for isotop reinitialize
449 *
450 * @return void
451 */
452 public function editor_cart_icon_script() {
453 if ( $this->is_edit_mode() ) {
454 $selector = $this->get_unique_selector() . ' .has-cart-button';
455 ?>
456 <script type="text/javascript">
457 // Product Archive Catelog
458 (function ($) {
459 setTimeout( function (){
460 var cartWrpper = $('body').find('<?php echo esc_attr( $selector ); ?>');
461 var cartIcon = cartWrpper.attr('data-cart-icon');
462 var cartButton = cartWrpper.find(
463 '.product_type_grouped, .add_to_cart_button, .single_add_to_cart_button '
464 );
465 if (cartIcon) {
466 cartButton.find('i').remove();
467 cartButton.find('svg').remove();
468 cartButton.find('img').remove();
469 cartButton.prepend(cartIcon);
470 }
471 }, 2000);
472 })(jQuery);
473 </script>
474 <?php
475 }
476 }
477
478 /**
479 * Elementor Edit mode script
480 *
481 * @return void
482 */
483 public function edit_mode_script() {
484 if ( ! $this->is_edit_mode() ) {
485 return;
486 }
487 $ajaxurl = admin_url( 'admin-ajax.php' );
488
489 // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
490 if ( in_array( 'sitepress-multilingual-cms/sitepress.php', get_option( 'active_plugins' ) ) ) {
491 $ajaxurl = admin_url( 'admin-ajax.php?lang=' . ICL_LANGUAGE_CODE );
492 }
493 ?>
494 <script>
495 var rtsb = {
496 ajaxurl: '<?php echo esc_url( $ajaxurl ); ?>',
497 nonce: '<?php echo esc_attr( wp_create_nonce( rtsb()->nonceId ) ); ?>',
498 is_pro: '<?php echo esc_attr( rtsb()->has_pro() ? 'true' : 'false' ); ?>',
499 isOptimizationEnabled: '<?php echo esc_attr( Fns::is_optimization_enabled() ); ?>'
500 };
501
502 if (!rtsb.isOptimizationEnabled) {
503 rtsbElFrontend();
504
505 setTimeout(function() {
506 rtsbProductPageInit();
507 }, 1000);
508 } else {
509 if (typeof elementorFrontend !== 'undefined') {
510 window.waitForRTSB((RTSB) => {
511 RTSB.modules.get('elementorInit')?.refresh();
512 RTSB.modules.get('singleProductTabs')?.refresh();
513 RTSB.modules.get('reviewFormStar')?.refresh();
514 RTSB.modules.get('addCartIcon')?.refresh();
515 RTSB.modules.get('productImage')?.refresh();
516 RTSB.modules.get('CartQuantityHandler')?.refresh();
517 });
518 }
519 }
520
521 <?php if ( rtsb()->has_pro() ) { ?>
522 var isMasonry = jQuery('.rtsb-elementor-container .rtsb-masonry');
523
524 if(isMasonry.length > 0) {
525 isMasonry.masonry();
526 }
527
528 if (!'<?php echo esc_attr( Fns::is_optimization_enabled() ); ?>') {
529 <?php if ( 'rtsb-ajax-product-filters' === $this->rtsb_base ) { ?>
530 if (typeof rtsbFilters === 'function') {
531 rtsbFilters();
532 }
533 <?php } ?>
534
535 setTimeout( function (){
536 window.rtsbCountdownApply();
537 }, 1000 );
538 } else {
539 if (typeof elementorFrontend !== 'undefined') {
540 window.waitForRTSB((RTSB) => {
541 RTSB.modules.get('countdownPro')?.refresh();
542 RTSB.modules.get('elementorInitPro')?.refresh();
543 <?php if ( 'rtsb-ajax-product-filters' === $this->rtsb_base ) { ?>
544 RTSB.modules.get('ajaxProductFiltersPro')?.refresh();
545 <?php } ?>
546 });
547 }
548 }
549 <?php } ?>
550 </script>
551
552 <?php
553 }
554
555 /**
556 * Starts an Elementor Section
557 *
558 * @param string $label Section label.
559 * @param object $tab Tab ID.
560 * @param array $conditions Section Condition.
561 * @param array $condition Section Conditions.
562 * @return array
563 */
564 public function start_section( $label, $tab, $conditions = [], $condition = [] ) {
565 $start = [
566 'mode' => 'section_start',
567 'tab' => $tab,
568 'label' => $label,
569 ];
570 if ( ! empty( $condition ) ) {
571 $start['condition'] = $condition;
572 }
573 if ( ! empty( $conditions ) ) {
574 $start['conditions'] = $conditions;
575 }
576 return $start;
577 }
578
579 /**
580 * Ends an Elementor Section
581 *
582 * @return array
583 */
584 public function end_section() {
585 return [
586 'mode' => 'section_end',
587 ];
588 }
589
590 /**
591 * Theme Support for render/widget_controls
592 *
593 * @param string $support Support for render/widget_controls.
594 * @return void
595 */
596 public function theme_support( $support = 'render' ) {
597
598 if ( empty( $support ) ) {
599 return;
600 }
601 $theme = ucwords( str_replace( [ '_', '-', ' ' ], '', rtsb()->current_theme ) );
602
603 $supportClass = apply_filters(
604 'radiustheme/sb/widgetsupport/class',
605 [
606 'ShopbuilderPlugin' => 'RadiusTheme\SB\Controllers\ThemesSupport\\' . $theme . '\\WidgetsSupport',
607 'TheTheme' => \WidgetSupport::class,
608 ]
609 );
610
611 foreach ( $supportClass as $key => $theClass ) {
612 $themeWidgetSupport = get_theme_file_path( '/shopbuilder/WidgetSupport.php' );
613 if ( 'TheTheme' === $key && file_exists( $themeWidgetSupport ) ) {
614 require_once $themeWidgetSupport;
615 }
616 if ( class_exists( $theClass ) ) {
617 $method = $support . '_' . str_replace( [ '-', ' ' ], '_', $this->rtsb_base );
618 if ( method_exists( $theClass, $method ) ) {
619 $theClass::instance( $this )->$method();
620 }
621 }
622 }
623 }
624
625 /**
626 * Starts an Elementor tab group.
627 *
628 * @param array $conditions Tab condition.
629 * @param array $condition Tab condition.
630 * @return array
631 */
632 public function start_tab_group( $conditions = [], $condition = [] ) {
633 return [
634 'mode' => 'tabs_start',
635 'conditions' => $conditions,
636 'condition' => $condition,
637 ];
638 }
639
640 /**
641 * Ends an Elementor tab group.
642 *
643 * @param array $conditions Tab condition.
644 * @param array $condition Tab condition.
645 * @return array
646 */
647 public function end_tab_group( $conditions = [], $condition = [] ) {
648 return [
649 'mode' => 'tabs_end',
650 'conditions' => $conditions,
651 'condition' => $condition,
652 ];
653 }
654
655 /**
656 * Starts an Elementor tab
657 *
658 * @param string $label Section label.
659 * @param array $conditions Tab condition.
660 * @param array $condition Tab condition.
661 * @return array
662 */
663 public function start_tab( $label, $conditions = [], $condition = [] ) {
664 return [
665 'mode' => 'tab_start',
666 'label' => $label,
667 'conditions' => $conditions,
668 'condition' => $condition,
669 ];
670 }
671
672 /**
673 * Ends an Elementor tab.
674 *
675 * @param array $conditions Tab condition.
676 * @param array $condition Tab condition.
677 * @return array
678 */
679 public function end_tab( $conditions = [], $condition = [] ) {
680 return [
681 'mode' => 'tab_end',
682 'conditions' => $conditions,
683 'condition' => $condition,
684 ];
685 }
686
687 /**
688 * Starts an Elementor Section Heading
689 *
690 * @param string $label Heading label.
691 * @param string $separator Section separator.
692 * @param array $conditions Section Condition.
693 * @param array $condition Section Conditions.
694 * @return array
695 */
696 public function el_heading( $label, $separator = null, $conditions = [], $condition = [] ) {
697 return [
698 'type' => 'html',
699 'raw' => sprintf(
700 '<h3 class="rtsb-elementor-group-heading">%s</h3>',
701 $label
702 ),
703 'separator' => $separator,
704 'content_classes' => 'elementor-panel-heading-title',
705 'conditions' => $conditions,
706 'condition' => $condition,
707 ];
708 }
709
710 /**
711 * Prints a control notification.
712 *
713 * @param string $label Field label.
714 * @return string
715 */
716 public function is_pro_control( $label ) {
717 if ( rtsb()->has_pro() ) {
718 return $label;
719 }
720
721 return $label . $this->pro_label;
722 }
723
724 /**
725 * Adds a class.
726 *
727 * @return string
728 */
729 public function pro_class() {
730 return ! rtsb()->has_pro() ? 'rtsb-pro-field' : '';
731 }
732
733 /**
734 * Elementor Fields.
735 *
736 * @param string $type Control type.
737 *
738 * @return string
739 */
740 private static function el_fields( $type ) {
741
742 $controls = Controls_Manager::class;
743
744 switch ( $type ) {
745 case 'link':
746 $type = $controls::URL;
747 break;
748
749 case 'image-dimensions':
750 $type = $controls::IMAGE_DIMENSIONS;
751 break;
752
753 case 'html':
754 $type = $controls::RAW_HTML;
755 break;
756
757 case 'switch':
758 $type = $controls::SWITCHER;
759 break;
760
761 case 'popover':
762 $type = $controls::POPOVER_TOGGLE;
763 break;
764
765 case 'rtsb-image-selector':
766 $type = \RadiusTheme\SB\Elementor\Controls\ImageSelectorControl::$controlName;
767 break;
768
769 case 'rt-select2':
770 $type = \RadiusTheme\SB\Elementor\Controls\Select2AjaxControl::$controlName;
771 break;
772
773 case 'typography':
774 $type = Group_Control_Typography::get_type();
775 break;
776
777 case 'border':
778 $type = Group_Control_Border::get_type();
779 break;
780
781 case 'background':
782 $type = Group_Control_Background::get_type();
783 break;
784
785 case 'box-shadow':
786 $type = Group_Control_Box_Shadow::get_type();
787 break;
788
789 case 'text-shadow':
790 $type = Group_Control_Text_Shadow::get_type();
791 break;
792
793 case 'text-stroke':
794 $type = Group_Control_Text_Stroke::get_type();
795 break;
796
797 case 'css-filter':
798 $type = Group_Control_Css_Filter::get_type();
799 break;
800 default:
801 $type = constant( 'Elementor\Controls_Manager::' . strtoupper( $type ) );
802
803 }
804 return $type;
805 }
806
807 /**
808 * Elementor Fields.
809 *
810 * @param string $tab Tab.
811 *
812 * @return string
813 */
814 private static function el_tabs( $tab ) {
815 return constant( 'Elementor\Controls_Manager::TAB_' . strtoupper( $tab ) );
816 }
817
818
819 /**
820 * Init render hooks & functions.
821 *
822 * @return void
823 */
824 protected function render_start() {
825 add_filter( 'rtsb/countdown/campaign/parent/class', [ $this, 'countdown_campaign_parent_class' ], 15 );
826 do_action( 'rtsb/custom/products/before/template/load', $this );
827 $this->theme_support();
828
829 if ( $this->is_builder_mode() ) {
830 add_filter( 'wp_kses_allowed_html', [ FilterHooks::class, 'custom_wpkses_post_tags' ], 10, 2 );
831 }
832 }
833 /**
834 * Archive Custom Layout Widget Rendering.
835 *
836 * @param array $classes class list.
837 *
838 * @return array
839 */
840 public function countdown_campaign_parent_class( $classes ) {
841 $settings = $this->get_settings_for_display();
842 $layout = $settings['countdown_layout'] ?? 'horizontal';
843 $v_position = $settings['countdown_vertical_position'] ?? '';
844 $countdown_preset = $settings['countdown_preset'] ?? '';
845 $vertical_center = $settings['countdown_vertical_center'] ?? false;
846
847 $remove = [
848 'rtsb-countdown-horizontal',
849 'rtsb-countdown-vertical',
850 'rtsb-vertical-position-top-left',
851 'rtsb-vertical-position-top-right',
852 ];
853 $classes = array_filter(
854 $classes,
855 function ( $item ) use ( $remove ) {
856 return ! in_array( $item, $remove ); // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
857 }
858 );
859 $new_class = 'rtsb-countdown-' . esc_attr( $countdown_preset );
860 $new_class .= ' rtsb-countdown-' . esc_attr( $layout );
861
862 if ( $v_position && 'horizontal' !== $layout ) {
863 $vertical_class = 'rtsb-vertical-position-top-' . esc_attr( $v_position );
864 $classes[] = $vertical_class;
865 if ( 'yes' === $vertical_center ) {
866 $classes[] = 'rtsb-countdown-vertical-middle';
867 }
868 }
869
870 $classes[] = $new_class;
871
872 return $classes;
873 }
874 /**
875 * End render hooks & functions.
876 *
877 * @return void
878 */
879 protected function render_end() {
880 $this->edit_mode_script();
881 do_action( 'rtsb/custom/products/after/template/load', $this );
882 $this->theme_support( 'render_reset' );
883 remove_filter( 'rtsb/countdown/campaign/parent/class', [ $this, 'countdown_campaign_parent_class' ], 15 );
884 }
885
886 /**
887 * Elementor controls marge all settings
888 *
889 * @return void
890 */
891 protected function apply_hooks_before_render() {
892 if ( $this->is_edit_mode() ) {
893 add_filter( 'wp_calculate_image_srcset_meta', '__return_null' );
894 }
895 }
896
897 /**
898 * If checkout registration is disabled and not logged in,
899 * the user cannot check out.
900 *
901 * @return bool
902 */
903 protected function has_checkout_restriction() {
904 $checkout = WC()->checkout();
905
906 return ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in();
907 }
908
909 /**
910 * Widget Exceptions.
911 *
912 * @return bool
913 */
914 private function widget_exceptions() {
915 $exceptions = [
916 'rtsb-product-filters',
917 'rtsb-wishlist',
918 'rtsb-product-breadcrumbs',
919 ];
920
921 return in_array( $this->rtsb_base, $exceptions, true );
922 }
923 }
924