PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.65
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.65
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.65, at includes/widgets/Pros_Cons_Box/Pros_Cons_Box.php

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