PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.82
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.82
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 / Compare_Table / Compare_Table.php

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

1,154 lines 36.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Compare Products Table Widget (Free).
4 *
5 * @package King_Addons
6 */
7
8 namespace King_Addons;
9
10 use Elementor\Controls_Manager;
11 use Elementor\Group_Control_Border;
12 use Elementor\Group_Control_Box_Shadow;
13 use Elementor\Group_Control_Typography;
14 use Elementor\Widget_Base;
15 use WC_Product;
16 use WP_Query;
17
18 if (!defined('ABSPATH')) {
19 exit;
20 }
21
22 /**
23 * Renders a WooCommerce products compare table.
24 */
25 class Compare_Table extends Widget_Base
26 {
27 /**
28 * Widget slug.
29 *
30 * @return string
31 */
32 public function get_name(): string
33 {
34 return 'king-addons-compare-table';
35 }
36
37 /**
38 * Widget title.
39 *
40 * @return string
41 */
42 public function get_title(): string
43 {
44 return esc_html__('Compare Products Table', 'king-addons');
45 }
46
47 /**
48 * Widget icon.
49 *
50 * @return string
51 */
52 public function get_icon(): string
53 {
54 return 'king-addons-icon king-addons-compare-table';
55 }
56
57 /**
58 * Style dependencies.
59 *
60 * @return array<int, string>
61 */
62 public function get_style_depends(): array
63 {
64 return [
65 KING_ADDONS_ASSETS_UNIQUE_KEY . '-compare-table-style',
66 ];
67 }
68
69 /**
70 * Script dependencies.
71 *
72 * @return array<int, string>
73 */
74 public function get_script_depends(): array
75 {
76 $deps = [
77 KING_ADDONS_ASSETS_UNIQUE_KEY . '-compare-table-script',
78 ];
79
80 if (class_exists('\WooCommerce') && function_exists('wp_script_is') && wp_script_is('wc-add-to-cart', 'registered')) {
81 $deps[] = 'wc-add-to-cart';
82 }
83
84 return $deps;
85 }
86
87 /**
88 * Categories.
89 *
90 * @return array<int, string>
91 */
92 public function get_categories(): array
93 {
94 return ['king-addons-woo'];
95 }
96
97 /**
98 * Keywords.
99 *
100 * @return array<int, string>
101 */
102 public function get_keywords(): array
103 {
104 return ['woocommerce', 'compare', 'table', 'product'];
105 }
106
107 public function get_custom_help_url()
108 {
109 return 'mailto:bug@kingaddons.com?subject=Bug Report - King Addons&body=Please describe the issue';
110 }
111
112 /**
113 * Register controls.
114 *
115 * @return void
116 */
117 public function register_controls(): void
118 {
119 $this->register_query_controls();
120 $this->register_display_controls();
121 $this->register_layout_controls();
122 $this->register_style_header_controls();
123 $this->register_style_cell_controls();
124 $this->register_style_button_controls();
125 $this->register_style_view_cart_controls();
126 $this->register_pro_controls();
127 $this->register_pro_notice_controls();
128 }
129
130 /**
131 * Register Pro-only controls placeholder.
132 *
133 * The Pro version overrides this method to add premium controls without
134 * overriding the full `register_controls()` flow.
135 *
136 * @return void
137 */
138 public function register_pro_controls(): void
139 {
140 // Intentionally empty in Free.
141 }
142
143 /**
144 * Render widget output.
145 *
146 * @return void
147 */
148 public function render(): void
149 {
150 if (!class_exists('\WooCommerce')) {
151 Core::renderEditorHint(esc_html__('Compare Table needs WooCommerce to be active.', 'king-addons'));
152 return;
153 }
154
155 $settings = $this->get_settings_for_display();
156 $products = $this->get_products($settings);
157
158 if (empty($products)) {
159 Core::renderEditorHint(esc_html__('Choose products (or a category) in the Content tab to build the comparison.', 'king-addons'));
160 return;
161 }
162
163 $rows = $this->get_rows_config($settings);
164 $wrapper_attrs = $this->get_wrapper_attributes($settings);
165
166 ?>
167 <div class="king-addons-compare-table" <?php echo $wrapper_attrs; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
168 <div class="king-addons-compare-table__scroll">
169 <table class="king-addons-compare-table__table">
170 <thead class="king-addons-compare-table__head">
171 <tr class="king-addons-compare-table__row king-addons-compare-table__row--head">
172 <th class="king-addons-compare-table__cell king-addons-compare-table__cell--label">
173 <?php echo esc_html__('Feature', 'king-addons'); ?>
174 </th>
175 <?php foreach ($products as $product) : ?>
176 <th class="king-addons-compare-table__cell king-addons-compare-table__cell--product">
177 <div class="king-addons-compare-table__product-head">
178 <div class="king-addons-compare-table__product-thumb">
179 <a href="<?php echo esc_url(get_permalink($product->get_id())); ?>">
180 <?php echo $product->get_image('thumbnail'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
181 </a>
182 </div>
183 <div class="king-addons-compare-table__product-title">
184 <a href="<?php echo esc_url(get_permalink($product->get_id())); ?>">
185 <?php echo esc_html($product->get_name()); ?>
186 </a>
187 </div>
188 </div>
189 </th>
190 <?php endforeach; ?>
191 </tr>
192 </thead>
193 <tbody class="king-addons-compare-table__body">
194 <?php foreach ($rows as $row_id => $row_label) : ?>
195 <tr class="king-addons-compare-table__row" data-row-id="<?php echo esc_attr($row_id); ?>">
196 <th class="king-addons-compare-table__cell king-addons-compare-table__cell--label">
197 <?php echo esc_html($row_label); ?>
198 </th>
199 <?php foreach ($products as $product) : ?>
200 <td class="king-addons-compare-table__cell king-addons-compare-table__cell--value">
201 <?php echo $this->get_cell_content($row_id, $product, $settings); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
202 </td>
203 <?php endforeach; ?>
204 </tr>
205 <?php endforeach; ?>
206 </tbody>
207 </table>
208 </div>
209 </div>
210 <?php
211 }
212
213 /**
214 * Query controls.
215 *
216 * @return void
217 */
218 protected function register_query_controls(): void
219 {
220 $this->start_controls_section(
221 'kng_query_section',
222 [
223 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Products', 'king-addons'),
224 'tab' => Controls_Manager::TAB_CONTENT,
225 ]
226 );
227
228 $this->add_control(
229 'kng_product_ids',
230 [
231 'label' => esc_html__('Product IDs', 'king-addons'),
232 'type' => Controls_Manager::TEXT,
233 'placeholder' => esc_html__('12, 34, 56', 'king-addons'),
234 'description' => esc_html__('Comma-separated product IDs to compare.', 'king-addons'),
235 ]
236 );
237
238 $this->add_control(
239 'kng_products_limit',
240 [
241 'label' => esc_html__('Max Products', 'king-addons'),
242 'type' => Controls_Manager::NUMBER,
243 'min' => 2,
244 'max' => 4,
245 'step' => 1,
246 'default' => 3,
247 'description' => esc_html__('Free version limited to 4 products.', 'king-addons'),
248 ]
249 );
250
251 $this->add_control(
252 'kng_categories',
253 [
254 'label' => sprintf(__('Categories %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
255 'type' => Controls_Manager::TEXT,
256 'description' => esc_html__('Comma-separated slugs (Pro).', 'king-addons'),
257 'classes' => 'king-addons-pro-control no-distance',
258 ]
259 );
260
261 $this->end_controls_section();
262 }
263
264 /**
265 * Display toggles.
266 *
267 * @return void
268 */
269 protected function register_display_controls(): void
270 {
271 $this->start_controls_section(
272 'kng_display_section',
273 [
274 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Display', 'king-addons'),
275 'tab' => Controls_Manager::TAB_CONTENT,
276 ]
277 );
278
279 $this->add_control(
280 'kng_show_image',
281 [
282 'label' => esc_html__('Show Image', 'king-addons'),
283 'type' => Controls_Manager::SWITCHER,
284 'return_value' => 'yes',
285 'default' => 'yes',
286 ]
287 );
288
289 $this->add_control(
290 'kng_show_price',
291 [
292 'label' => esc_html__('Show Price', 'king-addons'),
293 'type' => Controls_Manager::SWITCHER,
294 'return_value' => 'yes',
295 'default' => 'yes',
296 ]
297 );
298
299 $this->add_control(
300 'kng_show_rating',
301 [
302 'label' => esc_html__('Show Rating', 'king-addons'),
303 'type' => Controls_Manager::SWITCHER,
304 'return_value' => 'yes',
305 'default' => 'yes',
306 ]
307 );
308
309 $this->add_control(
310 'kng_show_excerpt',
311 [
312 'label' => esc_html__('Show Short Description', 'king-addons'),
313 'type' => Controls_Manager::SWITCHER,
314 'return_value' => 'yes',
315 'default' => 'yes',
316 ]
317 );
318
319 $this->add_control(
320 'kng_show_sku',
321 [
322 'label' => esc_html__('Show SKU', 'king-addons'),
323 'type' => Controls_Manager::SWITCHER,
324 'return_value' => 'yes',
325 'default' => 'yes',
326 ]
327 );
328
329 $this->add_control(
330 'kng_show_stock',
331 [
332 'label' => esc_html__('Show Stock', 'king-addons'),
333 'type' => Controls_Manager::SWITCHER,
334 'return_value' => 'yes',
335 'default' => 'yes',
336 ]
337 );
338
339 $this->add_control(
340 'kng_show_add_to_cart',
341 [
342 'label' => esc_html__('Show Add to Cart', 'king-addons'),
343 'type' => Controls_Manager::SWITCHER,
344 'return_value' => 'yes',
345 'default' => 'yes',
346 ]
347 );
348
349 $this->add_control(
350 'kng_hide_equal_rows',
351 [
352 'label' => sprintf(__('Hide Identical Rows %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
353 'type' => Controls_Manager::SWITCHER,
354 'return_value' => 'yes',
355 'default' => '',
356 'classes' => 'king-addons-pro-control no-distance',
357 ]
358 );
359
360 $this->end_controls_section();
361 }
362
363 /**
364 * Layout controls.
365 *
366 * @return void
367 */
368 protected function register_layout_controls(): void
369 {
370 $this->start_controls_section(
371 'kng_layout_section',
372 [
373 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Layout', 'king-addons'),
374 'tab' => Controls_Manager::TAB_CONTENT,
375 ]
376 );
377
378 $this->add_control(
379 'kng_cell_alignment',
380 [
381 'label' => esc_html__('Cell Alignment', 'king-addons'),
382 'type' => Controls_Manager::CHOOSE,
383 'options' => [
384 'left' => [
385 'title' => esc_html__('Left', 'king-addons'),
386 'icon' => 'eicon-text-align-left',
387 ],
388 'center' => [
389 'title' => esc_html__('Center', 'king-addons'),
390 'icon' => 'eicon-text-align-center',
391 ],
392 'right' => [
393 'title' => esc_html__('Right', 'king-addons'),
394 'icon' => 'eicon-text-align-right',
395 ],
396 ],
397 'default' => 'left',
398 'selectors' => [
399 '{{WRAPPER}} .king-addons-compare-table__cell' => 'text-align: {{VALUE}};',
400 ],
401 ]
402 );
403
404 $this->add_responsive_control(
405 'kng_cell_padding',
406 [
407 'label' => esc_html__('Cell Padding', 'king-addons'),
408 'type' => Controls_Manager::DIMENSIONS,
409 'size_units' => ['px', 'em'],
410 'selectors' => [
411 '{{WRAPPER}} .king-addons-compare-table__cell' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
412 ],
413 ]
414 );
415
416 $this->end_controls_section();
417 }
418
419 /**
420 * Header styles.
421 *
422 * @return void
423 */
424 protected function register_style_header_controls(): void
425 {
426 $this->start_controls_section(
427 'kng_style_header_section',
428 [
429 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Header', 'king-addons'),
430 'tab' => Controls_Manager::TAB_STYLE,
431 ]
432 );
433
434 $this->add_group_control(
435 Group_Control_Typography::get_type(),
436 [
437 'name' => 'kng_header_typography',
438 'selector' => '{{WRAPPER}} .king-addons-compare-table__head .king-addons-compare-table__cell',
439 ]
440 );
441
442 $this->add_control(
443 'kng_header_color',
444 [
445 'label' => esc_html__('Text Color', 'king-addons'),
446 'type' => Controls_Manager::COLOR,
447 'selectors' => [
448 '{{WRAPPER}} .king-addons-compare-table__head .king-addons-compare-table__cell' => 'color: {{VALUE}};',
449 ],
450 ]
451 );
452
453 $this->add_control(
454 'kng_header_bg',
455 [
456 'label' => esc_html__('Background', 'king-addons'),
457 'type' => Controls_Manager::COLOR,
458 'selectors' => [
459 '{{WRAPPER}} .king-addons-compare-table__head .king-addons-compare-table__row' => 'background-color: {{VALUE}};',
460 ],
461 ]
462 );
463
464 $this->add_group_control(
465 Group_Control_Border::get_type(),
466 [
467 'name' => 'kng_header_border',
468 'selector' => '{{WRAPPER}} .king-addons-compare-table__head .king-addons-compare-table__cell',
469 ]
470 );
471
472 $this->add_control(
473 'kng_header_radius',
474 [
475 'label' => esc_html__('Border Radius', 'king-addons'),
476 'type' => Controls_Manager::SLIDER,
477 'size_units' => ['px', '%'],
478 'range' => [
479 'px' => ['min' => 0, 'max' => 40],
480 '%' => ['min' => 0, 'max' => 100],
481 ],
482 'selectors' => [
483 '{{WRAPPER}} .king-addons-compare-table__row--head .king-addons-compare-table__cell' => 'border-radius: {{SIZE}}{{UNIT}};',
484 ],
485 ]
486 );
487
488 $this->add_group_control(
489 Group_Control_Box_Shadow::get_type(),
490 [
491 'name' => 'kng_header_shadow',
492 'selector' => '{{WRAPPER}} .king-addons-compare-table__head',
493 ]
494 );
495
496 $this->end_controls_section();
497 }
498
499 /**
500 * Cell styles.
501 *
502 * @return void
503 */
504 protected function register_style_cell_controls(): void
505 {
506 $this->start_controls_section(
507 'kng_style_cell_section',
508 [
509 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Body', 'king-addons'),
510 'tab' => Controls_Manager::TAB_STYLE,
511 ]
512 );
513
514 $this->add_group_control(
515 Group_Control_Typography::get_type(),
516 [
517 'name' => 'kng_body_typography',
518 'selector' => '{{WRAPPER}} .king-addons-compare-table__body .king-addons-compare-table__cell',
519 ]
520 );
521
522 $this->add_control(
523 'kng_body_color',
524 [
525 'label' => esc_html__('Text Color', 'king-addons'),
526 'type' => Controls_Manager::COLOR,
527 'selectors' => [
528 '{{WRAPPER}} .king-addons-compare-table__body .king-addons-compare-table__cell' => 'color: {{VALUE}};',
529 ],
530 ]
531 );
532
533 $this->add_control(
534 'kng_body_bg',
535 [
536 'label' => esc_html__('Background', 'king-addons'),
537 'type' => Controls_Manager::COLOR,
538 'selectors' => [
539 '{{WRAPPER}} .king-addons-compare-table__body .king-addons-compare-table__row' => 'background-color: {{VALUE}};',
540 ],
541 ]
542 );
543
544 $this->add_control(
545 'kng_body_stripe_bg',
546 [
547 'label' => esc_html__('Stripe Background', 'king-addons'),
548 'type' => Controls_Manager::COLOR,
549 'selectors' => [
550 '{{WRAPPER}} .king-addons-compare-table__row:nth-child(2n) .king-addons-compare-table__cell' => 'background-color: {{VALUE}};',
551 ],
552 ]
553 );
554
555 $this->add_group_control(
556 Group_Control_Border::get_type(),
557 [
558 'name' => 'kng_body_border',
559 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell',
560 ]
561 );
562
563 $this->add_control(
564 'kng_body_radius',
565 [
566 'label' => esc_html__('Cell Border Radius', 'king-addons'),
567 'type' => Controls_Manager::SLIDER,
568 'size_units' => ['px', '%'],
569 'range' => [
570 'px' => ['min' => 0, 'max' => 30],
571 '%' => ['min' => 0, 'max' => 100],
572 ],
573 'selectors' => [
574 '{{WRAPPER}} .king-addons-compare-table__cell' => 'border-radius: {{SIZE}}{{UNIT}};',
575 ],
576 ]
577 );
578
579 $this->end_controls_section();
580 }
581
582 /**
583 * Button styles.
584 *
585 * @return void
586 */
587 protected function register_style_button_controls(): void
588 {
589 $this->start_controls_section(
590 'kng_style_button_section',
591 [
592 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Add to Cart', 'king-addons'),
593 'tab' => Controls_Manager::TAB_STYLE,
594 ]
595 );
596
597 $this->add_group_control(
598 Group_Control_Typography::get_type(),
599 [
600 'name' => 'kng_button_typography',
601 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell .button',
602 ]
603 );
604
605 $this->add_responsive_control(
606 'kng_button_padding',
607 [
608 'label' => esc_html__('Padding', 'king-addons'),
609 'type' => Controls_Manager::DIMENSIONS,
610 'size_units' => ['px', 'em'],
611 'selectors' => [
612 '{{WRAPPER}} .king-addons-compare-table__cell .button' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
613 ],
614 ]
615 );
616
617 $this->add_responsive_control(
618 'kng_button_indicator_size',
619 [
620 'label' => esc_html__('Indicator Size', 'king-addons'),
621 'type' => Controls_Manager::SLIDER,
622 'size_units' => ['px'],
623 'range' => [
624 'px' => ['min' => 8, 'max' => 40],
625 ],
626 'selectors' => [
627 '{{WRAPPER}} .king-addons-compare-table__cell .king-addons-compare-table__add-to-cart' => '--king-addons-atc-indicator-size: {{SIZE}}{{UNIT}};',
628 ],
629 ]
630 );
631
632 $this->start_controls_tabs('kng_button_style_tabs');
633
634 $this->start_controls_tab(
635 'kng_button_style_tab_normal',
636 [
637 'label' => esc_html__('Normal', 'king-addons'),
638 ]
639 );
640
641 $this->add_control(
642 'kng_button_color',
643 [
644 'label' => esc_html__('Text Color', 'king-addons'),
645 'type' => Controls_Manager::COLOR,
646 'selectors' => [
647 '{{WRAPPER}} .king-addons-compare-table__cell .button' => 'color: {{VALUE}};',
648 ],
649 ]
650 );
651
652 $this->add_control(
653 'kng_button_bg',
654 [
655 'label' => esc_html__('Background', 'king-addons'),
656 'type' => Controls_Manager::COLOR,
657 'selectors' => [
658 '{{WRAPPER}} .king-addons-compare-table__cell .button' => 'background-color: {{VALUE}};',
659 ],
660 ]
661 );
662
663 $this->add_group_control(
664 Group_Control_Border::get_type(),
665 [
666 'name' => 'kng_button_border',
667 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell .button',
668 ]
669 );
670
671 $this->add_group_control(
672 Group_Control_Box_Shadow::get_type(),
673 [
674 'name' => 'kng_button_shadow',
675 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell .button',
676 ]
677 );
678
679 $this->end_controls_tab();
680
681 $this->start_controls_tab(
682 'kng_button_style_tab_hover',
683 [
684 'label' => esc_html__('Hover', 'king-addons'),
685 ]
686 );
687
688 $this->add_control(
689 'kng_button_color_hover',
690 [
691 'label' => esc_html__('Hover Text Color', 'king-addons'),
692 'type' => Controls_Manager::COLOR,
693 'selectors' => [
694 '{{WRAPPER}} .king-addons-compare-table__cell .button:hover' => 'color: {{VALUE}};',
695 ],
696 ]
697 );
698
699 $this->add_control(
700 'kng_button_bg_hover',
701 [
702 'label' => esc_html__('Hover Background', 'king-addons'),
703 'type' => Controls_Manager::COLOR,
704 'selectors' => [
705 '{{WRAPPER}} .king-addons-compare-table__cell .button:hover' => 'background-color: {{VALUE}};',
706 ],
707 ]
708 );
709
710 $this->add_group_control(
711 Group_Control_Border::get_type(),
712 [
713 'name' => 'kng_button_border_hover',
714 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell .button:hover',
715 ]
716 );
717
718 $this->add_group_control(
719 Group_Control_Box_Shadow::get_type(),
720 [
721 'name' => 'kng_button_shadow_hover',
722 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell .button:hover',
723 ]
724 );
725
726 $this->end_controls_tab();
727
728 $this->end_controls_tabs();
729
730 $this->add_control(
731 'kng_button_radius',
732 [
733 'label' => esc_html__('Border Radius', 'king-addons'),
734 'type' => Controls_Manager::SLIDER,
735 'size_units' => ['px', '%'],
736 'range' => [
737 'px' => ['min' => 0, 'max' => 40],
738 '%' => ['min' => 0, 'max' => 100],
739 ],
740 'selectors' => [
741 '{{WRAPPER}} .king-addons-compare-table__cell .button' => 'border-radius: {{SIZE}}{{UNIT}};',
742 ],
743 ]
744 );
745
746 $this->end_controls_section();
747 }
748
749 /**
750 * View cart link styles (WooCommerce injects `.added_to_cart` link after AJAX add to cart).
751 *
752 * @return void
753 */
754 protected function register_style_view_cart_controls(): void
755 {
756 $this->start_controls_section(
757 'kng_style_view_cart_section',
758 [
759 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('View Cart Link', 'king-addons'),
760 'tab' => Controls_Manager::TAB_STYLE,
761 ]
762 );
763
764 $this->add_responsive_control(
765 'kng_view_cart_gap',
766 [
767 'label' => esc_html__('Spacing From Button', 'king-addons'),
768 'type' => Controls_Manager::SLIDER,
769 'size_units' => ['px'],
770 'range' => [
771 'px' => ['min' => 0, 'max' => 60],
772 ],
773 'selectors' => [
774 '{{WRAPPER}} .king-addons-compare-table__cell .king-addons-compare-table__add-to-cart + .added_to_cart' => 'margin-left: {{SIZE}}{{UNIT}};',
775 ],
776 ]
777 );
778
779 $this->add_group_control(
780 Group_Control_Typography::get_type(),
781 [
782 'name' => 'kng_view_cart_typography',
783 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart',
784 ]
785 );
786
787 $this->add_responsive_control(
788 'kng_view_cart_padding',
789 [
790 'label' => esc_html__('Padding', 'king-addons'),
791 'type' => Controls_Manager::DIMENSIONS,
792 'size_units' => ['px', 'em'],
793 'selectors' => [
794 '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
795 ],
796 ]
797 );
798
799 $this->start_controls_tabs('kng_view_cart_style_tabs');
800
801 $this->start_controls_tab(
802 'kng_view_cart_style_tab_normal',
803 [
804 'label' => esc_html__('Normal', 'king-addons'),
805 ]
806 );
807
808 $this->add_control(
809 'kng_view_cart_color',
810 [
811 'label' => esc_html__('Text Color', 'king-addons'),
812 'type' => Controls_Manager::COLOR,
813 'selectors' => [
814 '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart' => 'color: {{VALUE}};',
815 ],
816 ]
817 );
818
819 $this->add_control(
820 'kng_view_cart_bg',
821 [
822 'label' => esc_html__('Background', 'king-addons'),
823 'type' => Controls_Manager::COLOR,
824 'selectors' => [
825 '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart' => 'background-color: {{VALUE}};',
826 ],
827 ]
828 );
829
830 $this->add_group_control(
831 Group_Control_Border::get_type(),
832 [
833 'name' => 'kng_view_cart_border',
834 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart',
835 ]
836 );
837
838 $this->add_group_control(
839 Group_Control_Box_Shadow::get_type(),
840 [
841 'name' => 'kng_view_cart_shadow',
842 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart',
843 ]
844 );
845
846 $this->end_controls_tab();
847
848 $this->start_controls_tab(
849 'kng_view_cart_style_tab_hover',
850 [
851 'label' => esc_html__('Hover', 'king-addons'),
852 ]
853 );
854
855 $this->add_control(
856 'kng_view_cart_color_hover',
857 [
858 'label' => esc_html__('Hover Text Color', 'king-addons'),
859 'type' => Controls_Manager::COLOR,
860 'selectors' => [
861 '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart:hover' => 'color: {{VALUE}};',
862 ],
863 ]
864 );
865
866 $this->add_control(
867 'kng_view_cart_bg_hover',
868 [
869 'label' => esc_html__('Hover Background', 'king-addons'),
870 'type' => Controls_Manager::COLOR,
871 'selectors' => [
872 '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart:hover' => 'background-color: {{VALUE}};',
873 ],
874 ]
875 );
876
877 $this->add_group_control(
878 Group_Control_Border::get_type(),
879 [
880 'name' => 'kng_view_cart_border_hover',
881 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart:hover',
882 ]
883 );
884
885 $this->add_group_control(
886 Group_Control_Box_Shadow::get_type(),
887 [
888 'name' => 'kng_view_cart_shadow_hover',
889 'selector' => '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart:hover',
890 ]
891 );
892
893 $this->end_controls_tab();
894
895 $this->end_controls_tabs();
896
897 $this->add_control(
898 'kng_view_cart_radius',
899 [
900 'label' => esc_html__('Border Radius', 'king-addons'),
901 'type' => Controls_Manager::SLIDER,
902 'size_units' => ['px', '%'],
903 'range' => [
904 'px' => ['min' => 0, 'max' => 40],
905 '%' => ['min' => 0, 'max' => 100],
906 ],
907 'selectors' => [
908 '{{WRAPPER}} .king-addons-compare-table__cell .added_to_cart' => 'border-radius: {{SIZE}}{{UNIT}};',
909 ],
910 ]
911 );
912
913 $this->end_controls_section();
914 }
915
916 /**
917 * Pro notice section.
918 *
919 * @return void
920 */
921 public function register_pro_notice_controls(): void
922 {
923 if (!king_addons_can_use_pro()) {
924 Core::renderProFeaturesSection($this, '', Controls_Manager::RAW_HTML, 'compare-table', [
925 'Unlimited products and category filters',
926 'Hide identical rows and sticky header',
927 'Extra attributes (dimensions, weight, taxonomy)',
928 'Highlight differences and advanced styling',
929 ]);
930 }
931 }
932
933 /**
934 * Collect products based on settings.
935 *
936 * @param array<string, mixed> $settings Settings.
937 *
938 * @return array<int, WC_Product>
939 */
940 protected function get_products(array $settings): array
941 {
942 $limit = isset($settings['kng_products_limit']) ? (int) $settings['kng_products_limit'] : 3;
943 $limit = min(max($limit, 2), 4);
944
945 $ids_raw = $settings['kng_product_ids'] ?? '';
946 $ids = array_filter(array_map('absint', explode(',', (string) $ids_raw)));
947 $ids = array_slice($ids, 0, $limit);
948
949 if (empty($ids)) {
950 return [];
951 }
952
953 $query = new WP_Query(
954 [
955 'post_type' => 'product',
956 'post__in' => $ids,
957 'posts_per_page' => $limit,
958 'orderby' => 'post__in',
959 'post_status' => 'publish',
960 ]
961 );
962
963 $products = [];
964
965 while ($query->have_posts()) {
966 $query->the_post();
967 $product = wc_get_product(get_the_ID());
968 if ($product) {
969 $products[] = $product;
970 }
971 }
972
973 wp_reset_postdata();
974
975 return $products;
976 }
977
978 /**
979 * Row labels map.
980 *
981 * @param array<string, mixed> $settings Settings.
982 *
983 * @return array<string, string>
984 */
985 protected function get_rows_config(array $settings): array
986 {
987 return $this->get_rows_config_base($settings);
988 }
989
990 /**
991 * Base row labels map.
992 *
993 * This method exists to allow the Pro version to extend row configuration
994 * without calling `parent::` methods.
995 *
996 * @param array<string, mixed> $settings Settings.
997 *
998 * @return array<string, string>
999 */
1000 protected function get_rows_config_base(array $settings): array
1001 {
1002 $rows = [];
1003
1004 if (($settings['kng_show_image'] ?? 'yes') === 'yes') {
1005 $rows['image'] = esc_html__('Image', 'king-addons');
1006 }
1007
1008 if (($settings['kng_show_price'] ?? 'yes') === 'yes') {
1009 $rows['price'] = esc_html__('Price', 'king-addons');
1010 }
1011
1012 if (($settings['kng_show_rating'] ?? 'yes') === 'yes') {
1013 $rows['rating'] = esc_html__('Rating', 'king-addons');
1014 }
1015
1016 if (($settings['kng_show_sku'] ?? 'yes') === 'yes') {
1017 $rows['sku'] = esc_html__('SKU', 'king-addons');
1018 }
1019
1020 if (($settings['kng_show_stock'] ?? 'yes') === 'yes') {
1021 $rows['stock'] = esc_html__('Stock', 'king-addons');
1022 }
1023
1024 if (($settings['kng_show_excerpt'] ?? 'yes') === 'yes') {
1025 $rows['excerpt'] = esc_html__('Short Description', 'king-addons');
1026 }
1027
1028 if (($settings['kng_show_add_to_cart'] ?? 'yes') === 'yes') {
1029 $rows['add_to_cart'] = esc_html__('Add to Cart', 'king-addons');
1030 }
1031
1032 return $rows;
1033 }
1034
1035 /**
1036 * Build cell content by row.
1037 *
1038 * @param string $row_id Row id.
1039 * @param WC_Product $product Product.
1040 * @param array<string, mixed> $settings Settings.
1041 *
1042 * @return string
1043 */
1044 protected function get_cell_content(string $row_id, WC_Product $product, array $settings): string
1045 {
1046 return $this->get_cell_content_base($row_id, $product, $settings);
1047 }
1048
1049 /**
1050 * Base cell content renderer.
1051 *
1052 * This method exists to allow the Pro version to extend row rendering
1053 * without calling `parent::` methods.
1054 *
1055 * @param string $row_id Row id.
1056 * @param WC_Product $product Product.
1057 * @param array<string, mixed> $settings Settings.
1058 *
1059 * @return string
1060 */
1061 protected function get_cell_content_base(string $row_id, WC_Product $product, array $settings): string
1062 {
1063 switch ($row_id) {
1064 case 'image':
1065 return $product->get_image('woocommerce_thumbnail');
1066 case 'price':
1067 return wp_kses_post($product->get_price_html());
1068 case 'rating':
1069 if (wc_review_ratings_enabled()) {
1070 return (string) wc_get_rating_html($product->get_average_rating());
1071 }
1072 return '';
1073 case 'sku':
1074 return $product->get_sku() ? esc_html($product->get_sku()) : esc_html__('N/A', 'king-addons');
1075 case 'stock':
1076 return $product->is_in_stock()
1077 ? '<span class="king-addons-compare-table__stock is-in">' . esc_html__('In stock', 'king-addons') . '</span>'
1078 : '<span class="king-addons-compare-table__stock is-out">' . esc_html__('Out of stock', 'king-addons') . '</span>';
1079 case 'excerpt':
1080 return wp_kses_post(wp_trim_words($product->get_short_description(), 20));
1081 case 'add_to_cart':
1082 return $this->render_add_to_cart_button($product);
1083 default:
1084 return '';
1085 }
1086 }
1087
1088 /**
1089 * Render a controlled Add to Cart button without Woo shortcode.
1090 *
1091 * @param WC_Product $product Product instance.
1092 *
1093 * @return string
1094 */
1095 protected function render_add_to_cart_button(WC_Product $product): string
1096 {
1097 if (!$product->is_purchasable() || !$product->is_in_stock()) {
1098 return '<span class="king-addons-compare-table__add-to-cart is-disabled">' . esc_html__('Unavailable', 'king-addons') . '</span>';
1099 }
1100
1101 $classes = [
1102 'king-addons-compare-table__add-to-cart',
1103 'button',
1104 'product_type_' . $product->get_type(),
1105 ];
1106
1107 if ($product->supports('ajax_add_to_cart')) {
1108 $classes[] = 'ajax_add_to_cart';
1109 $classes[] = 'add_to_cart_button';
1110 }
1111
1112 $attributes = [
1113 'href' => $product->add_to_cart_url(),
1114 'data-quantity' => 1,
1115 'data-product_id' => $product->get_id(),
1116 'data-product_sku' => $product->get_sku(),
1117 'rel' => 'nofollow',
1118 'class' => implode(' ', array_filter($classes)),
1119 'aria-label' => wp_strip_all_tags($product->add_to_cart_description()),
1120 ];
1121
1122 return '<a ' . wc_implode_html_attributes($attributes) . '><span class="king-addons-compare-table__add-to-cart-label">' . esc_html($product->add_to_cart_text()) . '</span></a>';
1123 }
1124
1125 /**
1126 * Wrapper data attributes.
1127 *
1128 * @param array<string, mixed> $settings Settings.
1129 *
1130 * @return string
1131 */
1132 protected function get_wrapper_attributes(array $settings): string
1133 {
1134 $attrs = [
1135 'data-hide-equal' => 'no',
1136 'data-sticky-header' => 'no',
1137 ];
1138
1139 $compiled = [];
1140 foreach ($attrs as $key => $value) {
1141 $compiled[] = esc_attr($key) . '="' . esc_attr($value) . '"';
1142 }
1143
1144 return implode(' ', $compiled);
1145 }
1146 }
1147
1148
1149
1150
1151
1152
1153
1154