PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.87
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.87
51.1.87 51.1.86 51.1.84 51.1.85 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 All 41 releases
← All changes | includes/widgets/Woo_Cart_Table/Woo_Cart_Table.php +81 -21 51.1.65 → 51.1.87 View file →
@@ -47,9 +47,9 @@
47 47 * @return string
48 48 */
49 49 public function get_icon(): string
50 50 {
51 - return 'eicon-cart';
51 + return 'king-addons-icon king-addons-woo-cart-table';
52 52 }
53 53
54 54 /**
55 55 * Categories.
@@ -111,9 +111,10 @@
111 111 'heading_empty',
112 112 [
113 113 'label' => esc_html__('Empty title', 'king-addons'),
114 114 'type' => Controls_Manager::TEXT,
115 - 'default' => esc_html__('Your cart is empty', 'king-addons'),
115 + 'dynamic' => ['active' => true],
116 + 'default' => __('Your cart is empty', 'king-addons'),
116 117 ]
117 118 );
118 119
119 120 $this->add_control(
@@ -120,9 +121,10 @@
120 121 'message_empty',
121 122 [
122 123 'label' => esc_html__('Empty message', 'king-addons'),
123 124 'type' => Controls_Manager::TEXTAREA,
124 - 'default' => esc_html__('Looks like you have not added anything to your cart yet.', 'king-addons'),
125 + 'dynamic' => ['active' => true],
126 + 'default' => __('Looks like you have not added anything to your cart yet.', 'king-addons'),
125 127 ]
126 128 );
127 129
128 130 $this->add_control(
@@ -129,9 +131,10 @@
129 131 'primary_btn_text',
130 132 [
131 133 'label' => esc_html__('Primary button text', 'king-addons'),
132 134 'type' => Controls_Manager::TEXT,
133 - 'default' => esc_html__('Return to shop', 'king-addons'),
135 + 'dynamic' => ['active' => true],
136 + 'default' => __('Return to shop', 'king-addons'),
134 137 ]
135 138 );
136 139
137 140 $this->add_control(
@@ -138,8 +141,9 @@
138 141 'primary_btn_url',
139 142 [
140 143 'label' => esc_html__('Primary button URL', 'king-addons'),
141 144 'type' => Controls_Manager::URL,
145 + 'dynamic' => ['active' => true],
142 146 'placeholder' => 'https://',
143 147 ]
144 148 );
145 149
@@ -147,9 +151,10 @@
147 151 'secondary_btn_text',
148 152 [
149 153 'label' => sprintf(__('Secondary button text %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
150 154 'type' => Controls_Manager::TEXT,
151 - 'default' => esc_html__('View offers', 'king-addons'),
155 + 'dynamic' => ['active' => true],
156 + 'default' => __('View offers', 'king-addons'),
152 157 ]
153 158 );
154 159
155 160 $this->add_control(
@@ -156,8 +161,9 @@
156 161 'secondary_btn_url',
157 162 [
158 163 'label' => sprintf(__('Secondary button URL %s', 'king-addons'), '<i class="eicon-pro-icon"></i>'),
159 164 'type' => Controls_Manager::URL,
165 + 'dynamic' => ['active' => true],
160 166 'placeholder' => 'https://',
161 167 ]
162 168 );
163 169
@@ -247,9 +253,21 @@
247 253 }
248 254
249 255 $ajax_nonce = wp_create_nonce('ka_cart');
250 256
251 - echo '<div class="ka-cart-table" data-ka-cart="1" data-ajax-url="' . esc_url(admin_url('admin-ajax.php')) . '" data-nonce="' . esc_attr($ajax_nonce) . '">';
257 + // The empty-cart block after an AJAX removal used to be a hardcoded
258 + // minimal version, so emptying the cart in place looked nothing like
259 + // loading an empty cart. Hand the configured copy to the script.
260 + $shop_id = wc_get_page_id('shop');
261 + $shop_url = $shop_id > 0 ? get_permalink($shop_id) : home_url('/');
262 + $empty_attrs = ' data-empty-title="' . esc_attr((string) ($settings['heading_empty'] ?? '')) . '"'
263 + . ' data-empty-message="' . esc_attr((string) ($settings['message_empty'] ?? '')) . '"'
264 + . ' data-empty-primary-text="' . esc_attr((string) ($settings['primary_btn_text'] ?? '')) . '"'
265 + . ' data-empty-primary-url="' . esc_url(!empty($settings['primary_btn_url']['url']) ? $settings['primary_btn_url']['url'] : $shop_url) . '"'
266 + . ' data-empty-secondary-text="' . esc_attr($can_pro ? (string) ($settings['secondary_btn_text'] ?? '') : '') . '"'
267 + . ' data-empty-secondary-url="' . esc_url(($can_pro && !empty($settings['secondary_btn_url']['url'])) ? $settings['secondary_btn_url']['url'] : '') . '"';
268 +
269 + echo '<div class="ka-cart-table" data-ka-cart="1" data-ajax-url="' . esc_url(admin_url('admin-ajax.php')) . '" data-nonce="' . esc_attr($ajax_nonce) . '"' . $empty_attrs . '>';
252 270 woocommerce_output_all_notices();
253 271 wc_get_template('cart/cart.php');
254 272 echo '</div>';
255 273
@@ -280,11 +298,11 @@
280 298 $shop_id = wc_get_page_id('shop');
281 299 $shop_url = $shop_id > 0 ? get_permalink($shop_id) : home_url('/');
282 300 $can_pro = king_addons_can_use_pro();
283 301
284 - $heading = $settings['heading_empty'] ?? esc_html__('Your cart is empty', 'king-addons');
285 - $message = $settings['message_empty'] ?? esc_html__('Looks like you have not added anything to your cart yet.', 'king-addons');
286 - $primary_text = $settings['primary_btn_text'] ?? esc_html__('Return to shop', 'king-addons');
302 + $heading = $settings['heading_empty'] ?? __('Your cart is empty', 'king-addons');
303 + $message = $settings['message_empty'] ?? __('Looks like you have not added anything to your cart yet.', 'king-addons');
304 + $primary_text = $settings['primary_btn_text'] ?? __('Return to shop', 'king-addons');
287 305 $primary_url = !empty($settings['primary_btn_url']['url']) ? $settings['primary_btn_url']['url'] : $shop_url;
288 306 $secondary_text = (!empty($settings['secondary_btn_text']) && $can_pro) ? $settings['secondary_btn_text'] : '';
289 307 $secondary_url = (!empty($settings['secondary_btn_url']['url']) && $can_pro) ? $settings['secondary_btn_url']['url'] : '';
290 308
@@ -384,12 +402,15 @@
384 402 private static function build_fragments(): array
385 403 {
386 404 $empty = WC()->cart->is_empty();
387 405
406 + // Capture notices before cart HTML. Previously render_cart_html() printed
407 + // them first via woocommerce_output_all_notices(), so ajax fragments
408 + // returned an empty notices string and the coupon widget stayed silent.
409 + $notices = function_exists('wc_print_notices') ? wc_print_notices(true) : '';
388 410 $cart_html = $empty ? self::render_empty_cart_html() : self::render_cart_html();
389 411 $totals_html = self::render_totals_html($empty);
390 412 $cross_html = self::render_cross_sells_html($empty);
391 - $notices = function_exists('wc_print_notices') ? wc_print_notices(true) : '';
392 413
393 414 return [
394 415 'cart_html' => $cart_html,
395 416 'totals_html' => $totals_html,
@@ -408,11 +429,25 @@
408 429 */
409 430 private static function render_cart_html(): string
410 431 {
411 432 ob_start();
412 - woocommerce_output_all_notices();
433 + $had_totals = has_action('woocommerce_cart_collaterals', 'woocommerce_cart_totals');
434 + $had_cross = has_action('woocommerce_cart_collaterals', 'woocommerce_cross_sell_display');
435 + if ($had_totals) {
436 + remove_action('woocommerce_cart_collaterals', 'woocommerce_cart_totals', 10);
437 + }
438 + if ($had_cross) {
439 + remove_action('woocommerce_cart_collaterals', 'woocommerce_cross_sell_display', 10);
440 + }
413 441 wc_get_template('cart/cart.php');
414 - return (string) ob_get_clean();
442 + if ($had_totals) {
443 + add_action('woocommerce_cart_collaterals', 'woocommerce_cart_totals', 10);
444 + }
445 + if ($had_cross) {
446 + add_action('woocommerce_cart_collaterals', 'woocommerce_cross_sell_display', 10);
447 + }
448 + $html = (string) ob_get_clean();
449 + return (string) preg_replace('#<div class="cart-collaterals">\s*</div>#', '', $html);
415 450 }
416 451
417 452 /**
418 453 * Render totals HTML.
@@ -457,24 +492,49 @@
457 492 {
458 493 $shop_id = wc_get_page_id('shop');
459 494 $shop_url = $shop_id > 0 ? get_permalink($shop_id) : home_url('/');
460 495
496 + // The copy comes from the widget, passed along by the script, so the
497 + // markup matches what a full page load of an empty cart produces.
498 + // phpcs:disable WordPress.Security.NonceVerification.Missing -- verified by the caller.
499 + $heading = isset($_POST['empty_title']) ? sanitize_text_field(wp_unslash($_POST['empty_title'])) : __('Your cart is empty', 'king-addons');
500 + $message = isset($_POST['empty_message']) ? sanitize_text_field(wp_unslash($_POST['empty_message'])) : '';
501 + $primary_text = isset($_POST['empty_primary_text']) ? sanitize_text_field(wp_unslash($_POST['empty_primary_text'])) : __('Return to shop', 'king-addons');
502 + $primary_url = isset($_POST['empty_primary_url']) ? esc_url_raw(wp_unslash($_POST['empty_primary_url'])) : '';
503 + $secondary_text = isset($_POST['empty_secondary_text']) ? sanitize_text_field(wp_unslash($_POST['empty_secondary_text'])) : '';
504 + $secondary_url = isset($_POST['empty_secondary_url']) ? esc_url_raw(wp_unslash($_POST['empty_secondary_url'])) : '';
505 + // phpcs:enable WordPress.Security.NonceVerification.Missing
506 +
507 + if ('' === $primary_url) {
508 + $primary_url = $shop_url;
509 + }
510 +
461 511 ob_start();
462 512 echo '<div class="ka-cart-empty">';
463 - echo '<p class="ka-cart-empty__text">' . esc_html__('Your cart is empty.', 'king-addons') . '</p>';
464 - echo '<a class="ka-cart-empty__link" href="' . esc_url($shop_url) . '">' . esc_html__('Return to shop', 'king-addons') . '</a>';
513 + echo '<div class="ka-cart-empty__icon" aria-hidden="true">🛒</div>';
514 + if ($heading) {
515 + echo '<h3 class="ka-cart-empty__title">' . esc_html($heading) . '</h3>';
516 + }
517 + if ($message) {
518 + echo '<p class="ka-cart-empty__text">' . esc_html($message) . '</p>';
519 + }
520 + echo '<div class="ka-cart-empty__actions">';
521 + if ($primary_text && $primary_url) {
522 + echo '<a class="ka-cart-empty__btn ka-cart-empty__btn--primary" href="' . esc_url($primary_url) . '">' . esc_html($primary_text) . '</a>';
523 + }
524 + if ($secondary_text && $secondary_url) {
525 + echo '<a class="ka-cart-empty__btn ka-cart-empty__btn--ghost" href="' . esc_url($secondary_url) . '">' . esc_html($secondary_text) . '</a>';
526 + }
465 527 echo '</div>';
528 + do_action('king_addons/cart/empty_after');
529 + echo '</div>';
466 530 return (string) ob_get_clean();
467 531 }
468 532 }
469 533
470 -// Register AJAX handlers only if WooCommerce is active
471 -if (class_exists('WooCommerce')) {
472 - add_action('wp_ajax_ka_cart_update', [Woo_Cart_Table::class, 'ajax_update']);
473 - add_action('wp_ajax_nopriv_ka_cart_update', [Woo_Cart_Table::class, 'ajax_update']);
474 - add_action('wp_ajax_ka_cart_coupon', [Woo_Cart_Table::class, 'ajax_coupon']);
475 - add_action('wp_ajax_nopriv_ka_cart_coupon', [Woo_Cart_Table::class, 'ajax_coupon']);
476 -}
534 +// Registration lives in Woo_Builder: admin-ajax.php never loads Elementor
535 +// widget files, so hooking from here meant the quantity, remove and coupon
536 +// requests all came back as "0".
477 537
478 538
479 539
480 540