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

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

472 lines 13.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ajax Add to Cart 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_Typography;
13 use Elementor\Widget_Base;
14
15 if (!defined('ABSPATH')) {
16 exit;
17 }
18
19 /**
20 * Renders the Ajax Add to Cart widget.
21 */
22 class Ajax_Add_To_Cart extends Widget_Base
23 {
24 /**
25 * Detect whether the current request is running inside Elementor editor/preview.
26 *
27 * Elementor loads the page inside an iframe while editing, which is still a frontend request.
28 * Some interactive behaviors (like redirects) must be disabled there to avoid breaking editing.
29 *
30 * @return bool
31 */
32 protected function is_elementor_editor_context(): bool
33 {
34 // Fast path: common query arg used by Elementor preview iframe.
35 if (isset($_GET['elementor-preview'])) {
36 return true;
37 }
38
39 if (!defined('ELEMENTOR_VERSION') || !class_exists('\Elementor\Plugin')) {
40 return false;
41 }
42
43 // Be defensive: these properties/methods exist in Elementor but we guard to avoid fatals.
44 $plugin = \Elementor\Plugin::$instance;
45
46 if (isset($plugin->editor) && is_object($plugin->editor) && method_exists($plugin->editor, 'is_edit_mode')) {
47 if ($plugin->editor->is_edit_mode()) {
48 return true;
49 }
50 }
51
52 if (isset($plugin->preview) && is_object($plugin->preview) && method_exists($plugin->preview, 'is_preview_mode')) {
53 if ($plugin->preview->is_preview_mode()) {
54 return true;
55 }
56 }
57
58 return false;
59 }
60
61 /**
62 * Widget slug.
63 *
64 * @return string
65 */
66 public function get_name(): string
67 {
68 return 'king-addons-ajax-add-to-cart';
69 }
70
71 /**
72 * Widget title.
73 *
74 * @return string
75 */
76 public function get_title(): string
77 {
78 return esc_html__('Ajax Add to Cart', 'king-addons');
79 }
80
81 /**
82 * Widget icon.
83 *
84 * @return string
85 */
86 public function get_icon(): string
87 {
88 return 'king-addons-icon king-addons-ajax-add-to-cart';
89 }
90
91 /**
92 * Scripts.
93 *
94 * @return array<int, string>
95 */
96 public function get_script_depends(): array
97 {
98 return [
99 'jquery',
100 'wc-add-to-cart',
101 KING_ADDONS_ASSETS_UNIQUE_KEY . '-ajax-add-to-cart-script',
102 ];
103 }
104
105 /**
106 * Styles.
107 *
108 * @return array<int, string>
109 */
110 public function get_style_depends(): array
111 {
112 return [
113 KING_ADDONS_ASSETS_UNIQUE_KEY . '-ajax-add-to-cart-style',
114 ];
115 }
116
117 /**
118 * Categories.
119 *
120 * @return array<int, string>
121 */
122 public function get_categories(): array
123 {
124 return ['king-addons'];
125 }
126
127 /**
128 * Keywords.
129 *
130 * @return array<int, string>
131 */
132 public function get_keywords(): array
133 {
134 return ['woocommerce', 'cart', 'ajax', 'button', 'add'];
135 }
136
137 public function get_custom_help_url()
138 {
139 return 'mailto:bug@kingaddons.com?subject=Bug Report - King Addons&body=Please describe the issue';
140 }
141
142 /**
143 * Register controls.
144 *
145 * @return void
146 */
147 public function register_controls(): void
148 {
149 $this->register_content_controls();
150 $this->register_style_button_controls();
151 $this->register_style_notice_controls();
152 $this->register_pro_notice_controls();
153 }
154
155 /**
156 * Render widget output.
157 *
158 * @return void
159 */
160 public function render(): void
161 {
162 if (!class_exists('\WooCommerce')) {
163 return;
164 }
165
166 $settings = $this->get_settings_for_display();
167 $product_id = $this->resolve_product_id($settings);
168
169 if (!$product_id) {
170 return;
171 }
172
173 $quantity = !empty($settings['kng_quantity']) ? max(1, (int) $settings['kng_quantity']) : 1;
174 $button_text = $settings['kng_button_text'] ?? esc_html__('Add to cart', 'king-addons');
175 $success_text = $settings['kng_success_text'] ?? esc_html__('Added to cart', 'king-addons');
176
177 $wrapper_classes = ['king-addons-ajax-atc'];
178 ?>
179 <div class="<?php echo esc_attr(implode(' ', $wrapper_classes)); ?>"
180 data-product-id="<?php echo esc_attr((string) $product_id); ?>"
181 data-quantity="<?php echo esc_attr((string) $quantity); ?>"
182 data-success-text="<?php echo esc_attr($success_text); ?>">
183 <button type="button" class="king-addons-ajax-atc__button">
184 <span class="king-addons-ajax-atc__label"><?php echo esc_html($button_text); ?></span>
185 </button>
186 <a class="added_to_cart wc-forward" href="<?php echo esc_url(wc_get_cart_url()); ?>">
187 <?php echo esc_html__('View cart', 'woocommerce'); ?>
188 </a>
189 <div class="king-addons-ajax-atc__notice" role="status" aria-live="polite"></div>
190 </div>
191 <?php
192 }
193
194 /**
195 * Register content controls.
196 *
197 * @return void
198 */
199 protected function register_content_controls(): void
200 {
201 $this->start_controls_section(
202 'kng_content_section',
203 [
204 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Settings', 'king-addons'),
205 'tab' => Controls_Manager::TAB_CONTENT,
206 ]
207 );
208
209 $this->add_control(
210 'kng_use_current_product',
211 [
212 'label' => esc_html__('Use Current Product (Single)', 'king-addons'),
213 'type' => Controls_Manager::SWITCHER,
214 'return_value' => 'yes',
215 'default' => 'yes',
216 'description' => esc_html__('On product pages, automatically use the current product.', 'king-addons'),
217 ]
218 );
219
220 $this->add_control(
221 'kng_product_id',
222 [
223 'label' => esc_html__('Product ID (fallback)', 'king-addons'),
224 'type' => Controls_Manager::NUMBER,
225 'min' => 1,
226 'step' => 1,
227 'description' => esc_html__('Used when not on a single product or when current product is unavailable.', 'king-addons'),
228 'condition' => [
229 'kng_use_current_product!' => 'yes',
230 ],
231 ]
232 );
233
234 $this->add_control(
235 'kng_quantity',
236 [
237 'label' => esc_html__('Quantity', 'king-addons'),
238 'type' => Controls_Manager::NUMBER,
239 'min' => 1,
240 'max' => 20,
241 'step' => 1,
242 'default' => 1,
243 ]
244 );
245
246 $this->add_control(
247 'kng_button_text',
248 [
249 'label' => esc_html__('Button Text', 'king-addons'),
250 'type' => Controls_Manager::TEXT,
251 'default' => esc_html__('Add to cart', 'king-addons'),
252 ]
253 );
254
255 $this->add_control(
256 'kng_success_text',
257 [
258 'label' => esc_html__('Success Message', 'king-addons'),
259 'type' => Controls_Manager::TEXT,
260 'default' => esc_html__('Added to cart', 'king-addons'),
261 ]
262 );
263
264 $this->end_controls_section();
265 }
266
267 /**
268 * Button styles.
269 *
270 * @return void
271 */
272 protected function register_style_button_controls(): void
273 {
274 $this->start_controls_section(
275 'kng_style_button_section',
276 [
277 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Button', 'king-addons'),
278 'tab' => Controls_Manager::TAB_STYLE,
279 ]
280 );
281
282 $this->add_control(
283 'kng_alignment',
284 [
285 'label' => esc_html__('Alignment', 'king-addons'),
286 'type' => Controls_Manager::CHOOSE,
287 'options' => [
288 'flex-start' => [
289 'title' => esc_html__('Left', 'king-addons'),
290 'icon' => 'eicon-h-align-left',
291 ],
292 'center' => [
293 'title' => esc_html__('Center', 'king-addons'),
294 'icon' => 'eicon-h-align-center',
295 ],
296 'flex-end' => [
297 'title' => esc_html__('Right', 'king-addons'),
298 'icon' => 'eicon-h-align-right',
299 ],
300 ],
301 'default' => 'flex-start',
302 'selectors' => [
303 '{{WRAPPER}} .king-addons-ajax-atc' => 'justify-content: {{VALUE}};',
304 ],
305 ]
306 );
307
308 $this->add_group_control(
309 Group_Control_Typography::get_type(),
310 [
311 'name' => 'kng_button_typography',
312 'selector' => '{{WRAPPER}} .king-addons-ajax-atc__button',
313 ]
314 );
315
316 $this->add_control(
317 'kng_button_color',
318 [
319 'label' => esc_html__('Text Color', 'king-addons'),
320 'type' => Controls_Manager::COLOR,
321 'selectors' => [
322 '{{WRAPPER}} .king-addons-ajax-atc__button' => 'color: {{VALUE}};',
323 ],
324 ]
325 );
326
327 $this->add_control(
328 'kng_button_bg',
329 [
330 'label' => esc_html__('Background', 'king-addons'),
331 'type' => Controls_Manager::COLOR,
332 'selectors' => [
333 '{{WRAPPER}} .king-addons-ajax-atc__button' => 'background-color: {{VALUE}};',
334 ],
335 ]
336 );
337
338 $this->add_control(
339 'kng_button_color_hover',
340 [
341 'label' => esc_html__('Hover Text Color', 'king-addons'),
342 'type' => Controls_Manager::COLOR,
343 'selectors' => [
344 '{{WRAPPER}} .king-addons-ajax-atc__button:hover' => 'color: {{VALUE}};',
345 ],
346 ]
347 );
348
349 $this->add_control(
350 'kng_button_bg_hover',
351 [
352 'label' => esc_html__('Hover Background', 'king-addons'),
353 'type' => Controls_Manager::COLOR,
354 'selectors' => [
355 '{{WRAPPER}} .king-addons-ajax-atc__button:hover' => 'background-color: {{VALUE}};',
356 ],
357 ]
358 );
359
360 $this->add_group_control(
361 Group_Control_Border::get_type(),
362 [
363 'name' => 'kng_button_border',
364 'selector' => '{{WRAPPER}} .king-addons-ajax-atc__button',
365 ]
366 );
367
368 $this->add_control(
369 'kng_button_radius',
370 [
371 'label' => esc_html__('Border Radius', 'king-addons'),
372 'type' => Controls_Manager::SLIDER,
373 'size_units' => ['px', '%'],
374 'range' => [
375 'px' => ['min' => 0, 'max' => 50],
376 '%' => ['min' => 0, 'max' => 100],
377 ],
378 'selectors' => [
379 '{{WRAPPER}} .king-addons-ajax-atc__button' => 'border-radius: {{SIZE}}{{UNIT}};',
380 ],
381 ]
382 );
383
384 $this->end_controls_section();
385 }
386
387 /**
388 * Notice styles.
389 *
390 * @return void
391 */
392 protected function register_style_notice_controls(): void
393 {
394 $this->start_controls_section(
395 'kng_style_notice_section',
396 [
397 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Notice', 'king-addons'),
398 'tab' => Controls_Manager::TAB_STYLE,
399 ]
400 );
401
402 $this->add_group_control(
403 Group_Control_Typography::get_type(),
404 [
405 'name' => 'kng_notice_typography',
406 'selector' => '{{WRAPPER}} .king-addons-ajax-atc__notice',
407 ]
408 );
409
410 $this->add_control(
411 'kng_notice_color',
412 [
413 'label' => esc_html__('Text Color', 'king-addons'),
414 'type' => Controls_Manager::COLOR,
415 'selectors' => [
416 '{{WRAPPER}} .king-addons-ajax-atc__notice' => 'color: {{VALUE}};',
417 ],
418 ]
419 );
420
421 $this->end_controls_section();
422 }
423
424 /**
425 * Resolve product ID based on settings.
426 *
427 * @param array<string, mixed> $settings Settings.
428 *
429 * @return int
430 */
431 protected function resolve_product_id(array $settings): int
432 {
433 $use_current = ($settings['kng_use_current_product'] ?? 'yes') === 'yes';
434 if ($use_current && is_singular('product')) {
435 $product_id = get_the_ID();
436 if ($product_id) {
437 return (int) $product_id;
438 }
439 }
440
441 if (!empty($settings['kng_product_id'])) {
442 return (int) $settings['kng_product_id'];
443 }
444
445 return 0;
446 }
447
448 /**
449 * Pro notice.
450 *
451 * @return void
452 */
453 public function register_pro_notice_controls(): void
454 {
455 if (!king_addons_freemius()->can_use_premium_code__premium_only()) {
456 Core::renderProFeaturesSection($this, '', Controls_Manager::RAW_HTML, 'ajax-add-to-cart', [
457 'Icons and badges on the button',
458 'Mini-cart fragment refresh toggle',
459 'Success/redirect behaviors and messages',
460 'Quantity selector and variable products',
461 ]);
462 }
463 }
464 }
465
466
467
468
469
470
471
472