PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.49
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.49
51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 51.1.47 51.1.49 All 37 releases
king-addons / includes / widgets / Pros_Cons_Box / Pros_Cons_Box.php

Pros_Cons_Box.php in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.49, at includes/widgets/Pros_Cons_Box/Pros_Cons_Box.php

1,933 lines 63.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Pros and Cons Box Widget (Free).
4 *
5 * @package King_Addons
6 */
7
8 namespace King_Addons;
9
10 use Elementor\Controls_Manager;
11 use Elementor\Group_Control_Background;
12 use Elementor\Group_Control_Border;
13 use Elementor\Group_Control_Box_Shadow;
14 use Elementor\Group_Control_Typography;
15 use Elementor\Icons_Manager;
16 use Elementor\Plugin;
17 use Elementor\Repeater;
18 use Elementor\Widget_Base;
19
20 if (!defined('ABSPATH')) {
21 exit;
22 }
23
24 /**
25 * Renders a pros/cons comparison box.
26 */
27 class Pros_Cons_Box extends Widget_Base
28 {
29 /**
30 * Current settings for render helpers.
31 *
32 * @var array<string, mixed>
33 */
34 protected array $current_settings = [];
35 /**
36 * Widget slug.
37 */
38 public function get_name(): string
39 {
40 return 'king-addons-pros-cons-box';
41 }
42
43 /**
44 * Widget title.
45 */
46 public function get_title(): string
47 {
48 return esc_html__('Pros and Cons Box', 'king-addons');
49 }
50
51 /**
52 * Widget icon.
53 */
54 public function get_icon(): string
55 {
56 return 'eicon-editor-list-ul';
57 }
58
59 /**
60 * Styles used.
61 *
62 * @return array<int, string>
63 */
64 public function get_style_depends(): array
65 {
66 return [
67 KING_ADDONS_ASSETS_UNIQUE_KEY . '-pros-cons-box-style',
68 ];
69 }
70
71 /**
72 * Scripts used.
73 *
74 * @return array<int, string>
75 */
76 public function get_script_depends(): array
77 {
78 return [
79 KING_ADDONS_ASSETS_UNIQUE_KEY . '-pros-cons-box-script',
80 ];
81 }
82
83 /**
84 * Widget categories.
85 *
86 * @return array<int, string>
87 */
88 public function get_categories(): array
89 {
90 return ['king-addons'];
91 }
92
93 /**
94 * Widget keywords.
95 *
96 * @return array<int, string>
97 */
98 public function get_keywords(): array
99 {
100 return ['pros', 'cons', 'comparison', 'review', 'box'];
101 }
102
103 /**
104 * Register controls.
105 */
106 public function register_controls(): void
107 {
108 $this->register_general_controls();
109 $this->register_layout_controls();
110 $this->register_list_controls();
111 $this->register_pros_controls();
112 $this->register_cons_controls();
113 $this->register_style_general_controls();
114 $this->register_style_section_controls();
115 $this->register_style_pros_controls();
116 $this->register_style_cons_controls();
117 $this->register_pro_notice_controls();
118 }
119
120 /**
121 * Render widget output.
122 */
123 public function render(): void
124 {
125 $settings = $this->get_settings_for_display();
126 $this->render_output($settings);
127 }
128
129 /**
130 * Render output.
131 *
132 * @param array<string, mixed> $settings Settings.
133 */
134 protected function render_output(array $settings): void
135 {
136 $this->current_settings = $settings;
137 $pros_items = $this->prepare_items($settings['kng_pros_items'] ?? []);
138 $cons_items = $this->prepare_items($settings['kng_cons_items'] ?? []);
139
140 $pros_count = count($pros_items);
141 $cons_count = count($cons_items);
142
143 $is_editor = class_exists(Plugin::class) && Plugin::$instance->editor->is_edit_mode();
144
145 $pros_payload = $this->build_section_payload('pros', $settings, $pros_items, $pros_count, $is_editor);
146 $cons_payload = $this->build_section_payload('cons', $settings, $cons_items, $cons_count, $is_editor);
147
148 if (!$pros_payload['show'] && !$cons_payload['show']) {
149 return;
150 }
151
152 $context = [
153 'show_pros' => $pros_payload['show'],
154 'show_cons' => $cons_payload['show'],
155 'pros_count' => $pros_count,
156 'cons_count' => $cons_count,
157 ];
158
159 $wrapper_classes = $this->get_wrapper_classes($settings, $context);
160 $data_attributes = $this->get_data_attributes($settings);
161 ?>
162 <div class="<?php echo esc_attr(implode(' ', $wrapper_classes)); ?>"<?php echo $data_attributes; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
163 <?php $this->render_header($settings, $context); ?>
164 <div class="king-addons-pros-cons__columns">
165 <?php if ($pros_payload['show']) : ?>
166 <?php $this->render_section('pros', $settings, $pros_payload); ?>
167 <?php endif; ?>
168 <?php if ($cons_payload['show']) : ?>
169 <?php $this->render_section('cons', $settings, $cons_payload); ?>
170 <?php endif; ?>
171 </div>
172 <?php $this->render_schema($settings, $context); ?>
173 </div>
174 <?php
175 }
176
177 /**
178 * Register general content controls.
179 */
180 protected function register_general_controls(): void
181 {
182 $this->start_controls_section(
183 'kng_general_section',
184 [
185 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('General', 'king-addons'),
186 'tab' => Controls_Manager::TAB_CONTENT,
187 ]
188 );
189
190 $this->add_control(
191 'kng_main_title',
192 [
193 'label' => esc_html__('Main Title', 'king-addons'),
194 'type' => Controls_Manager::TEXT,
195 'default' => esc_html__('Pros and Cons', 'king-addons'),
196 'label_block' => true,
197 ]
198 );
199
200 $this->add_control(
201 'kng_description',
202 [
203 'label' => esc_html__('Description', 'king-addons'),
204 'type' => Controls_Manager::TEXTAREA,
205 'rows' => 3,
206 'default' => '',
207 ]
208 );
209
210 $this->end_controls_section();
211 }
212
213 /**
214 * Register layout controls.
215 */
216 protected function register_layout_controls(): void
217 {
218 $this->start_controls_section(
219 'kng_layout_section',
220 [
221 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Layout', 'king-addons'),
222 'tab' => Controls_Manager::TAB_CONTENT,
223 ]
224 );
225
226 $this->add_control(
227 'kng_layout',
228 [
229 'label' => esc_html__('Layout', 'king-addons'),
230 'type' => Controls_Manager::SELECT,
231 'default' => 'side',
232 'options' => [
233 'side' => esc_html__('Side by Side', 'king-addons'),
234 'stacked' => esc_html__('Stacked', 'king-addons'),
235 ],
236 ]
237 );
238
239 $this->add_control(
240 'kng_stack_on_mobile',
241 [
242 'label' => esc_html__('Stack on Mobile', 'king-addons'),
243 'type' => Controls_Manager::SWITCHER,
244 'return_value' => 'yes',
245 'default' => 'yes',
246 ]
247 );
248
249 $this->add_responsive_control(
250 'kng_columns_gap',
251 [
252 'label' => esc_html__('Columns Gap', 'king-addons'),
253 'type' => Controls_Manager::SLIDER,
254 'size_units' => ['px'],
255 'range' => [
256 'px' => [
257 'min' => 0,
258 'max' => 80,
259 ],
260 ],
261 'default' => [
262 'size' => 24,
263 'unit' => 'px',
264 ],
265 'selectors' => [
266 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-pros-cons-gap: {{SIZE}}{{UNIT}};',
267 ],
268 ]
269 );
270
271 $this->add_responsive_control(
272 'kng_split_ratio',
273 [
274 'label' => esc_html__('Pros Width (%)', 'king-addons'),
275 'type' => Controls_Manager::SLIDER,
276 'size_units' => ['%'],
277 'range' => [
278 '%' => [
279 'min' => 30,
280 'max' => 70,
281 ],
282 ],
283 'default' => [
284 'size' => 50,
285 'unit' => '%',
286 ],
287 'condition' => [
288 'kng_layout' => 'side',
289 ],
290 'selectors' => [
291 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-pros-width: {{SIZE}}{{UNIT}};',
292 ],
293 ]
294 );
295
296 $this->add_responsive_control(
297 'kng_box_padding',
298 [
299 'label' => esc_html__('Box Padding', 'king-addons'),
300 'type' => Controls_Manager::DIMENSIONS,
301 'size_units' => ['px', 'em'],
302 'selectors' => [
303 '{{WRAPPER}} .king-addons-pros-cons__section' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
304 ],
305 ]
306 );
307
308 $this->add_control(
309 'kng_preset',
310 [
311 'label' => esc_html__('Style Preset', 'king-addons'),
312 'type' => Controls_Manager::SELECT,
313 'default' => 'clean',
314 'options' => $this->get_preset_options(),
315 ]
316 );
317
318 $this->end_controls_section();
319 }
320
321 /**
322 * Register list controls.
323 */
324 protected function register_list_controls(): void
325 {
326 $this->start_controls_section(
327 'kng_list_section',
328 [
329 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('List Settings', 'king-addons'),
330 'tab' => Controls_Manager::TAB_CONTENT,
331 ]
332 );
333
334 $this->add_control(
335 'kng_show_count',
336 [
337 'label' => esc_html__('Show Count', 'king-addons'),
338 'type' => Controls_Manager::SWITCHER,
339 'return_value' => 'yes',
340 'default' => '',
341 ]
342 );
343
344 $this->add_control(
345 'kng_show_item_icons',
346 [
347 'label' => esc_html__('Show Item Icons', 'king-addons'),
348 'type' => Controls_Manager::SWITCHER,
349 'return_value' => 'yes',
350 'default' => 'yes',
351 ]
352 );
353
354 $this->add_control(
355 'kng_item_icon_position',
356 [
357 'label' => esc_html__('Icon Position', 'king-addons'),
358 'type' => Controls_Manager::CHOOSE,
359 'options' => [
360 'left' => [
361 'title' => esc_html__('Left', 'king-addons'),
362 'icon' => 'eicon-h-align-left',
363 ],
364 'right' => [
365 'title' => esc_html__('Right', 'king-addons'),
366 'icon' => 'eicon-h-align-right',
367 ],
368 ],
369 'toggle' => false,
370 'default' => 'left',
371 ]
372 );
373
374 $this->add_control(
375 'kng_pros_item_icon',
376 [
377 'label' => esc_html__('Pros Default Icon', 'king-addons'),
378 'type' => Controls_Manager::ICONS,
379 'default' => [
380 'value' => 'fas fa-check',
381 'library' => 'fa-solid',
382 ],
383 'condition' => [
384 'kng_show_item_icons' => 'yes',
385 ],
386 ]
387 );
388
389 $this->add_control(
390 'kng_cons_item_icon',
391 [
392 'label' => esc_html__('Cons Default Icon', 'king-addons'),
393 'type' => Controls_Manager::ICONS,
394 'default' => [
395 'value' => 'fas fa-times',
396 'library' => 'fa-solid',
397 ],
398 'condition' => [
399 'kng_show_item_icons' => 'yes',
400 ],
401 ]
402 );
403
404 $this->end_controls_section();
405 }
406
407 /**
408 * Register pros controls.
409 */
410 protected function register_pros_controls(): void
411 {
412 $this->start_controls_section(
413 'kng_pros_section',
414 [
415 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Pros', 'king-addons'),
416 'tab' => Controls_Manager::TAB_CONTENT,
417 ]
418 );
419
420 $this->add_control(
421 'kng_pros_title',
422 [
423 'label' => esc_html__('Pros Title', 'king-addons'),
424 'type' => Controls_Manager::TEXT,
425 'default' => esc_html__('Pros', 'king-addons'),
426 'label_block' => true,
427 ]
428 );
429
430 $this->add_control(
431 'kng_pros_subtitle',
432 [
433 'label' => esc_html__('Pros Subtitle', 'king-addons'),
434 'type' => Controls_Manager::TEXT,
435 'default' => '',
436 'label_block' => true,
437 ]
438 );
439
440 $this->add_control(
441 'kng_pros_title_icon',
442 [
443 'label' => esc_html__('Pros Title Icon', 'king-addons'),
444 'type' => Controls_Manager::ICONS,
445 ]
446 );
447
448 $repeater = new Repeater();
449
450 $repeater->add_control(
451 'kng_item_text',
452 [
453 'label' => esc_html__('Text', 'king-addons'),
454 'type' => Controls_Manager::TEXTAREA,
455 'rows' => 2,
456 'default' => esc_html__('Clear advantage with a short explanation.', 'king-addons'),
457 ]
458 );
459
460 $repeater->add_control(
461 'kng_item_icon',
462 [
463 'label' => esc_html__('Icon Override', 'king-addons'),
464 'type' => Controls_Manager::ICONS,
465 'condition' => [
466 'kng_show_item_icons' => 'yes',
467 ],
468 ]
469 );
470
471 $repeater->add_control(
472 'kng_item_highlight',
473 [
474 'label' => esc_html__('Highlight', 'king-addons'),
475 'type' => Controls_Manager::SWITCHER,
476 'return_value' => 'yes',
477 'default' => '',
478 ]
479 );
480
481 $repeater->add_control(
482 'kng_item_tooltip',
483 [
484 'label' => esc_html__('Tooltip (Pro)', 'king-addons'),
485 'type' => Controls_Manager::TEXTAREA,
486 'rows' => 2,
487 'condition' => [
488 'kng_enable_tooltips' => 'yes',
489 ],
490 ]
491 );
492
493 $this->add_control(
494 'kng_pros_items',
495 [
496 'label' => esc_html__('Pros Items', 'king-addons'),
497 'type' => Controls_Manager::REPEATER,
498 'fields' => $repeater->get_controls(),
499 'default' => [],
500 'title_field' => '{{{ kng_item_text }}}',
501 ]
502 );
503
504 $this->add_control(
505 'kng_pros_empty_state',
506 [
507 'label' => esc_html__('Empty State', 'king-addons'),
508 'type' => Controls_Manager::SELECT,
509 'default' => 'hide',
510 'options' => [
511 'hide' => esc_html__('Hide Section', 'king-addons'),
512 'placeholder' => esc_html__('Show Placeholder', 'king-addons'),
513 ],
514 ]
515 );
516
517 $this->add_control(
518 'kng_pros_empty_text',
519 [
520 'label' => esc_html__('Placeholder Text', 'king-addons'),
521 'type' => Controls_Manager::TEXT,
522 'default' => esc_html__('Add pros items to show this section.', 'king-addons'),
523 'condition' => [
524 'kng_pros_empty_state' => 'placeholder',
525 ],
526 ]
527 );
528
529 $this->end_controls_section();
530 }
531
532 /**
533 * Register cons controls.
534 */
535 protected function register_cons_controls(): void
536 {
537 $this->start_controls_section(
538 'kng_cons_section',
539 [
540 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Cons', 'king-addons'),
541 'tab' => Controls_Manager::TAB_CONTENT,
542 ]
543 );
544
545 $this->add_control(
546 'kng_cons_title',
547 [
548 'label' => esc_html__('Cons Title', 'king-addons'),
549 'type' => Controls_Manager::TEXT,
550 'default' => esc_html__('Cons', 'king-addons'),
551 'label_block' => true,
552 ]
553 );
554
555 $this->add_control(
556 'kng_cons_subtitle',
557 [
558 'label' => esc_html__('Cons Subtitle', 'king-addons'),
559 'type' => Controls_Manager::TEXT,
560 'default' => '',
561 'label_block' => true,
562 ]
563 );
564
565 $this->add_control(
566 'kng_cons_title_icon',
567 [
568 'label' => esc_html__('Cons Title Icon', 'king-addons'),
569 'type' => Controls_Manager::ICONS,
570 ]
571 );
572
573 $repeater = new Repeater();
574
575 $repeater->add_control(
576 'kng_item_text',
577 [
578 'label' => esc_html__('Text', 'king-addons'),
579 'type' => Controls_Manager::TEXTAREA,
580 'rows' => 2,
581 'default' => esc_html__('Note a limitation or tradeoff to be aware of.', 'king-addons'),
582 ]
583 );
584
585 $repeater->add_control(
586 'kng_item_icon',
587 [
588 'label' => esc_html__('Icon Override', 'king-addons'),
589 'type' => Controls_Manager::ICONS,
590 'condition' => [
591 'kng_show_item_icons' => 'yes',
592 ],
593 ]
594 );
595
596 $repeater->add_control(
597 'kng_item_highlight',
598 [
599 'label' => esc_html__('Highlight', 'king-addons'),
600 'type' => Controls_Manager::SWITCHER,
601 'return_value' => 'yes',
602 'default' => '',
603 ]
604 );
605
606 $repeater->add_control(
607 'kng_item_tooltip',
608 [
609 'label' => esc_html__('Tooltip (Pro)', 'king-addons'),
610 'type' => Controls_Manager::TEXTAREA,
611 'rows' => 2,
612 'condition' => [
613 'kng_enable_tooltips' => 'yes',
614 ],
615 ]
616 );
617
618 $this->add_control(
619 'kng_cons_items',
620 [
621 'label' => esc_html__('Cons Items', 'king-addons'),
622 'type' => Controls_Manager::REPEATER,
623 'fields' => $repeater->get_controls(),
624 'default' => [],
625 'title_field' => '{{{ kng_item_text }}}',
626 ]
627 );
628
629 $this->add_control(
630 'kng_cons_empty_state',
631 [
632 'label' => esc_html__('Empty State', 'king-addons'),
633 'type' => Controls_Manager::SELECT,
634 'default' => 'hide',
635 'options' => [
636 'hide' => esc_html__('Hide Section', 'king-addons'),
637 'placeholder' => esc_html__('Show Placeholder', 'king-addons'),
638 ],
639 ]
640 );
641
642 $this->add_control(
643 'kng_cons_empty_text',
644 [
645 'label' => esc_html__('Placeholder Text', 'king-addons'),
646 'type' => Controls_Manager::TEXT,
647 'default' => esc_html__('Add cons items to show this section.', 'king-addons'),
648 'condition' => [
649 'kng_cons_empty_state' => 'placeholder',
650 ],
651 ]
652 );
653
654 $this->end_controls_section();
655 }
656
657 /**
658 * Register general style controls.
659 */
660 protected function register_style_general_controls(): void
661 {
662 $this->start_controls_section(
663 'kng_style_general_section',
664 [
665 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('General', 'king-addons'),
666 'tab' => Controls_Manager::TAB_STYLE,
667 ]
668 );
669
670 $this->add_group_control(
671 Group_Control_Background::get_type(),
672 [
673 'name' => 'kng_box_background',
674 'selector' => '{{WRAPPER}} .king-addons-pros-cons',
675 ]
676 );
677
678 $this->add_group_control(
679 Group_Control_Border::get_type(),
680 [
681 'name' => 'kng_box_border',
682 'selector' => '{{WRAPPER}} .king-addons-pros-cons',
683 ]
684 );
685
686 $this->add_control(
687 'kng_box_radius',
688 [
689 'label' => esc_html__('Border Radius', 'king-addons'),
690 'type' => Controls_Manager::SLIDER,
691 'size_units' => ['px', '%'],
692 'range' => [
693 'px' => ['min' => 0, 'max' => 60],
694 '%' => ['min' => 0, 'max' => 100],
695 ],
696 'selectors' => [
697 '{{WRAPPER}} .king-addons-pros-cons' => 'border-radius: {{SIZE}}{{UNIT}};',
698 ],
699 ]
700 );
701
702 $this->add_group_control(
703 Group_Control_Box_Shadow::get_type(),
704 [
705 'name' => 'kng_box_shadow',
706 'selector' => '{{WRAPPER}} .king-addons-pros-cons',
707 ]
708 );
709
710 $this->add_group_control(
711 Group_Control_Typography::get_type(),
712 [
713 'name' => 'kng_title_typography',
714 'selector' => '{{WRAPPER}} .king-addons-pros-cons__title',
715 ]
716 );
717
718 $this->add_control(
719 'kng_title_color',
720 [
721 'label' => esc_html__('Title Color', 'king-addons'),
722 'type' => Controls_Manager::COLOR,
723 'selectors' => [
724 '{{WRAPPER}} .king-addons-pros-cons__title' => 'color: {{VALUE}};',
725 ],
726 ]
727 );
728
729 $this->add_group_control(
730 Group_Control_Typography::get_type(),
731 [
732 'name' => 'kng_description_typography',
733 'selector' => '{{WRAPPER}} .king-addons-pros-cons__description',
734 ]
735 );
736
737 $this->add_control(
738 'kng_description_color',
739 [
740 'label' => esc_html__('Description Color', 'king-addons'),
741 'type' => Controls_Manager::COLOR,
742 'selectors' => [
743 '{{WRAPPER}} .king-addons-pros-cons__description' => 'color: {{VALUE}};',
744 ],
745 ]
746 );
747
748 $this->add_responsive_control(
749 'kng_header_spacing',
750 [
751 'label' => esc_html__('Header Bottom Spacing', 'king-addons'),
752 'type' => Controls_Manager::SLIDER,
753 'size_units' => ['px'],
754 'range' => [
755 'px' => ['min' => 0, 'max' => 80],
756 ],
757 'selectors' => [
758 '{{WRAPPER}} .king-addons-pros-cons__header' => 'margin-bottom: {{SIZE}}{{UNIT}};',
759 ],
760 ]
761 );
762
763 $this->end_controls_section();
764 }
765
766 /**
767 * Register shared section style controls.
768 */
769 protected function register_style_section_controls(): void
770 {
771 $this->start_controls_section(
772 'kng_style_section',
773 [
774 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Section', 'king-addons'),
775 'tab' => Controls_Manager::TAB_STYLE,
776 ]
777 );
778
779 $this->add_group_control(
780 Group_Control_Typography::get_type(),
781 [
782 'name' => 'kng_section_title_typography',
783 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section-title',
784 ]
785 );
786
787 $this->add_group_control(
788 Group_Control_Typography::get_type(),
789 [
790 'name' => 'kng_section_subtitle_typography',
791 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section-subtitle',
792 ]
793 );
794
795 $this->add_group_control(
796 Group_Control_Typography::get_type(),
797 [
798 'name' => 'kng_item_typography',
799 'selector' => '{{WRAPPER}} .king-addons-pros-cons__item-text',
800 ]
801 );
802
803 $this->add_responsive_control(
804 'kng_section_spacing',
805 [
806 'label' => esc_html__('Title Bottom Spacing', 'king-addons'),
807 'type' => Controls_Manager::SLIDER,
808 'size_units' => ['px'],
809 'range' => [
810 'px' => ['min' => 0, 'max' => 60],
811 ],
812 'selectors' => [
813 '{{WRAPPER}} .king-addons-pros-cons__section-header' => 'margin-bottom: {{SIZE}}{{UNIT}};',
814 ],
815 ]
816 );
817
818 $this->add_responsive_control(
819 'kng_item_spacing',
820 [
821 'label' => esc_html__('Item Spacing', 'king-addons'),
822 'type' => Controls_Manager::SLIDER,
823 'size_units' => ['px'],
824 'range' => [
825 'px' => ['min' => 0, 'max' => 40],
826 ],
827 'selectors' => [
828 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-pros-cons-item-gap: {{SIZE}}{{UNIT}};',
829 ],
830 ]
831 );
832
833 $this->add_control(
834 'kng_highlight_text_color',
835 [
836 'label' => esc_html__('Highlight Text Color', 'king-addons'),
837 'type' => Controls_Manager::COLOR,
838 'selectors' => [
839 '{{WRAPPER}} .king-addons-pros-cons__item.is-highlight .king-addons-pros-cons__item-text' => 'color: {{VALUE}};',
840 ],
841 ]
842 );
843
844 $this->add_responsive_control(
845 'kng_highlight_radius',
846 [
847 'label' => esc_html__('Highlight Border Radius', 'king-addons'),
848 'type' => Controls_Manager::SLIDER,
849 'size_units' => ['px', '%'],
850 'range' => [
851 'px' => ['min' => 0, 'max' => 40],
852 '%' => ['min' => 0, 'max' => 100],
853 ],
854 'selectors' => [
855 '{{WRAPPER}} .king-addons-pros-cons__item.is-highlight' => 'border-radius: {{SIZE}}{{UNIT}};',
856 ],
857 ]
858 );
859
860 $this->add_responsive_control(
861 'kng_highlight_padding',
862 [
863 'label' => esc_html__('Highlight Padding', 'king-addons'),
864 'type' => Controls_Manager::DIMENSIONS,
865 'size_units' => ['px', 'em'],
866 'selectors' => [
867 '{{WRAPPER}} .king-addons-pros-cons__item.is-highlight' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
868 ],
869 ]
870 );
871
872 $this->add_responsive_control(
873 'kng_item_icon_size',
874 [
875 'label' => esc_html__('Item Icon Size', 'king-addons'),
876 'type' => Controls_Manager::SLIDER,
877 'size_units' => ['px'],
878 'range' => [
879 'px' => ['min' => 10, 'max' => 36],
880 ],
881 'selectors' => [
882 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-pros-cons-icon-size: {{SIZE}}{{UNIT}};',
883 ],
884 'condition' => [
885 'kng_show_item_icons' => 'yes',
886 ],
887 ]
888 );
889
890 $this->add_responsive_control(
891 'kng_item_icon_gap',
892 [
893 'label' => esc_html__('Item Icon Gap', 'king-addons'),
894 'type' => Controls_Manager::SLIDER,
895 'size_units' => ['px'],
896 'range' => [
897 'px' => ['min' => 0, 'max' => 30],
898 ],
899 'selectors' => [
900 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-pros-cons-icon-gap: {{SIZE}}{{UNIT}};',
901 ],
902 'condition' => [
903 'kng_show_item_icons' => 'yes',
904 ],
905 ]
906 );
907
908 $this->add_responsive_control(
909 'kng_title_icon_size',
910 [
911 'label' => esc_html__('Title Icon Size', 'king-addons'),
912 'type' => Controls_Manager::SLIDER,
913 'size_units' => ['px'],
914 'range' => [
915 'px' => ['min' => 10, 'max' => 32],
916 ],
917 'selectors' => [
918 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-pros-cons-title-icon-size: {{SIZE}}{{UNIT}};',
919 ],
920 ]
921 );
922
923 $this->add_responsive_control(
924 'kng_title_icon_gap',
925 [
926 'label' => esc_html__('Title Icon Gap', 'king-addons'),
927 'type' => Controls_Manager::SLIDER,
928 'size_units' => ['px'],
929 'range' => [
930 'px' => ['min' => 0, 'max' => 40],
931 ],
932 'selectors' => [
933 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-pros-cons-title-icon-gap: {{SIZE}}{{UNIT}};',
934 ],
935 ]
936 );
937
938 $this->add_control(
939 'kng_title_icon_position',
940 [
941 'label' => esc_html__('Title Icon Position', 'king-addons'),
942 'type' => Controls_Manager::CHOOSE,
943 'options' => [
944 'left' => [
945 'title' => esc_html__('Left', 'king-addons'),
946 'icon' => 'eicon-h-align-left',
947 ],
948 'right' => [
949 'title' => esc_html__('Right', 'king-addons'),
950 'icon' => 'eicon-h-align-right',
951 ],
952 ],
953 'toggle' => false,
954 'default' => 'left',
955 'prefix_class' => 'king-addons-pros-cons-title-icon-',
956 ]
957 );
958
959 $this->add_group_control(
960 Group_Control_Background::get_type(),
961 [
962 'name' => 'kng_section_header_background',
963 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section-header',
964 ]
965 );
966
967 $this->add_group_control(
968 Group_Control_Border::get_type(),
969 [
970 'name' => 'kng_section_header_border',
971 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section-header',
972 ]
973 );
974
975 $this->add_responsive_control(
976 'kng_section_header_radius',
977 [
978 'label' => esc_html__('Header Border Radius', 'king-addons'),
979 'type' => Controls_Manager::SLIDER,
980 'size_units' => ['px', '%'],
981 'range' => [
982 'px' => ['min' => 0, 'max' => 60],
983 '%' => ['min' => 0, 'max' => 100],
984 ],
985 'selectors' => [
986 '{{WRAPPER}} .king-addons-pros-cons__section-header' => 'border-radius: {{SIZE}}{{UNIT}};',
987 ],
988 ]
989 );
990
991 $this->add_responsive_control(
992 'kng_section_header_padding',
993 [
994 'label' => esc_html__('Header Padding', 'king-addons'),
995 'type' => Controls_Manager::DIMENSIONS,
996 'size_units' => ['px', 'em'],
997 'selectors' => [
998 '{{WRAPPER}} .king-addons-pros-cons__section-header' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
999 ],
1000 ]
1001 );
1002
1003 $this->end_controls_section();
1004 }
1005
1006 /**
1007 * Register pros style controls.
1008 */
1009 protected function register_style_pros_controls(): void
1010 {
1011 $this->start_controls_section(
1012 'kng_style_pros_section',
1013 [
1014 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Pros Styles', 'king-addons'),
1015 'tab' => Controls_Manager::TAB_STYLE,
1016 ]
1017 );
1018
1019 $this->add_control(
1020 'kng_pros_title_color',
1021 [
1022 'label' => esc_html__('Title Color', 'king-addons'),
1023 'type' => Controls_Manager::COLOR,
1024 'selectors' => [
1025 '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__section-title' => 'color: {{VALUE}};',
1026 ],
1027 ]
1028 );
1029
1030 $this->add_control(
1031 'kng_pros_subtitle_color',
1032 [
1033 'label' => esc_html__('Subtitle Color', 'king-addons'),
1034 'type' => Controls_Manager::COLOR,
1035 'selectors' => [
1036 '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__section-subtitle' => 'color: {{VALUE}};',
1037 ],
1038 ]
1039 );
1040
1041 $this->add_control(
1042 'kng_pros_item_text_color',
1043 [
1044 'label' => esc_html__('Item Text Color', 'king-addons'),
1045 'type' => Controls_Manager::COLOR,
1046 'selectors' => [
1047 '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__item-text' => 'color: {{VALUE}};',
1048 ],
1049 ]
1050 );
1051
1052 $this->add_control(
1053 'kng_pros_highlight_text_color',
1054 [
1055 'label' => esc_html__('Highlight Text Color', 'king-addons'),
1056 'type' => Controls_Manager::COLOR,
1057 'selectors' => [
1058 '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__item.is-highlight .king-addons-pros-cons__item-text' => 'color: {{VALUE}};',
1059 ],
1060 ]
1061 );
1062
1063 $this->add_control(
1064 'kng_pros_accent_color',
1065 [
1066 'label' => esc_html__('Accent Color', 'king-addons'),
1067 'type' => Controls_Manager::COLOR,
1068 'selectors' => [
1069 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-pros-accent: {{VALUE}};',
1070 ],
1071 ]
1072 );
1073
1074 $this->add_control(
1075 'kng_pros_title_icon_color',
1076 [
1077 'label' => esc_html__('Title Icon Color', 'king-addons'),
1078 'type' => Controls_Manager::COLOR,
1079 'selectors' => [
1080 '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__section-title-icon' => 'color: {{VALUE}};',
1081 '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__section-title-icon svg' => 'fill: {{VALUE}};',
1082 ],
1083 ]
1084 );
1085
1086 $this->add_control(
1087 'kng_pros_header_heading',
1088 [
1089 'label' => esc_html__('Header', 'king-addons'),
1090 'type' => Controls_Manager::HEADING,
1091 'separator' => 'before',
1092 ]
1093 );
1094
1095 $this->add_group_control(
1096 Group_Control_Background::get_type(),
1097 [
1098 'name' => 'kng_pros_header_background',
1099 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__section-header',
1100 ]
1101 );
1102
1103 $this->add_group_control(
1104 Group_Control_Border::get_type(),
1105 [
1106 'name' => 'kng_pros_header_border',
1107 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__section-header',
1108 ]
1109 );
1110
1111 $this->add_responsive_control(
1112 'kng_pros_header_radius',
1113 [
1114 'label' => esc_html__('Header Border Radius', 'king-addons'),
1115 'type' => Controls_Manager::SLIDER,
1116 'size_units' => ['px', '%'],
1117 'range' => [
1118 'px' => ['min' => 0, 'max' => 60],
1119 '%' => ['min' => 0, 'max' => 100],
1120 ],
1121 'selectors' => [
1122 '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__section-header' => 'border-radius: {{SIZE}}{{UNIT}};',
1123 ],
1124 ]
1125 );
1126
1127 $this->add_responsive_control(
1128 'kng_pros_header_padding',
1129 [
1130 'label' => esc_html__('Header Padding', 'king-addons'),
1131 'type' => Controls_Manager::DIMENSIONS,
1132 'size_units' => ['px', 'em'],
1133 'selectors' => [
1134 '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__section-header' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1135 ],
1136 ]
1137 );
1138
1139 $this->add_group_control(
1140 Group_Control_Box_Shadow::get_type(),
1141 [
1142 'name' => 'kng_pros_header_shadow',
1143 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__section-header',
1144 ]
1145 );
1146
1147 $this->add_group_control(
1148 Group_Control_Background::get_type(),
1149 [
1150 'name' => 'kng_pros_section_background',
1151 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--pros',
1152 ]
1153 );
1154
1155 $this->add_group_control(
1156 Group_Control_Border::get_type(),
1157 [
1158 'name' => 'kng_pros_section_border',
1159 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--pros',
1160 ]
1161 );
1162
1163 $this->add_responsive_control(
1164 'kng_pros_section_radius',
1165 [
1166 'label' => esc_html__('Border Radius', 'king-addons'),
1167 'type' => Controls_Manager::SLIDER,
1168 'size_units' => ['px', '%'],
1169 'range' => [
1170 'px' => ['min' => 0, 'max' => 60],
1171 '%' => ['min' => 0, 'max' => 100],
1172 ],
1173 'selectors' => [
1174 '{{WRAPPER}} .king-addons-pros-cons__section--pros' => 'border-radius: {{SIZE}}{{UNIT}};',
1175 ],
1176 ]
1177 );
1178
1179 $this->add_group_control(
1180 Group_Control_Box_Shadow::get_type(),
1181 [
1182 'name' => 'kng_pros_section_shadow',
1183 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--pros',
1184 ]
1185 );
1186
1187 $this->add_control(
1188 'kng_pros_icon_color',
1189 [
1190 'label' => esc_html__('Item Icon Color', 'king-addons'),
1191 'type' => Controls_Manager::COLOR,
1192 'selectors' => [
1193 '{{WRAPPER}} .king-addons-pros-cons__section--pros .king-addons-pros-cons__item-icon' => 'color: {{VALUE}};',
1194 ],
1195 'condition' => [
1196 'kng_show_item_icons' => 'yes',
1197 ],
1198 ]
1199 );
1200
1201 $this->add_control(
1202 'kng_pros_highlight_background',
1203 [
1204 'label' => esc_html__('Highlight Background', 'king-addons'),
1205 'type' => Controls_Manager::COLOR,
1206 'selectors' => [
1207 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-pros-highlight: {{VALUE}};',
1208 ],
1209 ]
1210 );
1211
1212 $this->add_control(
1213 'kng_pros_accent_border_width',
1214 [
1215 'label' => esc_html__('Accent Border Width', 'king-addons'),
1216 'type' => Controls_Manager::SLIDER,
1217 'size_units' => ['px'],
1218 'range' => [
1219 'px' => ['min' => 0, 'max' => 10],
1220 ],
1221 'selectors' => [
1222 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-pros-border-width: {{SIZE}}{{UNIT}};',
1223 ],
1224 ]
1225 );
1226
1227 $this->end_controls_section();
1228 }
1229
1230 /**
1231 * Register cons style controls.
1232 */
1233 protected function register_style_cons_controls(): void
1234 {
1235 $this->start_controls_section(
1236 'kng_style_cons_section',
1237 [
1238 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Cons Styles', 'king-addons'),
1239 'tab' => Controls_Manager::TAB_STYLE,
1240 ]
1241 );
1242
1243 $this->add_control(
1244 'kng_cons_title_color',
1245 [
1246 'label' => esc_html__('Title Color', 'king-addons'),
1247 'type' => Controls_Manager::COLOR,
1248 'selectors' => [
1249 '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__section-title' => 'color: {{VALUE}};',
1250 ],
1251 ]
1252 );
1253
1254 $this->add_control(
1255 'kng_cons_subtitle_color',
1256 [
1257 'label' => esc_html__('Subtitle Color', 'king-addons'),
1258 'type' => Controls_Manager::COLOR,
1259 'selectors' => [
1260 '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__section-subtitle' => 'color: {{VALUE}};',
1261 ],
1262 ]
1263 );
1264
1265 $this->add_control(
1266 'kng_cons_item_text_color',
1267 [
1268 'label' => esc_html__('Item Text Color', 'king-addons'),
1269 'type' => Controls_Manager::COLOR,
1270 'selectors' => [
1271 '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__item-text' => 'color: {{VALUE}};',
1272 ],
1273 ]
1274 );
1275
1276 $this->add_control(
1277 'kng_cons_highlight_text_color',
1278 [
1279 'label' => esc_html__('Highlight Text Color', 'king-addons'),
1280 'type' => Controls_Manager::COLOR,
1281 'selectors' => [
1282 '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__item.is-highlight .king-addons-pros-cons__item-text' => 'color: {{VALUE}};',
1283 ],
1284 ]
1285 );
1286
1287 $this->add_control(
1288 'kng_cons_accent_color',
1289 [
1290 'label' => esc_html__('Accent Color', 'king-addons'),
1291 'type' => Controls_Manager::COLOR,
1292 'selectors' => [
1293 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-cons-accent: {{VALUE}};',
1294 ],
1295 ]
1296 );
1297
1298 $this->add_control(
1299 'kng_cons_title_icon_color',
1300 [
1301 'label' => esc_html__('Title Icon Color', 'king-addons'),
1302 'type' => Controls_Manager::COLOR,
1303 'selectors' => [
1304 '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__section-title-icon' => 'color: {{VALUE}};',
1305 '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__section-title-icon svg' => 'fill: {{VALUE}};',
1306 ],
1307 ]
1308 );
1309
1310 $this->add_control(
1311 'kng_cons_header_heading',
1312 [
1313 'label' => esc_html__('Header', 'king-addons'),
1314 'type' => Controls_Manager::HEADING,
1315 'separator' => 'before',
1316 ]
1317 );
1318
1319 $this->add_group_control(
1320 Group_Control_Background::get_type(),
1321 [
1322 'name' => 'kng_cons_header_background',
1323 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__section-header',
1324 ]
1325 );
1326
1327 $this->add_group_control(
1328 Group_Control_Border::get_type(),
1329 [
1330 'name' => 'kng_cons_header_border',
1331 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__section-header',
1332 ]
1333 );
1334
1335 $this->add_responsive_control(
1336 'kng_cons_header_radius',
1337 [
1338 'label' => esc_html__('Header Border Radius', 'king-addons'),
1339 'type' => Controls_Manager::SLIDER,
1340 'size_units' => ['px', '%'],
1341 'range' => [
1342 'px' => ['min' => 0, 'max' => 60],
1343 '%' => ['min' => 0, 'max' => 100],
1344 ],
1345 'selectors' => [
1346 '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__section-header' => 'border-radius: {{SIZE}}{{UNIT}};',
1347 ],
1348 ]
1349 );
1350
1351 $this->add_responsive_control(
1352 'kng_cons_header_padding',
1353 [
1354 'label' => esc_html__('Header Padding', 'king-addons'),
1355 'type' => Controls_Manager::DIMENSIONS,
1356 'size_units' => ['px', 'em'],
1357 'selectors' => [
1358 '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__section-header' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
1359 ],
1360 ]
1361 );
1362
1363 $this->add_group_control(
1364 Group_Control_Box_Shadow::get_type(),
1365 [
1366 'name' => 'kng_cons_header_shadow',
1367 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__section-header',
1368 ]
1369 );
1370
1371 $this->add_group_control(
1372 Group_Control_Background::get_type(),
1373 [
1374 'name' => 'kng_cons_section_background',
1375 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--cons',
1376 ]
1377 );
1378
1379 $this->add_group_control(
1380 Group_Control_Border::get_type(),
1381 [
1382 'name' => 'kng_cons_section_border',
1383 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--cons',
1384 ]
1385 );
1386
1387 $this->add_responsive_control(
1388 'kng_cons_section_radius',
1389 [
1390 'label' => esc_html__('Border Radius', 'king-addons'),
1391 'type' => Controls_Manager::SLIDER,
1392 'size_units' => ['px', '%'],
1393 'range' => [
1394 'px' => ['min' => 0, 'max' => 60],
1395 '%' => ['min' => 0, 'max' => 100],
1396 ],
1397 'selectors' => [
1398 '{{WRAPPER}} .king-addons-pros-cons__section--cons' => 'border-radius: {{SIZE}}{{UNIT}};',
1399 ],
1400 ]
1401 );
1402
1403 $this->add_group_control(
1404 Group_Control_Box_Shadow::get_type(),
1405 [
1406 'name' => 'kng_cons_section_shadow',
1407 'selector' => '{{WRAPPER}} .king-addons-pros-cons__section--cons',
1408 ]
1409 );
1410
1411 $this->add_control(
1412 'kng_cons_icon_color',
1413 [
1414 'label' => esc_html__('Item Icon Color', 'king-addons'),
1415 'type' => Controls_Manager::COLOR,
1416 'selectors' => [
1417 '{{WRAPPER}} .king-addons-pros-cons__section--cons .king-addons-pros-cons__item-icon' => 'color: {{VALUE}};',
1418 ],
1419 'condition' => [
1420 'kng_show_item_icons' => 'yes',
1421 ],
1422 ]
1423 );
1424
1425 $this->add_control(
1426 'kng_cons_highlight_background',
1427 [
1428 'label' => esc_html__('Highlight Background', 'king-addons'),
1429 'type' => Controls_Manager::COLOR,
1430 'selectors' => [
1431 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-cons-highlight: {{VALUE}};',
1432 ],
1433 ]
1434 );
1435
1436 $this->add_control(
1437 'kng_cons_accent_border_width',
1438 [
1439 'label' => esc_html__('Accent Border Width', 'king-addons'),
1440 'type' => Controls_Manager::SLIDER,
1441 'size_units' => ['px'],
1442 'range' => [
1443 'px' => ['min' => 0, 'max' => 10],
1444 ],
1445 'selectors' => [
1446 '{{WRAPPER}} .king-addons-pros-cons' => '--kng-cons-border-width: {{SIZE}}{{UNIT}};',
1447 ],
1448 ]
1449 );
1450
1451 $this->end_controls_section();
1452 }
1453
1454 /**
1455 * Pro notice section.
1456 */
1457 protected function register_pro_notice_controls(): void
1458 {
1459 if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
1460 Core::renderProFeaturesSection($this, '', Controls_Manager::RAW_HTML, 'pros-cons-box', [
1461 'Advanced presets and rating header',
1462 'Section-level collapse with memory',
1463 'Item tooltips and search-friendly output',
1464 'Review schema output and WooCommerce mapping',
1465 'Custom count formats and difference indicator',
1466 ]);
1467 }
1468 }
1469
1470 /**
1471 * Build section payload.
1472 *
1473 * @param string $type Section type.
1474 * @param array<string, mixed> $settings Settings.
1475 * @param array<int, array<string, mixed>> $items Items.
1476 * @param int $count Count.
1477 * @param bool $is_editor Editor state.
1478 *
1479 * @return array<string, mixed>
1480 */
1481 protected function build_section_payload(string $type, array $settings, array $items, int $count, bool $is_editor): array
1482 {
1483 $empty_state = $settings['kng_' . $type . '_empty_state'] ?? 'hide';
1484 $show = !empty($items) || $empty_state === 'placeholder';
1485 $is_placeholder = false;
1486
1487 if (!$show) {
1488 return [
1489 'show' => false,
1490 'items' => [],
1491 'count' => $count,
1492 'is_placeholder' => false,
1493 ];
1494 }
1495
1496 if (empty($items)) {
1497 $placeholder = trim((string) ($settings['kng_' . $type . '_empty_text'] ?? ''));
1498 if ($placeholder === '') {
1499 $placeholder = $type === 'pros'
1500 ? esc_html__('Add pros items to show this section.', 'king-addons')
1501 : esc_html__('Add cons items to show this section.', 'king-addons');
1502 }
1503
1504 $items = [
1505 [
1506 'text' => esc_html($placeholder),
1507 'icon' => [],
1508 'highlight' => false,
1509 'tooltip' => '',
1510 'id' => 'placeholder',
1511 ],
1512 ];
1513 $is_placeholder = true;
1514 }
1515
1516 return [
1517 'show' => true,
1518 'items' => $items,
1519 'count' => $count,
1520 'is_placeholder' => $is_placeholder,
1521 ];
1522 }
1523
1524 /**
1525 * Prepare repeater items.
1526 *
1527 * @param array<int, array<string, mixed>> $items Items.
1528 *
1529 * @return array<int, array<string, mixed>>
1530 */
1531 protected function prepare_items(array $items): array
1532 {
1533 $prepared = [];
1534 foreach ($items as $item) {
1535 $text = $this->sanitize_item_text((string) ($item['kng_item_text'] ?? ''));
1536 if ($text === '') {
1537 continue;
1538 }
1539
1540 $prepared[] = [
1541 'text' => $text,
1542 'icon' => $item['kng_item_icon'] ?? [],
1543 'highlight' => ($item['kng_item_highlight'] ?? '') === 'yes',
1544 'tooltip' => (string) ($item['kng_item_tooltip'] ?? ''),
1545 'id' => $item['_id'] ?? uniqid('kng', true),
1546 ];
1547 }
1548
1549 return array_slice($prepared, 0, 50);
1550 }
1551
1552 /**
1553 * Sanitize item text with minimal markup.
1554 *
1555 * @param string $text Text.
1556 * @return string
1557 */
1558 protected function sanitize_item_text(string $text): string
1559 {
1560 $allowed = [
1561 'strong' => [],
1562 'em' => [],
1563 'br' => [],
1564 ];
1565
1566 return wp_kses($text, $allowed);
1567 }
1568
1569 /**
1570 * Render header.
1571 *
1572 * @param array<string, mixed> $settings Settings.
1573 * @param array<string, mixed> $context Context.
1574 */
1575 protected function render_header(array $settings, array $context): void
1576 {
1577 $title = trim((string) ($settings['kng_main_title'] ?? ''));
1578 $description = trim((string) ($settings['kng_description'] ?? ''));
1579
1580 if ($title === '' && $description === '' && !$this->has_header_extra($settings, $context)) {
1581 return;
1582 }
1583 ?>
1584 <div class="king-addons-pros-cons__header">
1585 <?php if ($title !== '') : ?>
1586 <h3 class="king-addons-pros-cons__title"><?php echo esc_html($title); ?></h3>
1587 <?php endif; ?>
1588 <?php $this->render_header_extra($settings, $context); ?>
1589 <?php if ($description !== '') : ?>
1590 <div class="king-addons-pros-cons__description"><?php echo esc_html($description); ?></div>
1591 <?php endif; ?>
1592 </div>
1593 <?php
1594 }
1595
1596 /**
1597 * Render extra header elements (Pro).
1598 *
1599 * @param array<string, mixed> $settings Settings.
1600 * @param array<string, mixed> $context Context.
1601 */
1602 protected function render_header_extra(array $settings, array $context): void
1603 {
1604 // Reserved for Pro.
1605 }
1606
1607 /**
1608 * Check if extra header elements should render.
1609 *
1610 * @param array<string, mixed> $settings Settings.
1611 * @param array<string, mixed> $context Context.
1612 */
1613 protected function has_header_extra(array $settings, array $context): bool
1614 {
1615 return false;
1616 }
1617
1618 /**
1619 * Render section.
1620 *
1621 * @param string $type Section type.
1622 * @param array<string, mixed> $settings Settings.
1623 * @param array<string, mixed> $payload Payload.
1624 */
1625 protected function render_section(string $type, array $settings, array $payload): void
1626 {
1627 $title = trim((string) ($settings['kng_' . $type . '_title'] ?? ''));
1628 $subtitle = trim((string) ($settings['kng_' . $type . '_subtitle'] ?? ''));
1629 $title_icon = $settings['kng_' . $type . '_title_icon'] ?? [];
1630 $list_id = $this->get_section_list_id($type);
1631 $toggle_html = $this->render_section_toggle($type, $settings, $list_id);
1632 $section_title = $this->format_section_title($type, $title, (int) $payload['count'], $settings);
1633
1634 $section_classes = [
1635 'king-addons-pros-cons__section',
1636 'king-addons-pros-cons__section--' . $type,
1637 ];
1638
1639 if ($payload['is_placeholder']) {
1640 $section_classes[] = 'is-placeholder';
1641 }
1642
1643 if ($this->is_section_collapsible($type, $settings)) {
1644 $section_classes[] = 'is-collapsible';
1645 }
1646
1647 ?>
1648 <section class="<?php echo esc_attr(implode(' ', $section_classes)); ?>" data-section="<?php echo esc_attr($type); ?>"<?php echo $this->get_section_data_attributes($type, $settings); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
1649 <div class="king-addons-pros-cons__section-header">
1650 <div class="king-addons-pros-cons__section-heading">
1651 <?php if (!empty($title_icon['value'])) : ?>
1652 <span class="king-addons-pros-cons__section-title-icon" aria-hidden="true">
1653 <?php Icons_Manager::render_icon($title_icon, ['aria-hidden' => 'true']); ?>
1654 </span>
1655 <?php endif; ?>
1656 <?php if ($section_title !== '') : ?>
1657 <h4 class="king-addons-pros-cons__section-title"><?php echo esc_html($section_title); ?></h4>
1658 <?php endif; ?>
1659 </div>
1660 <?php if ($toggle_html !== '') : ?>
1661 <?php echo $toggle_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1662 <?php endif; ?>
1663 </div>
1664 <?php if ($subtitle !== '') : ?>
1665 <div class="king-addons-pros-cons__section-subtitle"><?php echo esc_html($subtitle); ?></div>
1666 <?php endif; ?>
1667 <ul id="<?php echo esc_attr($list_id); ?>" class="king-addons-pros-cons__list" aria-hidden="false">
1668 <?php foreach ($payload['items'] as $item) : ?>
1669 <?php $this->render_item($type, $settings, $item); ?>
1670 <?php endforeach; ?>
1671 </ul>
1672 </section>
1673 <?php
1674 }
1675
1676 /**
1677 * Render item.
1678 *
1679 * @param string $type Section type.
1680 * @param array<string, mixed> $settings Settings.
1681 * @param array<string, mixed> $item Item.
1682 */
1683 protected function render_item(string $type, array $settings, array $item): void
1684 {
1685 $show_icons = ($settings['kng_show_item_icons'] ?? 'yes') === 'yes';
1686 $default_icon = $settings['kng_' . $type . '_item_icon'] ?? [];
1687 $icon = !empty($item['icon']['value']) ? $item['icon'] : $default_icon;
1688 $tooltip = trim((string) ($item['tooltip'] ?? ''));
1689 $tooltip_html = $this->render_item_tooltip($tooltip, (string) ($item['id'] ?? ''));
1690
1691 $item_classes = ['king-addons-pros-cons__item'];
1692 if (!empty($item['highlight'])) {
1693 $item_classes[] = 'is-highlight';
1694 }
1695 if ($tooltip_html !== '') {
1696 $item_classes[] = 'has-tooltip';
1697 }
1698 ?>
1699 <li class="<?php echo esc_attr(implode(' ', $item_classes)); ?>">
1700 <?php if ($show_icons && !empty($icon['value'])) : ?>
1701 <span class="king-addons-pros-cons__item-icon" aria-hidden="true">
1702 <?php Icons_Manager::render_icon($icon, ['aria-hidden' => 'true']); ?>
1703 </span>
1704 <?php endif; ?>
1705 <span class="king-addons-pros-cons__item-text"><?php echo $item['text']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
1706 <?php if ($tooltip_html !== '') : ?>
1707 <?php echo $tooltip_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
1708 <?php endif; ?>
1709 </li>
1710 <?php
1711 }
1712
1713 /**
1714 * Render item tooltip (Pro).
1715 *
1716 * @param string $tooltip Tooltip text.
1717 * @param string $id Item id.
1718 * @return string
1719 */
1720 protected function render_item_tooltip(string $tooltip, string $id): string
1721 {
1722 if ($tooltip === '' || !($this->is_tooltip_enabled())) {
1723 return '';
1724 }
1725
1726 $tooltip_id = 'kng-pros-cons-tooltip-' . $this->get_id() . '-' . sanitize_key($id);
1727 $tooltip_text = esc_html($tooltip);
1728
1729 return sprintf(
1730 '<button type="button" class="king-addons-pros-cons__tooltip-trigger" aria-describedby="%1$s" aria-label="%2$s">i</button><span id="%1$s" class="king-addons-pros-cons__tooltip king-addons-pros-cons__tooltip--%3$s" role="tooltip">%4$s</span>',
1731 esc_attr($tooltip_id),
1732 esc_attr__('More info', 'king-addons'),
1733 esc_attr($this->get_tooltip_position()),
1734 $tooltip_text
1735 );
1736 }
1737
1738 /**
1739 * Tooltip enabled flag (Pro).
1740 */
1741 protected function is_tooltip_enabled(): bool
1742 {
1743 return false;
1744 }
1745
1746 /**
1747 * Tooltip position (Pro).
1748 */
1749 protected function get_tooltip_position(): string
1750 {
1751 return 'top';
1752 }
1753
1754 /**
1755 * Render section toggle (Pro).
1756 *
1757 * @param string $type Section type.
1758 * @param array<string, mixed> $settings Settings.
1759 * @param string $list_id List id.
1760 * @return string
1761 */
1762 protected function render_section_toggle(string $type, array $settings, string $list_id): string
1763 {
1764 if (!$this->is_section_collapsible($type, $settings)) {
1765 return '';
1766 }
1767
1768 $label = $type === 'pros'
1769 ? esc_html__('Toggle pros', 'king-addons')
1770 : esc_html__('Toggle cons', 'king-addons');
1771
1772 return sprintf(
1773 '<button type="button" class="king-addons-pros-cons__toggle" aria-expanded="true" aria-controls="%1$s" aria-label="%2$s"><span class="king-addons-pros-cons__toggle-icon" aria-hidden="true"></span></button>',
1774 esc_attr($list_id),
1775 esc_attr($label)
1776 );
1777 }
1778
1779 /**
1780 * Check if section is collapsible (Pro).
1781 *
1782 * @param string $type Section type.
1783 * @param array<string, mixed> $settings Settings.
1784 * @return bool
1785 */
1786 protected function is_section_collapsible(string $type, array $settings): bool
1787 {
1788 return false;
1789 }
1790
1791 /**
1792 * Section data attributes (Pro).
1793 *
1794 * @param string $type Section type.
1795 * @param array<string, mixed> $settings Settings.
1796 * @return string
1797 */
1798 protected function get_section_data_attributes(string $type, array $settings): string
1799 {
1800 return '';
1801 }
1802
1803 /**
1804 * Format section title with count.
1805 *
1806 * @param string $type Section type.
1807 * @param string $title Title.
1808 * @param int $count Count.
1809 * @param array<string, mixed> $settings Settings.
1810 * @return string
1811 */
1812 protected function format_section_title(string $type, string $title, int $count, array $settings): string
1813 {
1814 $show_count = ($settings['kng_show_count'] ?? '') === 'yes';
1815 if (!$show_count) {
1816 return $title;
1817 }
1818
1819 return sprintf('%s (%d)', $title, $count);
1820 }
1821
1822 /**
1823 * Generate section list id.
1824 *
1825 * @param string $type Section type.
1826 * @return string
1827 */
1828 protected function get_section_list_id(string $type): string
1829 {
1830 return 'kng-pros-cons-' . $this->get_id() . '-' . $type . '-list';
1831 }
1832
1833 /**
1834 * Wrapper classes.
1835 *
1836 * @param array<string, mixed> $settings Settings.
1837 * @param array<string, mixed> $context Context.
1838 * @return array<int, string>
1839 */
1840 protected function get_wrapper_classes(array $settings, array $context): array
1841 {
1842 $layout = $settings['kng_layout'] ?? 'side';
1843 $preset = $this->get_preset($settings);
1844 $icon_position = $settings['kng_item_icon_position'] ?? 'left';
1845 $show_icons = ($settings['kng_show_item_icons'] ?? 'yes') === 'yes';
1846 $stack_mobile = ($settings['kng_stack_on_mobile'] ?? 'yes') === 'yes';
1847
1848 $classes = [
1849 'king-addons-pros-cons',
1850 'king-addons-pros-cons--layout-' . sanitize_html_class((string) $layout),
1851 'king-addons-pros-cons--preset-' . sanitize_html_class($preset),
1852 'king-addons-pros-cons--icon-' . sanitize_html_class((string) $icon_position),
1853 ];
1854
1855 if ($stack_mobile) {
1856 $classes[] = 'king-addons-pros-cons--stacked-mobile';
1857 }
1858
1859 if (!$show_icons) {
1860 $classes[] = 'king-addons-pros-cons--no-icons';
1861 }
1862
1863 if (!($context['show_pros'] ?? false) || !($context['show_cons'] ?? false)) {
1864 $classes[] = 'king-addons-pros-cons--single';
1865 }
1866
1867 return array_filter($classes);
1868 }
1869
1870 /**
1871 * Build data attributes for the wrapper.
1872 *
1873 * @param array<string, mixed> $settings Settings.
1874 * @return string
1875 */
1876 protected function get_data_attributes(array $settings): string
1877 {
1878 $attributes = [
1879 'data-widget-id' => $this->get_id(),
1880 'data-tooltip' => $this->is_tooltip_enabled() ? 'yes' : 'no',
1881 ];
1882
1883 $output = [];
1884 foreach ($attributes as $key => $value) {
1885 $output[] = esc_attr($key) . '="' . esc_attr((string) $value) . '"';
1886 }
1887
1888 return ' ' . implode(' ', $output);
1889 }
1890
1891 /**
1892 * Preset options.
1893 *
1894 * @return array<string, string>
1895 */
1896 protected function get_preset_options(): array
1897 {
1898 return [
1899 'clean' => esc_html__('Clean', 'king-addons'),
1900 'card' => esc_html__('Card', 'king-addons'),
1901 ];
1902 }
1903
1904 /**
1905 * Sanitize preset.
1906 *
1907 * @param array<string, mixed> $settings Settings.
1908 * @return string
1909 */
1910 protected function get_preset(array $settings): string
1911 {
1912 $preset = $settings['kng_preset'] ?? 'clean';
1913 $options = $this->get_preset_options();
1914
1915 if (!isset($options[$preset])) {
1916 return 'clean';
1917 }
1918
1919 return (string) $preset;
1920 }
1921
1922 /**
1923 * Render schema output (Pro).
1924 *
1925 * @param array<string, mixed> $settings Settings.
1926 * @param array<string, mixed> $context Context.
1927 */
1928 protected function render_schema(array $settings, array $context): void
1929 {
1930 // Reserved for Pro.
1931 }
1932 }
1933