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

Sticky_Add_To_Cart.php in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.83, at includes/extensions/Sticky_Add_To_Cart/Sticky_Add_To_Cart.php

316 lines 9.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Sticky Add To Cart bar.
4 *
5 * Keeps the product's price and buy button reachable once the visitor has
6 * scrolled the real add-to-cart form out of view.
7 *
8 * @package King_Addons
9 */
10
11 namespace King_Addons;
12
13 if (!defined('ABSPATH')) {
14 exit;
15 }
16
17 /**
18 * Sticky add-to-cart module (Pro).
19 */
20 final class Sticky_Add_To_Cart
21 {
22 /**
23 * Settings option key.
24 */
25 public const OPTION_KEY = 'king_addons_sticky_add_to_cart_settings';
26
27 /**
28 * Singleton instance.
29 *
30 * @var Sticky_Add_To_Cart|null
31 */
32 private static ?Sticky_Add_To_Cart $instance = null;
33
34 /**
35 * Cached settings.
36 *
37 * @var array<string, mixed>
38 */
39 private array $settings = [];
40
41 /**
42 * Singleton accessor.
43 *
44 * @return Sticky_Add_To_Cart
45 */
46 public static function instance(): Sticky_Add_To_Cart
47 {
48 if (is_null(self::$instance)) {
49 self::$instance = new self();
50 }
51
52 return self::$instance;
53 }
54
55 /**
56 * Hooks.
57 */
58 public function __construct()
59 {
60 $this->settings = $this->get_settings();
61
62 add_action('admin_menu', [$this, 'register_admin_menu'], 15);
63 add_action('admin_post_king_addons_satc_save', [$this, 'handle_save']);
64
65 add_action('wp_enqueue_scripts', [$this, 'maybe_enqueue_assets']);
66 add_action('wp_footer', [$this, 'render_bar'], 20);
67 }
68
69 /**
70 * Whether the paid tier is active.
71 *
72 * @return bool
73 */
74 private function can_use_pro(): bool
75 {
76 return function_exists('king_addons_can_use_pro') && king_addons_can_use_pro();
77 }
78
79 /**
80 * Default settings.
81 *
82 * @return array<string, mixed>
83 */
84 public function get_default_settings(): array
85 {
86 return [
87 'enabled' => false,
88 'position' => 'bottom',
89 'show_thumbnail' => 'yes',
90 'show_price' => 'yes',
91 'show_on_mobile' => 'yes',
92 'button_text' => __('Add to cart', 'king-addons'),
93 'trigger_offset' => 400,
94 'bg_color' => '#ffffff',
95 'text_color' => '#1f2933',
96 'button_bg_color' => '#1f2933',
97 'button_text_color' => '#ffffff',
98 ];
99 }
100
101 /**
102 * Settings with defaults applied.
103 *
104 * @return array<string, mixed>
105 */
106 public function get_settings(): array
107 {
108 $saved = get_option(self::OPTION_KEY, []);
109 if (!is_array($saved)) {
110 $saved = [];
111 }
112
113 return array_merge($this->get_default_settings(), $saved);
114 }
115
116 /**
117 * Whether the bar should render on this request.
118 *
119 * @return bool
120 */
121 private function should_render(): bool
122 {
123 if (empty($this->settings['enabled']) || !$this->can_use_pro()) {
124 return false;
125 }
126
127 if (!function_exists('is_product') || !is_product()) {
128 return false;
129 }
130
131 if (empty($this->settings['show_on_mobile']) && wp_is_mobile()) {
132 return false;
133 }
134
135 return true;
136 }
137
138 /**
139 * Front-end assets.
140 *
141 * @return void
142 */
143 public function maybe_enqueue_assets(): void
144 {
145 if (!$this->should_render()) {
146 return;
147 }
148
149 $dir = KING_ADDONS_PATH . 'includes/extensions/Sticky_Add_To_Cart/assets/';
150 $css_ver = file_exists($dir . 'style.css') ? (string) filemtime($dir . 'style.css') : KING_ADDONS_VERSION;
151 $js_ver = file_exists($dir . 'script.js') ? (string) filemtime($dir . 'script.js') : KING_ADDONS_VERSION;
152
153 wp_enqueue_style(
154 KING_ADDONS_ASSETS_UNIQUE_KEY . '-sticky-add-to-cart',
155 KING_ADDONS_URL . 'includes/extensions/Sticky_Add_To_Cart/assets/style.css',
156 [],
157 $css_ver
158 );
159
160 wp_enqueue_script(
161 KING_ADDONS_ASSETS_UNIQUE_KEY . '-sticky-add-to-cart',
162 KING_ADDONS_URL . 'includes/extensions/Sticky_Add_To_Cart/assets/script.js',
163 [],
164 $js_ver,
165 true
166 );
167
168 wp_localize_script(
169 KING_ADDONS_ASSETS_UNIQUE_KEY . '-sticky-add-to-cart',
170 'kingAddonsStickyAddToCart',
171 ['offset' => (int) $this->settings['trigger_offset']]
172 );
173 }
174
175 /**
176 * Render the bar markup in the footer.
177 *
178 * @return void
179 */
180 public function render_bar(): void
181 {
182 if (!$this->should_render()) {
183 return;
184 }
185
186 global $product;
187 if (!$product instanceof \WC_Product) {
188 $product = wc_get_product(get_the_ID());
189 }
190
191 if (!$product instanceof \WC_Product || !$product->is_purchasable()) {
192 return;
193 }
194
195 $style = sprintf(
196 '--ka-satc-bg:%s;--ka-satc-text:%s;--ka-satc-btn-bg:%s;--ka-satc-btn-text:%s;',
197 sanitize_hex_color((string) $this->settings['bg_color']) ?: '#ffffff',
198 sanitize_hex_color((string) $this->settings['text_color']) ?: '#1f2933',
199 sanitize_hex_color((string) $this->settings['button_bg_color']) ?: '#1f2933',
200 sanitize_hex_color((string) $this->settings['button_text_color']) ?: '#ffffff'
201 );
202
203 $position = 'top' === ($this->settings['position'] ?? 'bottom') ? 'top' : 'bottom';
204
205 // A variable product cannot be added from a single button - send the
206 // visitor back to the real form instead of guessing a variation.
207 $is_simple = $product->is_type('simple');
208 $url = $is_simple
209 ? esc_url($product->add_to_cart_url())
210 : '#ka-satc-form-anchor';
211 $classes = 'king-addons-satc__button button';
212 if ($is_simple) {
213 $classes .= ' add_to_cart_button ajax_add_to_cart';
214 }
215 ?>
216 <div class="king-addons-satc king-addons-satc--<?php echo esc_attr($position); ?>"
217 style="<?php echo esc_attr($style); ?>" hidden>
218 <div class="king-addons-satc__inner">
219 <?php if (!empty($this->settings['show_thumbnail'])) : ?>
220 <div class="king-addons-satc__thumb"><?php echo wp_kses_post($product->get_image('thumbnail')); ?></div>
221 <?php endif; ?>
222
223 <div class="king-addons-satc__meta">
224 <span class="king-addons-satc__title"><?php echo esc_html($product->get_name()); ?></span>
225 <?php if (!empty($this->settings['show_price'])) : ?>
226 <span class="king-addons-satc__price"><?php echo wp_kses_post($product->get_price_html()); ?></span>
227 <?php endif; ?>
228 </div>
229
230 <a href="<?php echo $url; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>"
231 class="<?php echo esc_attr($classes); ?>"
232 data-quantity="1"
233 data-product_id="<?php echo esc_attr((string) $product->get_id()); ?>"
234 rel="nofollow">
235 <?php echo esc_html((string) $this->settings['button_text']); ?>
236 </a>
237 </div>
238 </div>
239 <?php
240 }
241
242 /**
243 * Admin submenu.
244 *
245 * @return void
246 */
247 public function register_admin_menu(): void
248 {
249 add_submenu_page(
250 king_addons_woo_admin_parent_slug(),
251 esc_html__('Sticky Add To Cart', 'king-addons'),
252 esc_html__('Sticky Add To Cart', 'king-addons'),
253 'manage_options',
254 'king-addons-sticky-add-to-cart',
255 [$this, 'render_admin_page']
256 );
257 }
258
259 /**
260 * Save handler.
261 *
262 * @return void
263 */
264 public function handle_save(): void
265 {
266 if (!current_user_can('manage_options')) {
267 wp_die(esc_html__('You are not allowed to do this.', 'king-addons'));
268 }
269
270 check_admin_referer('king_addons_satc_save');
271
272 $raw = isset($_POST['ka_satc']) && is_array($_POST['ka_satc'])
273 ? wp_unslash($_POST['ka_satc']) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
274 : [];
275
276 $defaults = $this->get_default_settings();
277
278 update_option(self::OPTION_KEY, [
279 'enabled' => !empty($raw['enabled']),
280 'position' => in_array(($raw['position'] ?? 'bottom'), ['top', 'bottom'], true) ? $raw['position'] : 'bottom',
281 'show_thumbnail' => !empty($raw['show_thumbnail']) ? 'yes' : '',
282 'show_price' => !empty($raw['show_price']) ? 'yes' : '',
283 'show_on_mobile' => !empty($raw['show_on_mobile']) ? 'yes' : '',
284 'button_text' => sanitize_text_field((string) ($raw['button_text'] ?? $defaults['button_text'])),
285 'trigger_offset' => max(0, min(5000, (int) ($raw['trigger_offset'] ?? $defaults['trigger_offset']))),
286 'bg_color' => sanitize_hex_color((string) ($raw['bg_color'] ?? '')) ?: $defaults['bg_color'],
287 'text_color' => sanitize_hex_color((string) ($raw['text_color'] ?? '')) ?: $defaults['text_color'],
288 'button_bg_color' => sanitize_hex_color((string) ($raw['button_bg_color'] ?? '')) ?: $defaults['button_bg_color'],
289 'button_text_color' => sanitize_hex_color((string) ($raw['button_text_color'] ?? '')) ?: $defaults['button_text_color'],
290 ]);
291
292 wp_safe_redirect(add_query_arg(
293 ['page' => 'king-addons-sticky-add-to-cart', 'ka-saved' => '1'],
294 admin_url('admin.php')
295 ));
296 exit;
297 }
298
299 /**
300 * Settings screen.
301 *
302 * @return void
303 */
304 public function render_admin_page(): void
305 {
306 if (!current_user_can('manage_options')) {
307 return;
308 }
309
310 $s = $this->get_settings();
311 $is_pro = $this->can_use_pro();
312
313 require __DIR__ . '/templates/admin-page.php';
314 }
315 }
316