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 / 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.49, at includes/widgets/Compare_Table/Compare_Table.php

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